| // Copyright 2014 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "src/runtime/runtime-utils.h" |
| |
| #include "src/arguments.h" |
| #include "src/bootstrapper.h" |
| #include "src/debug/debug.h" |
| #include "src/isolate-inl.h" |
| #include "src/messages.h" |
| #include "src/objects/property-descriptor-object.h" |
| #include "src/property-descriptor.h" |
| #include "src/runtime/runtime.h" |
| |
| namespace v8 { |
| namespace internal { |
| |
| MaybeHandle<Object> Runtime::GetObjectProperty(Isolate* isolate, |
| Handle<Object> object, |
| Handle<Object> key, |
| bool* is_found_out) { |
| if (object->IsNullOrUndefined(isolate)) { |
| THROW_NEW_ERROR( |
| isolate, |
| NewTypeError(MessageTemplate::kNonObjectPropertyLoad, key, object), |
| Object); |
| } |
| |
| bool success = false; |
| LookupIterator it = |
| LookupIterator::PropertyOrElement(isolate, object, key, &success); |
| if (!success) return MaybeHandle<Object>(); |
| |
| MaybeHandle<Object> result = Object::GetProperty(&it); |
| if (is_found_out) *is_found_out = it.IsFound(); |
| return result; |
| } |
| |
| static MaybeHandle<Object> KeyedGetObjectProperty(Isolate* isolate, |
| Handle<Object> receiver_obj, |
| Handle<Object> key_obj) { |
| // Fast cases for getting named properties of the receiver JSObject |
| // itself. |
| // |
| // The global proxy objects has to be excluded since LookupOwn on |
| // the global proxy object can return a valid result even though the |
| // global proxy object never has properties. This is the case |
| // because the global proxy object forwards everything to its hidden |
| // prototype including own lookups. |
| // |
| // Additionally, we need to make sure that we do not cache results |
| // for objects that require access checks. |
| |
| // Convert string-index keys to their number variant to avoid internalization |
| // below; and speed up subsequent conversion to index. |
| uint32_t index; |
| if (key_obj->IsString() && String::cast(*key_obj)->AsArrayIndex(&index)) { |
| key_obj = isolate->factory()->NewNumberFromUint(index); |
| } |
| if (receiver_obj->IsJSObject()) { |
| if (!receiver_obj->IsJSGlobalProxy() && |
| !receiver_obj->IsAccessCheckNeeded() && key_obj->IsName()) { |
| Handle<JSObject> receiver = Handle<JSObject>::cast(receiver_obj); |
| Handle<Name> key = Handle<Name>::cast(key_obj); |
| key_obj = key = isolate->factory()->InternalizeName(key); |
| |
| DisallowHeapAllocation no_allocation; |
| if (receiver->IsJSGlobalObject()) { |
| // Attempt dictionary lookup. |
| GlobalDictionary* dictionary = |
| JSGlobalObject::cast(*receiver)->global_dictionary(); |
| int entry = dictionary->FindEntry(key); |
| if (entry != GlobalDictionary::kNotFound) { |
| PropertyCell* cell = dictionary->CellAt(entry); |
| if (cell->property_details().kind() == kData) { |
| Object* value = cell->value(); |
| if (!value->IsTheHole(isolate)) { |
| return Handle<Object>(value, isolate); |
| } |
| // If value is the hole (meaning, absent) do the general lookup. |
| } |
| } |
| } else if (!receiver->HasFastProperties()) { |
| // Attempt dictionary lookup. |
| NameDictionary* dictionary = receiver->property_dictionary(); |
| int entry = dictionary->FindEntry(key); |
| if ((entry != NameDictionary::kNotFound) && |
| (dictionary->DetailsAt(entry).kind() == kData)) { |
| Object* value = dictionary->ValueAt(entry); |
| return Handle<Object>(value, isolate); |
| } |
| } |
| } else if (key_obj->IsSmi()) { |
| // JSObject without a name key. If the key is a Smi, check for a |
| // definite out-of-bounds access to elements, which is a strong indicator |
| // that subsequent accesses will also call the runtime. Proactively |
| // transition elements to FAST_*_ELEMENTS to avoid excessive boxing of |
| // doubles for those future calls in the case that the elements would |
| // become PACKED_DOUBLE_ELEMENTS. |
| Handle<JSObject> js_object = Handle<JSObject>::cast(receiver_obj); |
| ElementsKind elements_kind = js_object->GetElementsKind(); |
| if (IsDoubleElementsKind(elements_kind)) { |
| if (Smi::ToInt(*key_obj) >= js_object->elements()->length()) { |
| elements_kind = IsHoleyElementsKind(elements_kind) ? HOLEY_ELEMENTS |
| : PACKED_ELEMENTS; |
| JSObject::TransitionElementsKind(js_object, elements_kind); |
| } |
| } else { |
| DCHECK(IsSmiOrObjectElementsKind(elements_kind) || |
| !IsFastElementsKind(elements_kind)); |
| } |
| } |
| } else if (receiver_obj->IsString() && key_obj->IsSmi()) { |
| // Fast case for string indexing using [] with a smi index. |
| Handle<String> str = Handle<String>::cast(receiver_obj); |
| int index = Handle<Smi>::cast(key_obj)->value(); |
| if (index >= 0 && index < str->length()) { |
| Factory* factory = isolate->factory(); |
| return factory->LookupSingleCharacterStringFromCode( |
| String::Flatten(str)->Get(index)); |
| } |
| } |
| |
| // Fall back to GetObjectProperty. |
| return Runtime::GetObjectProperty(isolate, receiver_obj, key_obj); |
| } |
| |
| namespace { |
| |
| bool DeleteObjectPropertyFast(Isolate* isolate, Handle<JSReceiver> receiver, |
| Handle<Object> raw_key) { |
| DisallowHeapAllocation no_allocation; |
| // This implements a special case for fast property deletion: when the |
| // last property in an object is deleted, then instead of normalizing |
| // the properties, we can undo the last map transition, with a few |
| // prerequisites: |
| // (1) The receiver must be a regular object and the key a unique name. |
| Map* map = receiver->map(); |
| if (map->IsSpecialReceiverMap()) return false; |
| if (!raw_key->IsUniqueName()) return false; |
| Handle<Name> key = Handle<Name>::cast(raw_key); |
| // (2) The property to be deleted must be the last property. |
| int nof = map->NumberOfOwnDescriptors(); |
| if (nof == 0) return false; |
| int descriptor = nof - 1; |
| DescriptorArray* descriptors = map->instance_descriptors(); |
| if (descriptors->GetKey(descriptor) != *key) return false; |
| // (3) The property to be deleted must be deletable. |
| PropertyDetails details = descriptors->GetDetails(descriptor); |
| if (!details.IsConfigurable()) return false; |
| // (4) The map must have a back pointer. |
| Object* backpointer = map->GetBackPointer(); |
| if (!backpointer->IsMap()) return false; |
| // (5) The last transition must have been caused by adding a property |
| // (and not any kind of special transition). |
| if (Map::cast(backpointer)->NumberOfOwnDescriptors() != nof - 1) return false; |
| |
| // Preconditions successful. No more bailouts after this point. |
| |
| // Zap the property to avoid keeping objects alive. Zapping is not necessary |
| // for properties stored in the descriptor array. |
| if (details.location() == kField) { |
| isolate->heap()->NotifyObjectLayoutChange(*receiver, map->instance_size(), |
| no_allocation); |
| FieldIndex index = FieldIndex::ForPropertyIndex(map, details.field_index()); |
| // Special case deleting the last out-of object property. |
| if (!index.is_inobject() && index.outobject_array_index() == 0) { |
| DCHECK(!Map::cast(backpointer)->HasOutOfObjectProperties()); |
| // Clear out the properties backing store. |
| receiver->SetProperties(isolate->heap()->empty_fixed_array()); |
| } else { |
| Object* filler = isolate->heap()->one_pointer_filler_map(); |
| JSObject::cast(*receiver)->RawFastPropertyAtPut(index, filler); |
| // We must clear any recorded slot for the deleted property, because |
| // subsequent object modifications might put a raw double there. |
| // Slot clearing is the reason why this entire function cannot currently |
| // be implemented in the DeleteProperty stub. |
| if (index.is_inobject() && !map->IsUnboxedDoubleField(index)) { |
| isolate->heap()->ClearRecordedSlot( |
| *receiver, HeapObject::RawField(*receiver, index.offset())); |
| } |
| } |
| } |
| // If the map was marked stable before, then there could be optimized code |
| // that depends on the assumption that no object that reached this map |
| // transitions away from it without triggering the "deoptimize dependent |
| // code" mechanism. |
| map->NotifyLeafMapLayoutChange(); |
| // Finally, perform the map rollback. |
| receiver->synchronized_set_map(Map::cast(backpointer)); |
| #if VERIFY_HEAP |
| receiver->HeapObjectVerify(); |
| receiver->property_array()->PropertyArrayVerify(); |
| #endif |
| return true; |
| } |
| |
| } // namespace |
| |
| Maybe<bool> Runtime::DeleteObjectProperty(Isolate* isolate, |
| Handle<JSReceiver> receiver, |
| Handle<Object> key, |
| LanguageMode language_mode) { |
| if (DeleteObjectPropertyFast(isolate, receiver, key)) return Just(true); |
| |
| bool success = false; |
| LookupIterator it = LookupIterator::PropertyOrElement( |
| isolate, receiver, key, &success, LookupIterator::OWN); |
| if (!success) return Nothing<bool>(); |
| |
| return JSReceiver::DeleteProperty(&it, language_mode); |
| } |
| |
| // ES #sec-object.keys |
| RUNTIME_FUNCTION(Runtime_ObjectKeys) { |
| HandleScope scope(isolate); |
| Handle<Object> object = args.at(0); |
| |
| // Convert the {object} to a proper {receiver}. |
| Handle<JSReceiver> receiver; |
| ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver, |
| Object::ToObject(isolate, object)); |
| |
| // Collect the own keys for the {receiver}. |
| Handle<FixedArray> keys; |
| ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| isolate, keys, |
| KeyAccumulator::GetKeys(receiver, KeyCollectionMode::kOwnOnly, |
| ENUMERABLE_STRINGS, |
| GetKeysConversion::kConvertToString)); |
| return *keys; |
| } |
| |
| // ES6 19.1.3.2 |
| RUNTIME_FUNCTION(Runtime_ObjectHasOwnProperty) { |
| HandleScope scope(isolate); |
| Handle<Object> property = args.at(1); |
| |
| Handle<Name> key; |
| uint32_t index; |
| bool key_is_array_index = property->ToArrayIndex(&index); |
| |
| if (!key_is_array_index) { |
| ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, key, |
| Object::ToName(isolate, property)); |
| key_is_array_index = key->AsArrayIndex(&index); |
| } |
| |
| Handle<Object> object = args.at(0); |
| |
| if (object->IsJSModuleNamespace()) { |
| if (key.is_null()) { |
| DCHECK(key_is_array_index); |
| // Namespace objects can't have indexed properties. |
| return isolate->heap()->false_value(); |
| } |
| |
| Maybe<bool> result = |
| JSReceiver::HasOwnProperty(Handle<JSReceiver>::cast(object), key); |
| if (!result.IsJust()) return isolate->heap()->exception(); |
| return isolate->heap()->ToBoolean(result.FromJust()); |
| |
| } else if (object->IsJSObject()) { |
| Handle<JSObject> js_obj = Handle<JSObject>::cast(object); |
| // Fast case: either the key is a real named property or it is not |
| // an array index and there are no interceptors or hidden |
| // prototypes. |
| // TODO(jkummerow): Make JSReceiver::HasOwnProperty fast enough to |
| // handle all cases directly (without this custom fast path). |
| { |
| LookupIterator::Configuration c = LookupIterator::OWN_SKIP_INTERCEPTOR; |
| LookupIterator it = |
| key_is_array_index ? LookupIterator(isolate, js_obj, index, js_obj, c) |
| : LookupIterator(js_obj, key, js_obj, c); |
| Maybe<bool> maybe = JSReceiver::HasProperty(&it); |
| if (maybe.IsNothing()) return isolate->heap()->exception(); |
| DCHECK(!isolate->has_pending_exception()); |
| if (maybe.FromJust()) return isolate->heap()->true_value(); |
| } |
| |
| Map* map = js_obj->map(); |
| if (!map->has_hidden_prototype() && |
| (key_is_array_index ? !map->has_indexed_interceptor() |
| : !map->has_named_interceptor())) { |
| return isolate->heap()->false_value(); |
| } |
| |
| // Slow case. |
| LookupIterator::Configuration c = LookupIterator::OWN; |
| LookupIterator it = key_is_array_index |
| ? LookupIterator(isolate, js_obj, index, js_obj, c) |
| : LookupIterator(js_obj, key, js_obj, c); |
| |
| Maybe<bool> maybe = JSReceiver::HasProperty(&it); |
| if (maybe.IsNothing()) return isolate->heap()->exception(); |
| DCHECK(!isolate->has_pending_exception()); |
| return isolate->heap()->ToBoolean(maybe.FromJust()); |
| |
| } else if (object->IsJSProxy()) { |
| if (key.is_null()) { |
| DCHECK(key_is_array_index); |
| key = isolate->factory()->Uint32ToString(index); |
| } |
| |
| Maybe<bool> result = |
| JSReceiver::HasOwnProperty(Handle<JSProxy>::cast(object), key); |
| if (result.IsNothing()) return isolate->heap()->exception(); |
| return isolate->heap()->ToBoolean(result.FromJust()); |
| |
| } else if (object->IsString()) { |
| return isolate->heap()->ToBoolean( |
| key_is_array_index |
| ? index < static_cast<uint32_t>(String::cast(*object)->length()) |
| : key->Equals(isolate->heap()->length_string())); |
| } else if (object->IsNullOrUndefined(isolate)) { |
| THROW_NEW_ERROR_RETURN_FAILURE( |
| isolate, NewTypeError(MessageTemplate::kUndefinedOrNullToObject)); |
| } |
| |
| return isolate->heap()->false_value(); |
| } |
| |
| RUNTIME_FUNCTION(Runtime_AddDictionaryProperty) { |
| HandleScope scope(isolate); |
| Handle<JSObject> receiver = args.at<JSObject>(0); |
| Handle<Name> name = args.at<Name>(1); |
| Handle<Object> value = args.at(2); |
| |
| DCHECK(name->IsUniqueName()); |
| |
| Handle<NameDictionary> dictionary(receiver->property_dictionary(), isolate); |
| PropertyDetails property_details(kData, NONE, PropertyCellType::kNoCell); |
| dictionary = NameDictionary::Add(dictionary, name, value, property_details); |
| receiver->SetProperties(*dictionary); |
| return *value; |
| } |
| |
| // ES6 section 19.1.2.2 Object.create ( O [ , Properties ] ) |
| // TODO(verwaest): Support the common cases with precached map directly in |
| // an Object.create stub. |
| RUNTIME_FUNCTION(Runtime_ObjectCreate) { |
| HandleScope scope(isolate); |
| Handle<Object> prototype = args.at(0); |
| if (!prototype->IsNull(isolate) && !prototype->IsJSReceiver()) { |
| THROW_NEW_ERROR_RETURN_FAILURE( |
| isolate, NewTypeError(MessageTemplate::kProtoObjectOrNull, prototype)); |
| } |
| |
| // Generate the map with the specified {prototype} based on the Object |
| // function's initial map from the current native context. |
| // TODO(bmeurer): Use a dedicated cache for Object.create; think about |
| // slack tracking for Object.create. |
| Handle<Map> map = |
| Map::GetObjectCreateMap(Handle<HeapObject>::cast(prototype)); |
| |
| // Actually allocate the object. |
| Handle<JSObject> object; |
| if (map->is_dictionary_map()) { |
| object = isolate->factory()->NewSlowJSObjectFromMap(map); |
| } else { |
| object = isolate->factory()->NewJSObjectFromMap(map); |
| } |
| |
| // Define the properties if properties was specified and is not undefined. |
| Handle<Object> properties = args.at(1); |
| if (!properties->IsUndefined(isolate)) { |
| RETURN_FAILURE_ON_EXCEPTION( |
| isolate, JSReceiver::DefineProperties(isolate, object, properties)); |
| } |
| |
| return *object; |
| } |
| |
| MaybeHandle<Object> Runtime::SetObjectProperty(Isolate* isolate, |
| Handle<Object> object, |
| Handle<Object> key, |
| Handle<Object> value, |
| LanguageMode language_mode) { |
| if (object->IsNullOrUndefined(isolate)) { |
| THROW_NEW_ERROR( |
| isolate, |
| NewTypeError(MessageTemplate::kNonObjectPropertyStore, key, object), |
| Object); |
| } |
| |
| // Check if the given key is an array index. |
| bool success = false; |
| LookupIterator it = |
| LookupIterator::PropertyOrElement(isolate, object, key, &success); |
| if (!success) return MaybeHandle<Object>(); |
| |
| MAYBE_RETURN_NULL(Object::SetProperty(&it, value, language_mode, |
| Object::MAY_BE_STORE_FROM_KEYED)); |
| return value; |
| } |
| |
| |
| RUNTIME_FUNCTION(Runtime_GetPrototype) { |
| HandleScope scope(isolate); |
| DCHECK_EQ(1, args.length()); |
| CONVERT_ARG_HANDLE_CHECKED(JSReceiver, obj, 0); |
| RETURN_RESULT_OR_FAILURE(isolate, JSReceiver::GetPrototype(isolate, obj)); |
| } |
| |
| |
| RUNTIME_FUNCTION(Runtime_InternalSetPrototype) { |
| HandleScope scope(isolate); |
| DCHECK_EQ(2, args.length()); |
| CONVERT_ARG_HANDLE_CHECKED(JSReceiver, obj, 0); |
| CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1); |
| if (prototype->IsJSFunction()) { |
| Handle<JSFunction> function = Handle<JSFunction>::cast(prototype); |
| if (!function->shared()->has_shared_name()) { |
| Handle<Map> function_map(function->map(), isolate); |
| if (!JSFunction::SetName(function, isolate->factory()->proto_string(), |
| isolate->factory()->empty_string())) { |
| return isolate->heap()->exception(); |
| } |
| CHECK_EQ(*function_map, function->map()); |
| } |
| } |
| MAYBE_RETURN(JSReceiver::SetPrototype(obj, prototype, false, kThrowOnError), |
| isolate->heap()->exception()); |
| return *obj; |
| } |
| |
| RUNTIME_FUNCTION(Runtime_OptimizeObjectForAddingMultipleProperties) { |
| HandleScope scope(isolate); |
| DCHECK_EQ(2, args.length()); |
| CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); |
| CONVERT_SMI_ARG_CHECKED(properties, 1); |
| // Conservative upper limit to prevent fuzz tests from going OOM. |
| if (properties > 100000) return isolate->ThrowIllegalOperation(); |
| if (object->HasFastProperties() && !object->IsJSGlobalProxy()) { |
| JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties, |
| "OptimizeForAdding"); |
| } |
| return *object; |
| } |
| |
| RUNTIME_FUNCTION(Runtime_ObjectValues) { |
| HandleScope scope(isolate); |
| DCHECK_EQ(1, args.length()); |
| |
| CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0); |
| |
| Handle<FixedArray> values; |
| ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| isolate, values, |
| JSReceiver::GetOwnValues(receiver, PropertyFilter::ENUMERABLE_STRINGS, |
| true)); |
| return *isolate->factory()->NewJSArrayWithElements(values); |
| } |
| |
| RUNTIME_FUNCTION(Runtime_ObjectValuesSkipFastPath) { |
| HandleScope scope(isolate); |
| DCHECK_EQ(1, args.length()); |
| |
| CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0); |
| |
| Handle<FixedArray> value; |
| ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| isolate, value, |
| JSReceiver::GetOwnValues(receiver, PropertyFilter::ENUMERABLE_STRINGS, |
| false)); |
| return *isolate->factory()->NewJSArrayWithElements(value); |
| } |
| |
| RUNTIME_FUNCTION(Runtime_ObjectEntries) { |
| HandleScope scope(isolate); |
| DCHECK_EQ(1, args.length()); |
| |
| CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0); |
| |
| Handle<FixedArray> entries; |
| ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| isolate, entries, |
| JSReceiver::GetOwnEntries(receiver, PropertyFilter::ENUMERABLE_STRINGS, |
| true)); |
| return *isolate->factory()->NewJSArrayWithElements(entries); |
| } |
| |
| RUNTIME_FUNCTION(Runtime_ObjectEntriesSkipFastPath) { |
| HandleScope scope(isolate); |
| DCHECK_EQ(1, args.length()); |
| |
| CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0); |
| |
| Handle<FixedArray> entries; |
| ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| isolate, entries, |
| JSReceiver::GetOwnEntries(receiver, PropertyFilter::ENUMERABLE_STRINGS, |
| false)); |
| return *isolate->factory()->NewJSArrayWithElements(entries); |
| } |
| |
| RUNTIME_FUNCTION(Runtime_GetProperty) { |
| HandleScope scope(isolate); |
| DCHECK_EQ(2, args.length()); |
| |
| CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); |
| CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); |
| |
| RETURN_RESULT_OR_FAILURE(isolate, |
| Runtime::GetObjectProperty(isolate, object, key)); |
| } |
| |
| // KeyedGetProperty is called from KeyedLoadIC::GenerateGeneric. |
| RUNTIME_FUNCTION(Runtime_KeyedGetProperty) { |
| HandleScope scope(isolate); |
| DCHECK_EQ(2, args.length()); |
| |
| CONVERT_ARG_HANDLE_CHECKED(Object, receiver_obj, 0); |
| CONVERT_ARG_HANDLE_CHECKED(Object, key_obj, 1); |
| |
| RETURN_RESULT_OR_FAILURE( |
| isolate, KeyedGetObjectProperty(isolate, receiver_obj, key_obj)); |
| } |
| |
| RUNTIME_FUNCTION(Runtime_AddNamedProperty) { |
| HandleScope scope(isolate); |
| DCHECK_EQ(4, args.length()); |
| |
| CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); |
| CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); |
| CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); |
| CONVERT_PROPERTY_ATTRIBUTES_CHECKED(attrs, 3); |
| |
| #ifdef DEBUG |
| uint32_t index = 0; |
| DCHECK(!name->ToArrayIndex(&index)); |
| LookupIterator it(object, name, object, LookupIterator::OWN_SKIP_INTERCEPTOR); |
| Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it); |
| if (maybe.IsNothing()) return isolate->heap()->exception(); |
| DCHECK(!it.IsFound()); |
| #endif |
| |
| RETURN_RESULT_OR_FAILURE(isolate, JSObject::SetOwnPropertyIgnoreAttributes( |
| object, name, value, attrs)); |
| } |
| |
| |
| // Adds an element to an array. |
| // This is used to create an indexed data property into an array. |
| RUNTIME_FUNCTION(Runtime_AddElement) { |
| HandleScope scope(isolate); |
| DCHECK_EQ(3, args.length()); |
| |
| CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); |
| CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); |
| CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); |
| |
| uint32_t index = 0; |
| CHECK(key->ToArrayIndex(&index)); |
| |
| #ifdef DEBUG |
| LookupIterator it(isolate, object, index, object, |
| LookupIterator::OWN_SKIP_INTERCEPTOR); |
| Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it); |
| if (maybe.IsNothing()) return isolate->heap()->exception(); |
| DCHECK(!it.IsFound()); |
| |
| if (object->IsJSArray()) { |
| Handle<JSArray> array = Handle<JSArray>::cast(object); |
| DCHECK(!JSArray::WouldChangeReadOnlyLength(array, index)); |
| } |
| #endif |
| |
| RETURN_RESULT_OR_FAILURE(isolate, JSObject::SetOwnElementIgnoreAttributes( |
| object, index, value, NONE)); |
| } |
| |
| |
| RUNTIME_FUNCTION(Runtime_AppendElement) { |
| HandleScope scope(isolate); |
| DCHECK_EQ(2, args.length()); |
| |
| CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0); |
| CONVERT_ARG_HANDLE_CHECKED(Object, value, 1); |
| CHECK(!value->IsTheHole(isolate)); |
| |
| uint32_t index; |
| CHECK(array->length()->ToArrayIndex(&index)); |
| |
| RETURN_FAILURE_ON_EXCEPTION( |
| isolate, JSObject::AddDataElement(array, index, value, NONE)); |
| JSObject::ValidateElements(*array); |
| return *array; |
| } |
| |
| |
| RUNTIME_FUNCTION(Runtime_SetProperty) { |
| HandleScope scope(isolate); |
| DCHECK_EQ(4, args.length()); |
| |
| CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); |
| CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); |
| CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); |
| CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 3); |
| |
| RETURN_RESULT_OR_FAILURE( |
| isolate, |
| Runtime::SetObjectProperty(isolate, object, key, value, language_mode)); |
| } |
| |
| |
| namespace { |
| |
| // ES6 section 12.5.4. |
| Object* DeleteProperty(Isolate* isolate, Handle<Object> object, |
| Handle<Object> key, LanguageMode language_mode) { |
| Handle<JSReceiver> receiver; |
| ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver, |
| Object::ToObject(isolate, object)); |
| Maybe<bool> result = |
| Runtime::DeleteObjectProperty(isolate, receiver, key, language_mode); |
| MAYBE_RETURN(result, isolate->heap()->exception()); |
| return isolate->heap()->ToBoolean(result.FromJust()); |
| } |
| |
| } // namespace |
| |
| RUNTIME_FUNCTION(Runtime_DeleteProperty) { |
| HandleScope scope(isolate); |
| DCHECK_EQ(3, args.length()); |
| CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); |
| CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); |
| CONVERT_SMI_ARG_CHECKED(language_mode, 2); |
| return DeleteProperty(isolate, object, key, |
| static_cast<LanguageMode>(language_mode)); |
| } |
| |
| RUNTIME_FUNCTION(Runtime_ShrinkPropertyDictionary) { |
| HandleScope scope(isolate); |
| DCHECK_EQ(1, args.length()); |
| CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0); |
| Handle<NameDictionary> dictionary(receiver->property_dictionary(), isolate); |
| Handle<NameDictionary> new_properties = NameDictionary::Shrink(dictionary); |
| receiver->SetProperties(*new_properties); |
| return Smi::kZero; |
| } |
| |
| // ES6 section 12.9.3, operator in. |
| RUNTIME_FUNCTION(Runtime_HasProperty) { |
| HandleScope scope(isolate); |
| DCHECK_EQ(2, args.length()); |
| CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); |
| CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); |
| |
| // Check that {object} is actually a receiver. |
| if (!object->IsJSReceiver()) { |
| THROW_NEW_ERROR_RETURN_FAILURE( |
| isolate, |
| NewTypeError(MessageTemplate::kInvalidInOperatorUse, key, object)); |
| } |
| Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object); |
| |
| // Convert the {key} to a name. |
| Handle<Name> name; |
| ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name, |
| Object::ToName(isolate, key)); |
| |
| // Lookup the {name} on {receiver}. |
| Maybe<bool> maybe = JSReceiver::HasProperty(receiver, name); |
| if (maybe.IsNothing()) return isolate->heap()->exception(); |
| return isolate->heap()->ToBoolean(maybe.FromJust()); |
| } |
| |
| |
| RUNTIME_FUNCTION(Runtime_GetOwnPropertyKeys) { |
| HandleScope scope(isolate); |
| DCHECK_EQ(2, args.length()); |
| CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0); |
| CONVERT_SMI_ARG_CHECKED(filter_value, 1); |
| PropertyFilter filter = static_cast<PropertyFilter>(filter_value); |
| |
| Handle<FixedArray> keys; |
| ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| isolate, keys, |
| KeyAccumulator::GetKeys(object, KeyCollectionMode::kOwnOnly, filter, |
| GetKeysConversion::kConvertToString)); |
| |
| return *isolate->factory()->NewJSArrayWithElements(keys); |
| } |
| |
| |
| // Return information on whether an object has a named or indexed interceptor. |
| // args[0]: object |
| RUNTIME_FUNCTION(Runtime_GetInterceptorInfo) { |
| HandleScope scope(isolate); |
| DCHECK_EQ(1, args.length()); |
| if (!args[0]->IsJSObject()) { |
| return Smi::kZero; |
| } |
| CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); |
| |
| int result = 0; |
| if (obj->HasNamedInterceptor()) result |= 2; |
| if (obj->HasIndexedInterceptor()) result |= 1; |
| |
| return Smi::FromInt(result); |
| } |
| |
| |
| RUNTIME_FUNCTION(Runtime_ToFastProperties) { |
| HandleScope scope(isolate); |
| DCHECK_EQ(1, args.length()); |
| CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); |
| if (object->IsJSObject() && !object->IsJSGlobalObject()) { |
| JSObject::MigrateSlowToFast(Handle<JSObject>::cast(object), 0, |
| "RuntimeToFastProperties"); |
| } |
| return *object; |
| } |
| |
| |
| RUNTIME_FUNCTION(Runtime_AllocateHeapNumber) { |
| HandleScope scope(isolate); |
| DCHECK_EQ(0, args.length()); |
| return *isolate->factory()->NewHeapNumber(0); |
| } |
| |
| |
| RUNTIME_FUNCTION(Runtime_NewObject) { |
| HandleScope scope(isolate); |
| DCHECK_EQ(2, args.length()); |
| CONVERT_ARG_HANDLE_CHECKED(JSFunction, target, 0); |
| CONVERT_ARG_HANDLE_CHECKED(JSReceiver, new_target, 1); |
| RETURN_RESULT_OR_FAILURE(isolate, JSObject::New(target, new_target)); |
| } |
| |
| RUNTIME_FUNCTION(Runtime_CompleteInobjectSlackTrackingForMap) { |
| DisallowHeapAllocation no_gc; |
| HandleScope scope(isolate); |
| DCHECK_EQ(1, args.length()); |
| |
| CONVERT_ARG_HANDLE_CHECKED(Map, initial_map, 0); |
| initial_map->CompleteInobjectSlackTracking(); |
| |
| return isolate->heap()->undefined_value(); |
| } |
| |
| |
| RUNTIME_FUNCTION(Runtime_LoadMutableDouble) { |
| HandleScope scope(isolate); |
| DCHECK_EQ(2, args.length()); |
| CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); |
| CONVERT_ARG_HANDLE_CHECKED(Smi, index, 1); |
| CHECK_EQ(index->value() & 1, 1); |
| FieldIndex field_index = |
| FieldIndex::ForLoadByFieldIndex(object->map(), index->value()); |
| if (field_index.is_inobject()) { |
| CHECK(field_index.property_index() < |
| object->map()->GetInObjectProperties()); |
| } else { |
| CHECK(field_index.outobject_array_index() < |
| object->property_dictionary()->length()); |
| } |
| return *JSObject::FastPropertyAt(object, Representation::Double(), |
| field_index); |
| } |
| |
| |
| RUNTIME_FUNCTION(Runtime_TryMigrateInstance) { |
| HandleScope scope(isolate); |
| DCHECK_EQ(1, args.length()); |
| CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); |
| if (!object->IsJSObject()) return Smi::kZero; |
| Handle<JSObject> js_object = Handle<JSObject>::cast(object); |
| // It could have been a DCHECK but we call this function directly from tests. |
| if (!js_object->map()->is_deprecated()) return Smi::kZero; |
| // This call must not cause lazy deopts, because it's called from deferred |
| // code where we can't handle lazy deopts for lack of a suitable bailout |
| // ID. So we just try migration and signal failure if necessary, |
| // which will also trigger a deopt. |
| if (!JSObject::TryMigrateInstance(js_object)) return Smi::kZero; |
| return *object; |
| } |
| |
| |
| RUNTIME_FUNCTION(Runtime_IsJSGlobalProxy) { |
| SealHandleScope shs(isolate); |
| DCHECK_EQ(1, args.length()); |
| CONVERT_ARG_CHECKED(Object, obj, 0); |
| return isolate->heap()->ToBoolean(obj->IsJSGlobalProxy()); |
| } |
| |
| static bool IsValidAccessor(Isolate* isolate, Handle<Object> obj) { |
| return obj->IsNullOrUndefined(isolate) || obj->IsCallable(); |
| } |
| |
| |
| // Implements part of 8.12.9 DefineOwnProperty. |
| // There are 3 cases that lead here: |
| // Step 4b - define a new accessor property. |
| // Steps 9c & 12 - replace an existing data property with an accessor property. |
| // Step 12 - update an existing accessor property with an accessor or generic |
| // descriptor. |
| RUNTIME_FUNCTION(Runtime_DefineAccessorPropertyUnchecked) { |
| HandleScope scope(isolate); |
| DCHECK_EQ(5, args.length()); |
| CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); |
| CHECK(!obj->IsNull(isolate)); |
| CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); |
| CONVERT_ARG_HANDLE_CHECKED(Object, getter, 2); |
| CHECK(IsValidAccessor(isolate, getter)); |
| CONVERT_ARG_HANDLE_CHECKED(Object, setter, 3); |
| CHECK(IsValidAccessor(isolate, setter)); |
| CONVERT_PROPERTY_ATTRIBUTES_CHECKED(attrs, 4); |
| |
| RETURN_FAILURE_ON_EXCEPTION( |
| isolate, JSObject::DefineAccessor(obj, name, getter, setter, attrs)); |
| return isolate->heap()->undefined_value(); |
| } |
| |
| |
| RUNTIME_FUNCTION(Runtime_DefineDataPropertyInLiteral) { |
| HandleScope scope(isolate); |
| DCHECK_EQ(6, args.length()); |
| CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); |
| CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); |
| CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); |
| CONVERT_SMI_ARG_CHECKED(flag, 3); |
| CONVERT_ARG_HANDLE_CHECKED(FeedbackVector, vector, 4); |
| CONVERT_SMI_ARG_CHECKED(index, 5); |
| |
| StoreDataPropertyInLiteralICNexus nexus(vector, vector->ToSlot(index)); |
| if (nexus.ic_state() == UNINITIALIZED) { |
| if (name->IsUniqueName()) { |
| nexus.ConfigureMonomorphic(name, handle(object->map())); |
| } else { |
| nexus.ConfigureMegamorphic(PROPERTY); |
| } |
| } else if (nexus.ic_state() == MONOMORPHIC) { |
| if (nexus.FindFirstMap() != object->map() || |
| nexus.GetFeedbackExtra() != *name) { |
| nexus.ConfigureMegamorphic(PROPERTY); |
| } |
| } |
| |
| DataPropertyInLiteralFlags flags = |
| static_cast<DataPropertyInLiteralFlag>(flag); |
| |
| PropertyAttributes attrs = (flags & DataPropertyInLiteralFlag::kDontEnum) |
| ? PropertyAttributes::DONT_ENUM |
| : PropertyAttributes::NONE; |
| |
| if (flags & DataPropertyInLiteralFlag::kSetFunctionName) { |
| DCHECK(value->IsJSFunction()); |
| Handle<JSFunction> function = Handle<JSFunction>::cast(value); |
| DCHECK(!function->shared()->has_shared_name()); |
| Handle<Map> function_map(function->map(), isolate); |
| if (!JSFunction::SetName(function, name, |
| isolate->factory()->empty_string())) { |
| return isolate->heap()->exception(); |
| } |
| // Class constructors do not reserve in-object space for name field. |
| CHECK_IMPLIES(!IsClassConstructor(function->shared()->kind()), |
| *function_map == function->map()); |
| } |
| |
| LookupIterator it = LookupIterator::PropertyOrElement( |
| isolate, object, name, object, LookupIterator::OWN); |
| // Cannot fail since this should only be called when |
| // creating an object literal. |
| CHECK( |
| JSObject::DefineOwnPropertyIgnoreAttributes(&it, value, attrs, kDontThrow) |
| .IsJust()); |
| return *object; |
| } |
| |
| RUNTIME_FUNCTION(Runtime_CollectTypeProfile) { |
| HandleScope scope(isolate); |
| DCHECK_EQ(3, args.length()); |
| CONVERT_ARG_HANDLE_CHECKED(Smi, position, 0); |
| CONVERT_ARG_HANDLE_CHECKED(Object, value, 1); |
| CONVERT_ARG_HANDLE_CHECKED(FeedbackVector, vector, 2); |
| |
| Handle<String> type = Object::TypeOf(isolate, value); |
| if (value->IsJSReceiver()) { |
| Handle<JSReceiver> object = Handle<JSReceiver>::cast(value); |
| type = JSReceiver::GetConstructorName(object); |
| } else if (value->IsNull(isolate)) { |
| // typeof(null) is object. But it's more user-friendly to annotate |
| // null as type "null". |
| type = Handle<String>(isolate->heap()->null_string()); |
| } |
| |
| DCHECK(vector->metadata()->HasTypeProfileSlot()); |
| CollectTypeProfileNexus nexus(vector, vector->GetTypeProfileSlot()); |
| nexus.Collect(type, position->value()); |
| |
| return isolate->heap()->undefined_value(); |
| } |
| |
| // Return property without being observable by accessors or interceptors. |
| RUNTIME_FUNCTION(Runtime_GetDataProperty) { |
| HandleScope scope(isolate); |
| DCHECK_EQ(2, args.length()); |
| CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0); |
| CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); |
| return *JSReceiver::GetDataProperty(object, name); |
| } |
| |
| RUNTIME_FUNCTION(Runtime_GetConstructorName) { |
| HandleScope scope(isolate); |
| DCHECK_EQ(1, args.length()); |
| CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); |
| |
| CHECK(!object->IsNullOrUndefined(isolate)); |
| Handle<JSReceiver> recv = Object::ToObject(isolate, object).ToHandleChecked(); |
| return *JSReceiver::GetConstructorName(recv); |
| } |
| |
| RUNTIME_FUNCTION(Runtime_HasFastPackedElements) { |
| SealHandleScope shs(isolate); |
| DCHECK_EQ(1, args.length()); |
| CONVERT_ARG_CHECKED(HeapObject, obj, 0); |
| return isolate->heap()->ToBoolean( |
| IsFastPackedElementsKind(obj->map()->elements_kind())); |
| } |
| |
| |
| RUNTIME_FUNCTION(Runtime_ValueOf) { |
| SealHandleScope shs(isolate); |
| DCHECK_EQ(1, args.length()); |
| CONVERT_ARG_CHECKED(Object, obj, 0); |
| if (!obj->IsJSValue()) return obj; |
| return JSValue::cast(obj)->value(); |
| } |
| |
| |
| RUNTIME_FUNCTION(Runtime_IsJSReceiver) { |
| SealHandleScope shs(isolate); |
| DCHECK_EQ(1, args.length()); |
| CONVERT_ARG_CHECKED(Object, obj, 0); |
| return isolate->heap()->ToBoolean(obj->IsJSReceiver()); |
| } |
| |
| |
| RUNTIME_FUNCTION(Runtime_ClassOf) { |
| SealHandleScope shs(isolate); |
| DCHECK_EQ(1, args.length()); |
| CONVERT_ARG_CHECKED(Object, obj, 0); |
| if (!obj->IsJSReceiver()) return isolate->heap()->null_value(); |
| return JSReceiver::cast(obj)->class_name(); |
| } |
| |
| |
| RUNTIME_FUNCTION(Runtime_DefineGetterPropertyUnchecked) { |
| HandleScope scope(isolate); |
| DCHECK_EQ(4, args.length()); |
| CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); |
| CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); |
| CONVERT_ARG_HANDLE_CHECKED(JSFunction, getter, 2); |
| CONVERT_PROPERTY_ATTRIBUTES_CHECKED(attrs, 3); |
| |
| if (String::cast(getter->shared()->name())->length() == 0) { |
| Handle<Map> getter_map(getter->map(), isolate); |
| if (!JSFunction::SetName(getter, name, isolate->factory()->get_string())) { |
| return isolate->heap()->exception(); |
| } |
| CHECK_EQ(*getter_map, getter->map()); |
| } |
| |
| RETURN_FAILURE_ON_EXCEPTION( |
| isolate, |
| JSObject::DefineAccessor(object, name, getter, |
| isolate->factory()->null_value(), attrs)); |
| return isolate->heap()->undefined_value(); |
| } |
| |
| RUNTIME_FUNCTION(Runtime_CopyDataProperties) { |
| HandleScope scope(isolate); |
| DCHECK_EQ(2, args.length()); |
| CONVERT_ARG_HANDLE_CHECKED(JSObject, target, 0); |
| CONVERT_ARG_HANDLE_CHECKED(Object, source, 1); |
| |
| // 2. If source is undefined or null, let keys be an empty List. |
| if (source->IsUndefined(isolate) || source->IsNull(isolate)) { |
| return isolate->heap()->undefined_value(); |
| } |
| |
| MAYBE_RETURN(JSReceiver::SetOrCopyDataProperties(isolate, target, source, |
| nullptr, false), |
| isolate->heap()->exception()); |
| return isolate->heap()->undefined_value(); |
| } |
| |
| RUNTIME_FUNCTION(Runtime_CopyDataPropertiesWithExcludedProperties) { |
| HandleScope scope(isolate); |
| DCHECK_LE(1, args.length()); |
| CONVERT_ARG_HANDLE_CHECKED(Object, source, 0); |
| |
| // 2. If source is undefined or null, let keys be an empty List. |
| if (source->IsUndefined(isolate) || source->IsNull(isolate)) { |
| return isolate->heap()->undefined_value(); |
| } |
| |
| ScopedVector<Handle<Object>> excluded_properties(args.length() - 1); |
| for (int i = 1; i < args.length(); i++) { |
| Handle<Object> property = args.at(i); |
| uint32_t property_num; |
| // We convert string to number if possible, in cases of computed |
| // properties resolving to numbers, which would've been strings |
| // instead because of our call to %ToName() in the desugaring for |
| // computed properties. |
| if (property->IsString() && |
| String::cast(*property)->AsArrayIndex(&property_num)) { |
| property = isolate->factory()->NewNumberFromUint(property_num); |
| } |
| |
| excluded_properties[i - 1] = property; |
| } |
| |
| Handle<JSObject> target = |
| isolate->factory()->NewJSObject(isolate->object_function()); |
| MAYBE_RETURN(JSReceiver::SetOrCopyDataProperties(isolate, target, source, |
| &excluded_properties, false), |
| isolate->heap()->exception()); |
| return *target; |
| } |
| |
| namespace { |
| |
| inline void TrySetNative(Handle<Object> maybe_func) { |
| if (!maybe_func->IsJSFunction()) return; |
| JSFunction::cast(*maybe_func)->shared()->set_native(true); |
| } |
| |
| inline void TrySetNativeAndLength(Handle<Object> maybe_func, int length) { |
| if (!maybe_func->IsJSFunction()) return; |
| SharedFunctionInfo* shared = JSFunction::cast(*maybe_func)->shared(); |
| shared->set_native(true); |
| if (length >= 0) { |
| shared->set_length(length); |
| } |
| } |
| |
| } // namespace |
| |
| RUNTIME_FUNCTION(Runtime_DefineMethodsInternal) { |
| HandleScope scope(isolate); |
| DCHECK_EQ(3, args.length()); |
| CHECK(isolate->bootstrapper()->IsActive()); |
| CONVERT_ARG_HANDLE_CHECKED(JSObject, target, 0); |
| CONVERT_ARG_HANDLE_CHECKED(JSFunction, source_class, 1); |
| CONVERT_SMI_ARG_CHECKED(length, 2); |
| |
| DCHECK(source_class->prototype()->IsJSObject()); |
| Handle<JSObject> source(JSObject::cast(source_class->prototype()), isolate); |
| |
| Handle<FixedArray> keys; |
| ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| isolate, keys, |
| KeyAccumulator::GetKeys(source, KeyCollectionMode::kOwnOnly, |
| ALL_PROPERTIES, |
| GetKeysConversion::kConvertToString)); |
| |
| for (int i = 0; i < keys->length(); ++i) { |
| Handle<Name> key = Handle<Name>::cast(FixedArray::get(*keys, i, isolate)); |
| if (*key == isolate->heap()->constructor_string()) continue; |
| |
| PropertyDescriptor descriptor; |
| Maybe<bool> did_get_descriptor = |
| JSReceiver::GetOwnPropertyDescriptor(isolate, source, key, &descriptor); |
| CHECK(did_get_descriptor.FromJust()); |
| if (descriptor.has_value()) { |
| TrySetNativeAndLength(descriptor.value(), length); |
| } else { |
| if (descriptor.has_get()) TrySetNative(descriptor.get()); |
| if (descriptor.has_set()) TrySetNative(descriptor.set()); |
| } |
| |
| Maybe<bool> success = JSReceiver::DefineOwnProperty( |
| isolate, target, key, &descriptor, kDontThrow); |
| CHECK(success.FromJust()); |
| } |
| return isolate->heap()->undefined_value(); |
| } |
| |
| RUNTIME_FUNCTION(Runtime_DefineSetterPropertyUnchecked) { |
| HandleScope scope(isolate); |
| DCHECK_EQ(4, args.length()); |
| CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); |
| CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); |
| CONVERT_ARG_HANDLE_CHECKED(JSFunction, setter, 2); |
| CONVERT_PROPERTY_ATTRIBUTES_CHECKED(attrs, 3); |
| |
| if (String::cast(setter->shared()->name())->length() == 0) { |
| Handle<Map> setter_map(setter->map(), isolate); |
| if (!JSFunction::SetName(setter, name, isolate->factory()->set_string())) { |
| return isolate->heap()->exception(); |
| } |
| CHECK_EQ(*setter_map, setter->map()); |
| } |
| |
| RETURN_FAILURE_ON_EXCEPTION( |
| isolate, |
| JSObject::DefineAccessor(object, name, isolate->factory()->null_value(), |
| setter, attrs)); |
| return isolate->heap()->undefined_value(); |
| } |
| |
| RUNTIME_FUNCTION(Runtime_ToObject) { |
| // Runtime call is implemented in InterpreterIntrinsics and lowered in |
| // JSIntrinsicLowering. |
| UNREACHABLE(); |
| } |
| |
| RUNTIME_FUNCTION(Runtime_ToPrimitive) { |
| HandleScope scope(isolate); |
| DCHECK_EQ(1, args.length()); |
| CONVERT_ARG_HANDLE_CHECKED(Object, input, 0); |
| RETURN_RESULT_OR_FAILURE(isolate, Object::ToPrimitive(input)); |
| } |
| |
| |
| RUNTIME_FUNCTION(Runtime_ToPrimitive_Number) { |
| HandleScope scope(isolate); |
| DCHECK_EQ(1, args.length()); |
| CONVERT_ARG_HANDLE_CHECKED(Object, input, 0); |
| RETURN_RESULT_OR_FAILURE( |
| isolate, Object::ToPrimitive(input, ToPrimitiveHint::kNumber)); |
| } |
| |
| RUNTIME_FUNCTION(Runtime_ToNumber) { |
| HandleScope scope(isolate); |
| DCHECK_EQ(1, args.length()); |
| CONVERT_ARG_HANDLE_CHECKED(Object, input, 0); |
| RETURN_RESULT_OR_FAILURE(isolate, Object::ToNumber(input)); |
| } |
| |
| RUNTIME_FUNCTION(Runtime_ToNumeric) { |
| HandleScope scope(isolate); |
| DCHECK_EQ(1, args.length()); |
| CONVERT_ARG_HANDLE_CHECKED(Object, input, 0); |
| RETURN_RESULT_OR_FAILURE(isolate, Object::ToNumeric(input)); |
| } |
| |
| RUNTIME_FUNCTION(Runtime_ToInteger) { |
| HandleScope scope(isolate); |
| DCHECK_EQ(1, args.length()); |
| CONVERT_ARG_HANDLE_CHECKED(Object, input, 0); |
| RETURN_RESULT_OR_FAILURE(isolate, Object::ToInteger(isolate, input)); |
| } |
| |
| |
| RUNTIME_FUNCTION(Runtime_ToLength) { |
| HandleScope scope(isolate); |
| DCHECK_EQ(1, args.length()); |
| CONVERT_ARG_HANDLE_CHECKED(Object, input, 0); |
| RETURN_RESULT_OR_FAILURE(isolate, Object::ToLength(isolate, input)); |
| } |
| |
| |
| RUNTIME_FUNCTION(Runtime_ToString) { |
| HandleScope scope(isolate); |
| DCHECK_EQ(1, args.length()); |
| CONVERT_ARG_HANDLE_CHECKED(Object, input, 0); |
| RETURN_RESULT_OR_FAILURE(isolate, Object::ToString(isolate, input)); |
| } |
| |
| |
| RUNTIME_FUNCTION(Runtime_ToName) { |
| HandleScope scope(isolate); |
| DCHECK_EQ(1, args.length()); |
| CONVERT_ARG_HANDLE_CHECKED(Object, input, 0); |
| RETURN_RESULT_OR_FAILURE(isolate, Object::ToName(isolate, input)); |
| } |
| |
| |
| RUNTIME_FUNCTION(Runtime_SameValue) { |
| SealHandleScope scope(isolate); |
| DCHECK_EQ(2, args.length()); |
| CONVERT_ARG_CHECKED(Object, x, 0); |
| CONVERT_ARG_CHECKED(Object, y, 1); |
| return isolate->heap()->ToBoolean(x->SameValue(y)); |
| } |
| |
| |
| RUNTIME_FUNCTION(Runtime_SameValueZero) { |
| SealHandleScope scope(isolate); |
| DCHECK_EQ(2, args.length()); |
| CONVERT_ARG_CHECKED(Object, x, 0); |
| CONVERT_ARG_CHECKED(Object, y, 1); |
| return isolate->heap()->ToBoolean(x->SameValueZero(y)); |
| } |
| |
| RUNTIME_FUNCTION(Runtime_HasInPrototypeChain) { |
| HandleScope scope(isolate); |
| DCHECK_EQ(2, args.length()); |
| CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); |
| CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1); |
| if (!object->IsJSReceiver()) return isolate->heap()->false_value(); |
| Maybe<bool> result = JSReceiver::HasInPrototypeChain( |
| isolate, Handle<JSReceiver>::cast(object), prototype); |
| MAYBE_RETURN(result, isolate->heap()->exception()); |
| return isolate->heap()->ToBoolean(result.FromJust()); |
| } |
| |
| |
| // ES6 section 7.4.7 CreateIterResultObject ( value, done ) |
| RUNTIME_FUNCTION(Runtime_CreateIterResultObject) { |
| HandleScope scope(isolate); |
| DCHECK_EQ(2, args.length()); |
| CONVERT_ARG_HANDLE_CHECKED(Object, value, 0); |
| CONVERT_ARG_HANDLE_CHECKED(Object, done, 1); |
| return *isolate->factory()->NewJSIteratorResult(value, done->BooleanValue()); |
| } |
| |
| RUNTIME_FUNCTION(Runtime_CreateDataProperty) { |
| HandleScope scope(isolate); |
| DCHECK_EQ(3, args.length()); |
| CONVERT_ARG_HANDLE_CHECKED(JSReceiver, o, 0); |
| CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); |
| CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); |
| bool success; |
| LookupIterator it = LookupIterator::PropertyOrElement( |
| isolate, o, key, &success, LookupIterator::OWN); |
| if (!success) return isolate->heap()->exception(); |
| MAYBE_RETURN(JSReceiver::CreateDataProperty(&it, value, kThrowOnError), |
| isolate->heap()->exception()); |
| return *value; |
| } |
| |
| // Checks that 22.2.2.1.1 Runtime Semantics: IterableToList produces exactly the |
| // same result as doing nothing. |
| RUNTIME_FUNCTION(Runtime_IterableToListCanBeElided) { |
| HandleScope scope(isolate); |
| DCHECK_EQ(1, args.length()); |
| CONVERT_ARG_HANDLE_CHECKED(JSReceiver, obj, 0); |
| |
| if (!obj->IsJSObject()) return isolate->heap()->ToBoolean(false); |
| |
| // While iteration alone may not have observable side-effects, calling |
| // toNumber on an object will. Make sure the arg is not an array of objects. |
| ElementsKind kind = JSObject::cast(*obj)->GetElementsKind(); |
| if (!IsFastNumberElementsKind(kind)) return isolate->heap()->ToBoolean(false); |
| |
| return isolate->heap()->ToBoolean(!obj->IterationHasObservableEffects()); |
| } |
| |
| RUNTIME_FUNCTION(Runtime_GetOwnPropertyDescriptor) { |
| HandleScope scope(isolate); |
| |
| DCHECK_EQ(2, args.length()); |
| CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0); |
| CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); |
| |
| PropertyDescriptor desc; |
| Maybe<bool> found = |
| JSReceiver::GetOwnPropertyDescriptor(isolate, object, name, &desc); |
| MAYBE_RETURN(found, isolate->heap()->exception()); |
| |
| if (!found.FromJust()) return isolate->heap()->undefined_value(); |
| return *desc.ToPropertyDescriptorObject(isolate); |
| } |
| |
| } // namespace internal |
| } // namespace v8 |