Index: src/runtime/runtime-object.cc |
diff --git a/src/runtime/runtime-object.cc b/src/runtime/runtime-object.cc |
index b3b917b03ab2eafc8bebc5a9d212517b4d250ea9..d119867b3044480881e24e890a69092b64430cc5 100644 |
--- a/src/runtime/runtime-object.cc |
+++ b/src/runtime/runtime-object.cc |
@@ -26,7 +26,8 @@ |
MaybeHandle<Object> Runtime::GetElementOrCharAt(Isolate* isolate, |
Handle<Object> object, |
- uint32_t index) { |
+ uint32_t index, |
+ LanguageMode language_mode) { |
// Handle [] indexing on Strings |
if (object->IsString() && |
index < static_cast<uint32_t>(String::cast(*object)->length())) { |
@@ -34,7 +35,7 @@ |
if (!result->IsUndefined()) return result; |
} |
- return Object::GetElement(isolate, object, index); |
+ return Object::GetElement(isolate, object, index, language_mode); |
} |
@@ -52,7 +53,8 @@ |
MaybeHandle<Object> Runtime::GetObjectProperty(Isolate* isolate, |
Handle<Object> object, |
- Handle<Object> key) { |
+ Handle<Object> key, |
+ LanguageMode language_mode) { |
if (object->IsUndefined() || object->IsNull()) { |
THROW_NEW_ERROR( |
isolate, |
@@ -63,7 +65,7 @@ |
// Check if the given key is an array index. |
uint32_t index = 0; |
if (key->ToArrayIndex(&index)) { |
- return GetElementOrCharAt(isolate, object, index); |
+ return GetElementOrCharAt(isolate, object, index, language_mode); |
} |
// Convert the key to a name - possibly by calling back into JavaScript. |
@@ -77,320 +79,8 @@ |
if (name->AsArrayIndex(&index)) { |
return GetElementOrCharAt(isolate, object, index); |
} else { |
- return Object::GetProperty(object, name); |
- } |
-} |
- |
- |
-MaybeHandle<Object> Runtime::SetObjectProperty(Isolate* isolate, |
- Handle<Object> object, |
- Handle<Object> key, |
- Handle<Object> value, |
- LanguageMode language_mode) { |
- if (object->IsUndefined() || object->IsNull()) { |
- THROW_NEW_ERROR( |
- isolate, |
- NewTypeError(MessageTemplate::kNonObjectPropertyStore, key, object), |
- Object); |
- } |
- |
- // Check if the given key is an array index. |
- uint32_t index = 0; |
- if (key->ToArrayIndex(&index)) { |
- // TODO(verwaest): Support other objects as well. |
- if (!object->IsJSReceiver()) return value; |
- return JSReceiver::SetElement(Handle<JSReceiver>::cast(object), index, |
- value, language_mode); |
- } |
- |
- Handle<Name> name; |
- ASSIGN_RETURN_ON_EXCEPTION(isolate, name, ToName(isolate, key), Object); |
- |
- LookupIterator it = LookupIterator::PropertyOrElement(isolate, object, name); |
- // TODO(verwaest): Support other objects as well. |
- if (it.IsElement() && !object->IsJSReceiver()) return value; |
- return Object::SetProperty(&it, value, language_mode, |
- Object::MAY_BE_STORE_FROM_KEYED); |
-} |
- |
- |
-MaybeHandle<Object> Runtime::GetPrototype(Isolate* isolate, |
- Handle<Object> obj) { |
- // We don't expect access checks to be needed on JSProxy objects. |
- DCHECK(!obj->IsAccessCheckNeeded() || obj->IsJSObject()); |
- PrototypeIterator iter(isolate, obj, PrototypeIterator::START_AT_RECEIVER); |
- do { |
- if (PrototypeIterator::GetCurrent(iter)->IsAccessCheckNeeded() && |
- !isolate->MayAccess( |
- Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)))) { |
- isolate->ReportFailedAccessCheck( |
- Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter))); |
- RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); |
- return isolate->factory()->undefined_value(); |
- } |
- iter.AdvanceIgnoringProxies(); |
- if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) { |
- return PrototypeIterator::GetCurrent(iter); |
- } |
- } while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)); |
- return PrototypeIterator::GetCurrent(iter); |
-} |
- |
- |
-RUNTIME_FUNCTION(Runtime_GetPrototype) { |
- HandleScope scope(isolate); |
- DCHECK(args.length() == 1); |
- CONVERT_ARG_HANDLE_CHECKED(Object, obj, 0); |
- Handle<Object> result; |
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, |
- Runtime::GetPrototype(isolate, obj)); |
- return *result; |
-} |
- |
- |
-RUNTIME_FUNCTION(Runtime_InternalSetPrototype) { |
- HandleScope scope(isolate); |
- DCHECK(args.length() == 2); |
- CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); |
- CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1); |
- DCHECK(!obj->IsAccessCheckNeeded()); |
- DCHECK(!obj->map()->is_observed()); |
- Handle<Object> result; |
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
- isolate, result, JSObject::SetPrototype(obj, prototype, false)); |
- return *result; |
-} |
- |
- |
-RUNTIME_FUNCTION(Runtime_SetPrototype) { |
- HandleScope scope(isolate); |
- DCHECK(args.length() == 2); |
- CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); |
- CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1); |
- if (obj->IsAccessCheckNeeded() && !isolate->MayAccess(obj)) { |
- isolate->ReportFailedAccessCheck(obj); |
- RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); |
- return isolate->heap()->undefined_value(); |
- } |
- if (obj->map()->is_observed()) { |
- Handle<Object> old_value = |
- Object::GetPrototypeSkipHiddenPrototypes(isolate, obj); |
- Handle<Object> result; |
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
- isolate, result, JSObject::SetPrototype(obj, prototype, true)); |
- |
- Handle<Object> new_value = |
- Object::GetPrototypeSkipHiddenPrototypes(isolate, obj); |
- if (!new_value->SameValue(*old_value)) { |
- RETURN_FAILURE_ON_EXCEPTION( |
- isolate, JSObject::EnqueueChangeRecord( |
- obj, "setPrototype", isolate->factory()->proto_string(), |
- old_value)); |
- } |
- return *result; |
- } |
- Handle<Object> result; |
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
- isolate, result, JSObject::SetPrototype(obj, prototype, true)); |
- return *result; |
-} |
- |
- |
-RUNTIME_FUNCTION(Runtime_IsInPrototypeChain) { |
- HandleScope shs(isolate); |
- DCHECK(args.length() == 2); |
- // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8). |
- CONVERT_ARG_HANDLE_CHECKED(Object, O, 0); |
- CONVERT_ARG_HANDLE_CHECKED(Object, V, 1); |
- PrototypeIterator iter(isolate, V, PrototypeIterator::START_AT_RECEIVER); |
- while (true) { |
- iter.AdvanceIgnoringProxies(); |
- if (iter.IsAtEnd()) return isolate->heap()->false_value(); |
- if (iter.IsAtEnd(O)) return isolate->heap()->true_value(); |
- } |
-} |
- |
- |
-// Enumerator used as indices into the array returned from GetOwnProperty |
-enum PropertyDescriptorIndices { |
- IS_ACCESSOR_INDEX, |
- VALUE_INDEX, |
- GETTER_INDEX, |
- SETTER_INDEX, |
- WRITABLE_INDEX, |
- ENUMERABLE_INDEX, |
- CONFIGURABLE_INDEX, |
- DESCRIPTOR_SIZE |
-}; |
- |
- |
-MUST_USE_RESULT static MaybeHandle<Object> GetOwnProperty(Isolate* isolate, |
- Handle<JSObject> obj, |
- Handle<Name> name) { |
- Heap* heap = isolate->heap(); |
- Factory* factory = isolate->factory(); |
- |
- PropertyAttributes attrs; |
- // Get attributes. |
- LookupIterator it = LookupIterator::PropertyOrElement(isolate, obj, name, |
- LookupIterator::HIDDEN); |
- Maybe<PropertyAttributes> maybe = JSObject::GetPropertyAttributes(&it); |
- |
- if (!maybe.IsJust()) return MaybeHandle<Object>(); |
- attrs = maybe.FromJust(); |
- if (attrs == ABSENT) return factory->undefined_value(); |
- |
- DCHECK(!isolate->has_pending_exception()); |
- Handle<FixedArray> elms = factory->NewFixedArray(DESCRIPTOR_SIZE); |
- elms->set(ENUMERABLE_INDEX, heap->ToBoolean((attrs & DONT_ENUM) == 0)); |
- elms->set(CONFIGURABLE_INDEX, heap->ToBoolean((attrs & DONT_DELETE) == 0)); |
- |
- bool is_accessor_pair = it.state() == LookupIterator::ACCESSOR && |
- it.GetAccessors()->IsAccessorPair(); |
- elms->set(IS_ACCESSOR_INDEX, heap->ToBoolean(is_accessor_pair)); |
- |
- if (is_accessor_pair) { |
- Handle<AccessorPair> accessors = |
- Handle<AccessorPair>::cast(it.GetAccessors()); |
- Handle<Object> getter(accessors->GetComponent(ACCESSOR_GETTER), isolate); |
- Handle<Object> setter(accessors->GetComponent(ACCESSOR_SETTER), isolate); |
- elms->set(GETTER_INDEX, *getter); |
- elms->set(SETTER_INDEX, *setter); |
- } else { |
- Handle<Object> value; |
- ASSIGN_RETURN_ON_EXCEPTION(isolate, value, Object::GetProperty(&it), |
- Object); |
- elms->set(WRITABLE_INDEX, heap->ToBoolean((attrs & READ_ONLY) == 0)); |
- elms->set(VALUE_INDEX, *value); |
- } |
- |
- return factory->NewJSArrayWithElements(elms); |
-} |
- |
- |
-// Returns an array with the property description: |
-// if args[1] is not a property on args[0] |
-// returns undefined |
-// if args[1] is a data property on args[0] |
-// [false, value, Writeable, Enumerable, Configurable] |
-// if args[1] is an accessor on args[0] |
-// [true, GetFunction, SetFunction, Enumerable, Configurable] |
-RUNTIME_FUNCTION(Runtime_GetOwnProperty) { |
- HandleScope scope(isolate); |
- DCHECK(args.length() == 2); |
- CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); |
- CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); |
- Handle<Object> result; |
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, |
- GetOwnProperty(isolate, obj, name)); |
- return *result; |
-} |
- |
- |
-RUNTIME_FUNCTION(Runtime_PreventExtensions) { |
- HandleScope scope(isolate); |
- DCHECK(args.length() == 1); |
- CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); |
- Handle<Object> result; |
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, |
- JSObject::PreventExtensions(obj)); |
- return *result; |
-} |
- |
- |
-RUNTIME_FUNCTION(Runtime_IsExtensible) { |
- SealHandleScope shs(isolate); |
- DCHECK(args.length() == 1); |
- CONVERT_ARG_CHECKED(JSObject, obj, 0); |
- return isolate->heap()->ToBoolean(obj->IsExtensible()); |
-} |
- |
- |
-RUNTIME_FUNCTION(Runtime_DisableAccessChecks) { |
- HandleScope scope(isolate); |
- DCHECK(args.length() == 1); |
- CONVERT_ARG_HANDLE_CHECKED(HeapObject, object, 0); |
- Handle<Map> old_map(object->map()); |
- bool needs_access_checks = old_map->is_access_check_needed(); |
- if (needs_access_checks) { |
- // Copy map so it won't interfere constructor's initial map. |
- Handle<Map> new_map = Map::Copy(old_map, "DisableAccessChecks"); |
- new_map->set_is_access_check_needed(false); |
- JSObject::MigrateToMap(Handle<JSObject>::cast(object), new_map); |
- } |
- return isolate->heap()->ToBoolean(needs_access_checks); |
-} |
- |
- |
-RUNTIME_FUNCTION(Runtime_EnableAccessChecks) { |
- HandleScope scope(isolate); |
- DCHECK(args.length() == 1); |
- CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); |
- Handle<Map> old_map(object->map()); |
- RUNTIME_ASSERT(!old_map->is_access_check_needed()); |
- // Copy map so it won't interfere constructor's initial map. |
- Handle<Map> new_map = Map::Copy(old_map, "EnableAccessChecks"); |
- new_map->set_is_access_check_needed(true); |
- JSObject::MigrateToMap(object, new_map); |
- return isolate->heap()->undefined_value(); |
-} |
- |
- |
-RUNTIME_FUNCTION(Runtime_OptimizeObjectForAddingMultipleProperties) { |
- HandleScope scope(isolate); |
- DCHECK(args.length() == 2); |
- CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); |
- CONVERT_SMI_ARG_CHECKED(properties, 1); |
- // Conservative upper limit to prevent fuzz tests from going OOM. |
- RUNTIME_ASSERT(properties <= 100000); |
- if (object->HasFastProperties() && !object->IsJSGlobalProxy()) { |
- JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties, |
- "OptimizeForAdding"); |
- } |
- return *object; |
-} |
- |
- |
-RUNTIME_FUNCTION(Runtime_ObjectFreeze) { |
- HandleScope scope(isolate); |
- DCHECK(args.length() == 1); |
- CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); |
- |
- // %ObjectFreeze is a fast path and these cases are handled elsewhere. |
- RUNTIME_ASSERT(!object->HasSloppyArgumentsElements() && |
- !object->map()->is_observed() && !object->IsJSProxy()); |
- |
- Handle<Object> result; |
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, JSObject::Freeze(object)); |
- return *result; |
-} |
- |
- |
-RUNTIME_FUNCTION(Runtime_ObjectSeal) { |
- HandleScope scope(isolate); |
- DCHECK(args.length() == 1); |
- CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); |
- |
- // %ObjectSeal is a fast path and these cases are handled elsewhere. |
- RUNTIME_ASSERT(!object->HasSloppyArgumentsElements() && |
- !object->map()->is_observed() && !object->IsJSProxy()); |
- |
- Handle<Object> result; |
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, JSObject::Seal(object)); |
- return *result; |
-} |
- |
- |
-RUNTIME_FUNCTION(Runtime_GetProperty) { |
- HandleScope scope(isolate); |
- DCHECK(args.length() == 2); |
- |
- CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); |
- CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); |
- Handle<Object> result; |
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
- isolate, result, Runtime::GetObjectProperty(isolate, object, key)); |
- return *result; |
+ return Object::GetProperty(object, name, language_mode); |
+ } |
} |
@@ -412,14 +102,9 @@ |
} |
-// KeyedGetProperty is called from KeyedLoadIC::GenerateGeneric. |
-RUNTIME_FUNCTION(Runtime_KeyedGetProperty) { |
- HandleScope scope(isolate); |
- DCHECK(args.length() == 2); |
- |
- CONVERT_ARG_HANDLE_CHECKED(Object, receiver_obj, 0); |
- CONVERT_ARG_HANDLE_CHECKED(Object, key_obj, 1); |
- |
+MaybeHandle<Object> Runtime::KeyedGetObjectProperty( |
+ Isolate* isolate, Handle<Object> receiver_obj, Handle<Object> key_obj, |
+ LanguageMode language_mode) { |
// Fast cases for getting named properties of the receiver JSObject |
// itself. |
// |
@@ -446,7 +131,7 @@ |
PropertyCell* cell = PropertyCell::cast(dictionary->ValueAt(entry)); |
if (cell->property_details().type() == DATA) { |
Object* value = cell->value(); |
- if (!value->IsTheHole()) return value; |
+ if (!value->IsTheHole()) return Handle<Object>(value, isolate); |
// If value is the hole (meaning, absent) do the general lookup. |
} |
} |
@@ -457,7 +142,7 @@ |
if ((entry != NameDictionary::kNotFound) && |
(dictionary->DetailsAt(entry).type() == DATA)) { |
Object* value = dictionary->ValueAt(entry); |
- return value; |
+ return Handle<Object>(value, isolate); |
} |
} |
} else if (key_obj->IsSmi()) { |
@@ -477,8 +162,9 @@ |
} else { |
elements_kind = FAST_ELEMENTS; |
} |
- RETURN_FAILURE_ON_EXCEPTION( |
- isolate, TransitionElements(js_object, elements_kind, isolate)); |
+ RETURN_ON_EXCEPTION( |
+ isolate, TransitionElements(js_object, elements_kind, isolate), |
+ Object); |
} |
} else { |
DCHECK(IsFastSmiOrObjectElementsKind(elements_kind) || |
@@ -488,17 +174,344 @@ |
} 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 = args.smi_at(1); |
+ int index = Handle<Smi>::cast(key_obj)->value(); |
if (index >= 0 && index < str->length()) { |
- return *GetCharAt(str, index); |
+ return GetCharAt(str, index); |
} |
} |
// Fall back to GetObjectProperty. |
+ return GetObjectProperty(isolate, receiver_obj, key_obj, language_mode); |
+} |
+ |
+ |
+MaybeHandle<Object> Runtime::SetObjectProperty(Isolate* isolate, |
+ Handle<Object> object, |
+ Handle<Object> key, |
+ Handle<Object> value, |
+ LanguageMode language_mode) { |
+ if (object->IsUndefined() || object->IsNull()) { |
+ THROW_NEW_ERROR( |
+ isolate, |
+ NewTypeError(MessageTemplate::kNonObjectPropertyStore, key, object), |
+ Object); |
+ } |
+ |
+ // Check if the given key is an array index. |
+ uint32_t index = 0; |
+ if (key->ToArrayIndex(&index)) { |
+ // TODO(verwaest): Support other objects as well. |
+ if (!object->IsJSReceiver()) return value; |
+ return JSReceiver::SetElement(Handle<JSReceiver>::cast(object), index, |
+ value, language_mode); |
+ } |
+ |
+ Handle<Name> name; |
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, name, ToName(isolate, key), Object); |
+ |
+ LookupIterator it = LookupIterator::PropertyOrElement(isolate, object, name); |
+ // TODO(verwaest): Support other objects as well. |
+ if (it.IsElement() && !object->IsJSReceiver()) return value; |
+ return Object::SetProperty(&it, value, language_mode, |
+ Object::MAY_BE_STORE_FROM_KEYED); |
+} |
+ |
+ |
+MaybeHandle<Object> Runtime::GetPrototype(Isolate* isolate, |
+ Handle<Object> obj) { |
+ // We don't expect access checks to be needed on JSProxy objects. |
+ DCHECK(!obj->IsAccessCheckNeeded() || obj->IsJSObject()); |
+ PrototypeIterator iter(isolate, obj, PrototypeIterator::START_AT_RECEIVER); |
+ do { |
+ if (PrototypeIterator::GetCurrent(iter)->IsAccessCheckNeeded() && |
+ !isolate->MayAccess( |
+ Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)))) { |
+ isolate->ReportFailedAccessCheck( |
+ Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter))); |
+ RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); |
+ return isolate->factory()->undefined_value(); |
+ } |
+ iter.AdvanceIgnoringProxies(); |
+ if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) { |
+ return PrototypeIterator::GetCurrent(iter); |
+ } |
+ } while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)); |
+ return PrototypeIterator::GetCurrent(iter); |
+} |
+ |
+ |
+RUNTIME_FUNCTION(Runtime_GetPrototype) { |
+ HandleScope scope(isolate); |
+ DCHECK(args.length() == 1); |
+ CONVERT_ARG_HANDLE_CHECKED(Object, obj, 0); |
+ Handle<Object> result; |
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, |
+ Runtime::GetPrototype(isolate, obj)); |
+ return *result; |
+} |
+ |
+ |
+RUNTIME_FUNCTION(Runtime_InternalSetPrototype) { |
+ HandleScope scope(isolate); |
+ DCHECK(args.length() == 2); |
+ CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); |
+ CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1); |
+ DCHECK(!obj->IsAccessCheckNeeded()); |
+ DCHECK(!obj->map()->is_observed()); |
+ Handle<Object> result; |
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
+ isolate, result, JSObject::SetPrototype(obj, prototype, false)); |
+ return *result; |
+} |
+ |
+ |
+RUNTIME_FUNCTION(Runtime_SetPrototype) { |
+ HandleScope scope(isolate); |
+ DCHECK(args.length() == 2); |
+ CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); |
+ CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1); |
+ if (obj->IsAccessCheckNeeded() && !isolate->MayAccess(obj)) { |
+ isolate->ReportFailedAccessCheck(obj); |
+ RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); |
+ return isolate->heap()->undefined_value(); |
+ } |
+ if (obj->map()->is_observed()) { |
+ Handle<Object> old_value = |
+ Object::GetPrototypeSkipHiddenPrototypes(isolate, obj); |
+ Handle<Object> result; |
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
+ isolate, result, JSObject::SetPrototype(obj, prototype, true)); |
+ |
+ Handle<Object> new_value = |
+ Object::GetPrototypeSkipHiddenPrototypes(isolate, obj); |
+ if (!new_value->SameValue(*old_value)) { |
+ RETURN_FAILURE_ON_EXCEPTION( |
+ isolate, JSObject::EnqueueChangeRecord( |
+ obj, "setPrototype", isolate->factory()->proto_string(), |
+ old_value)); |
+ } |
+ return *result; |
+ } |
+ Handle<Object> result; |
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
+ isolate, result, JSObject::SetPrototype(obj, prototype, true)); |
+ return *result; |
+} |
+ |
+ |
+RUNTIME_FUNCTION(Runtime_IsInPrototypeChain) { |
+ HandleScope shs(isolate); |
+ DCHECK(args.length() == 2); |
+ // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8). |
+ CONVERT_ARG_HANDLE_CHECKED(Object, O, 0); |
+ CONVERT_ARG_HANDLE_CHECKED(Object, V, 1); |
+ PrototypeIterator iter(isolate, V, PrototypeIterator::START_AT_RECEIVER); |
+ while (true) { |
+ iter.AdvanceIgnoringProxies(); |
+ if (iter.IsAtEnd()) return isolate->heap()->false_value(); |
+ if (iter.IsAtEnd(O)) return isolate->heap()->true_value(); |
+ } |
+} |
+ |
+ |
+// Enumerator used as indices into the array returned from GetOwnProperty |
+enum PropertyDescriptorIndices { |
+ IS_ACCESSOR_INDEX, |
+ VALUE_INDEX, |
+ GETTER_INDEX, |
+ SETTER_INDEX, |
+ WRITABLE_INDEX, |
+ ENUMERABLE_INDEX, |
+ CONFIGURABLE_INDEX, |
+ DESCRIPTOR_SIZE |
+}; |
+ |
+ |
+MUST_USE_RESULT static MaybeHandle<Object> GetOwnProperty(Isolate* isolate, |
+ Handle<JSObject> obj, |
+ Handle<Name> name) { |
+ Heap* heap = isolate->heap(); |
+ Factory* factory = isolate->factory(); |
+ |
+ PropertyAttributes attrs; |
+ // Get attributes. |
+ LookupIterator it = LookupIterator::PropertyOrElement(isolate, obj, name, |
+ LookupIterator::HIDDEN); |
+ Maybe<PropertyAttributes> maybe = JSObject::GetPropertyAttributes(&it); |
+ |
+ if (!maybe.IsJust()) return MaybeHandle<Object>(); |
+ attrs = maybe.FromJust(); |
+ if (attrs == ABSENT) return factory->undefined_value(); |
+ |
+ DCHECK(!isolate->has_pending_exception()); |
+ Handle<FixedArray> elms = factory->NewFixedArray(DESCRIPTOR_SIZE); |
+ elms->set(ENUMERABLE_INDEX, heap->ToBoolean((attrs & DONT_ENUM) == 0)); |
+ elms->set(CONFIGURABLE_INDEX, heap->ToBoolean((attrs & DONT_DELETE) == 0)); |
+ |
+ bool is_accessor_pair = it.state() == LookupIterator::ACCESSOR && |
+ it.GetAccessors()->IsAccessorPair(); |
+ elms->set(IS_ACCESSOR_INDEX, heap->ToBoolean(is_accessor_pair)); |
+ |
+ if (is_accessor_pair) { |
+ Handle<AccessorPair> accessors = |
+ Handle<AccessorPair>::cast(it.GetAccessors()); |
+ Handle<Object> getter(accessors->GetComponent(ACCESSOR_GETTER), isolate); |
+ Handle<Object> setter(accessors->GetComponent(ACCESSOR_SETTER), isolate); |
+ elms->set(GETTER_INDEX, *getter); |
+ elms->set(SETTER_INDEX, *setter); |
+ } else { |
+ Handle<Object> value; |
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, value, Object::GetProperty(&it), |
+ Object); |
+ elms->set(WRITABLE_INDEX, heap->ToBoolean((attrs & READ_ONLY) == 0)); |
+ elms->set(VALUE_INDEX, *value); |
+ } |
+ |
+ return factory->NewJSArrayWithElements(elms); |
+} |
+ |
+ |
+// Returns an array with the property description: |
+// if args[1] is not a property on args[0] |
+// returns undefined |
+// if args[1] is a data property on args[0] |
+// [false, value, Writeable, Enumerable, Configurable] |
+// if args[1] is an accessor on args[0] |
+// [true, GetFunction, SetFunction, Enumerable, Configurable] |
+RUNTIME_FUNCTION(Runtime_GetOwnProperty) { |
+ HandleScope scope(isolate); |
+ DCHECK(args.length() == 2); |
+ CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); |
+ CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); |
+ Handle<Object> result; |
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, |
+ GetOwnProperty(isolate, obj, name)); |
+ return *result; |
+} |
+ |
+ |
+RUNTIME_FUNCTION(Runtime_PreventExtensions) { |
+ HandleScope scope(isolate); |
+ DCHECK(args.length() == 1); |
+ CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); |
+ Handle<Object> result; |
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, |
+ JSObject::PreventExtensions(obj)); |
+ return *result; |
+} |
+ |
+ |
+RUNTIME_FUNCTION(Runtime_IsExtensible) { |
+ SealHandleScope shs(isolate); |
+ DCHECK(args.length() == 1); |
+ CONVERT_ARG_CHECKED(JSObject, obj, 0); |
+ return isolate->heap()->ToBoolean(obj->IsExtensible()); |
+} |
+ |
+ |
+RUNTIME_FUNCTION(Runtime_DisableAccessChecks) { |
+ HandleScope scope(isolate); |
+ DCHECK(args.length() == 1); |
+ CONVERT_ARG_HANDLE_CHECKED(HeapObject, object, 0); |
+ Handle<Map> old_map(object->map()); |
+ bool needs_access_checks = old_map->is_access_check_needed(); |
+ if (needs_access_checks) { |
+ // Copy map so it won't interfere constructor's initial map. |
+ Handle<Map> new_map = Map::Copy(old_map, "DisableAccessChecks"); |
+ new_map->set_is_access_check_needed(false); |
+ JSObject::MigrateToMap(Handle<JSObject>::cast(object), new_map); |
+ } |
+ return isolate->heap()->ToBoolean(needs_access_checks); |
+} |
+ |
+ |
+RUNTIME_FUNCTION(Runtime_EnableAccessChecks) { |
+ HandleScope scope(isolate); |
+ DCHECK(args.length() == 1); |
+ CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); |
+ Handle<Map> old_map(object->map()); |
+ RUNTIME_ASSERT(!old_map->is_access_check_needed()); |
+ // Copy map so it won't interfere constructor's initial map. |
+ Handle<Map> new_map = Map::Copy(old_map, "EnableAccessChecks"); |
+ new_map->set_is_access_check_needed(true); |
+ JSObject::MigrateToMap(object, new_map); |
+ return isolate->heap()->undefined_value(); |
+} |
+ |
+ |
+RUNTIME_FUNCTION(Runtime_OptimizeObjectForAddingMultipleProperties) { |
+ HandleScope scope(isolate); |
+ DCHECK(args.length() == 2); |
+ CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); |
+ CONVERT_SMI_ARG_CHECKED(properties, 1); |
+ // Conservative upper limit to prevent fuzz tests from going OOM. |
+ RUNTIME_ASSERT(properties <= 100000); |
+ if (object->HasFastProperties() && !object->IsJSGlobalProxy()) { |
+ JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties, |
+ "OptimizeForAdding"); |
+ } |
+ return *object; |
+} |
+ |
+ |
+RUNTIME_FUNCTION(Runtime_ObjectFreeze) { |
+ HandleScope scope(isolate); |
+ DCHECK(args.length() == 1); |
+ CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); |
+ |
+ // %ObjectFreeze is a fast path and these cases are handled elsewhere. |
+ RUNTIME_ASSERT(!object->HasSloppyArgumentsElements() && |
+ !object->map()->is_observed() && !object->IsJSProxy()); |
+ |
+ Handle<Object> result; |
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, JSObject::Freeze(object)); |
+ return *result; |
+} |
+ |
+ |
+RUNTIME_FUNCTION(Runtime_ObjectSeal) { |
+ HandleScope scope(isolate); |
+ DCHECK(args.length() == 1); |
+ CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); |
+ |
+ // %ObjectSeal is a fast path and these cases are handled elsewhere. |
+ RUNTIME_ASSERT(!object->HasSloppyArgumentsElements() && |
+ !object->map()->is_observed() && !object->IsJSProxy()); |
+ |
+ Handle<Object> result; |
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, JSObject::Seal(object)); |
+ return *result; |
+} |
+ |
+ |
+RUNTIME_FUNCTION(Runtime_GetProperty) { |
+ HandleScope scope(isolate); |
+ DCHECK(args.length() == 3); |
+ |
+ CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); |
+ CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); |
+ CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 2); |
+ |
Handle<Object> result; |
ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
isolate, result, |
- Runtime::GetObjectProperty(isolate, receiver_obj, key_obj)); |
+ Runtime::GetObjectProperty(isolate, object, key, language_mode)); |
+ return *result; |
+} |
+ |
+ |
+RUNTIME_FUNCTION(Runtime_KeyedGetProperty) { |
+ HandleScope scope(isolate); |
+ DCHECK(args.length() == 3); |
+ |
+ CONVERT_ARG_HANDLE_CHECKED(Object, receiver_obj, 0); |
+ CONVERT_ARG_HANDLE_CHECKED(Object, key_obj, 1); |
+ CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 2); |
+ |
+ Handle<Object> result; |
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
+ isolate, result, Runtime::KeyedGetObjectProperty(isolate, receiver_obj, |
+ key_obj, language_mode)); |
return *result; |
} |