Index: src/objects.cc |
diff --git a/src/objects.cc b/src/objects.cc |
index ea3649198e1e77b8e1adbfdb4c10f2e000329816..cb47e5766d182758868db7e37ffa2604cb274349 100644 |
--- a/src/objects.cc |
+++ b/src/objects.cc |
@@ -116,17 +116,6 @@ |
return result; |
} |
-// ES6 section 9.2.1.2, OrdinaryCallBindThis for sloppy callee. |
-// static |
-MaybeHandle<JSReceiver> Object::ConvertReceiver(Isolate* isolate, |
- Handle<Object> object) { |
- if (object->IsJSReceiver()) return Handle<JSReceiver>::cast(object); |
- if (*object == isolate->heap()->null_value() || |
- *object == isolate->heap()->undefined_value()) { |
- return isolate->global_proxy(); |
- } |
- return Object::ToObject(isolate, object); |
-} |
// static |
MaybeHandle<Object> Object::ToNumber(Handle<Object> input) { |
@@ -6146,9 +6135,7 @@ |
// ES6 7.1.14 |
-// static |
-MaybeHandle<Object> Object::ToPropertyKey(Isolate* isolate, |
- Handle<Object> value) { |
+MaybeHandle<Object> ToPropertyKey(Isolate* isolate, Handle<Object> value) { |
// 1. Let key be ToPrimitive(argument, hint String). |
MaybeHandle<Object> maybe_key = |
Object::ToPrimitive(value, ToPrimitiveHint::kString); |
@@ -8931,6 +8918,53 @@ |
return object; |
} |
+ |
+ |
+MaybeHandle<Object> JSObject::GetAccessor(Handle<JSObject> object, |
+ Handle<Name> name, |
+ AccessorComponent component) { |
+ Isolate* isolate = object->GetIsolate(); |
+ |
+ // Make sure that the top context does not change when doing callbacks or |
+ // interceptor calls. |
+ AssertNoContextChange ncc(isolate); |
+ |
+ LookupIterator it = LookupIterator::PropertyOrElement( |
+ isolate, object, name, LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR); |
+ |
+ for (; it.IsFound(); it.Next()) { |
+ switch (it.state()) { |
+ case LookupIterator::INTERCEPTOR: |
+ case LookupIterator::NOT_FOUND: |
+ case LookupIterator::TRANSITION: |
+ UNREACHABLE(); |
+ |
+ case LookupIterator::ACCESS_CHECK: |
+ if (it.HasAccess()) continue; |
+ isolate->ReportFailedAccessCheck(it.GetHolder<JSObject>()); |
+ RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); |
+ return isolate->factory()->undefined_value(); |
+ |
+ case LookupIterator::JSPROXY: |
+ return isolate->factory()->undefined_value(); |
+ |
+ case LookupIterator::INTEGER_INDEXED_EXOTIC: |
+ return isolate->factory()->undefined_value(); |
+ case LookupIterator::DATA: |
+ continue; |
+ case LookupIterator::ACCESSOR: { |
+ Handle<Object> maybe_pair = it.GetAccessors(); |
+ if (maybe_pair->IsAccessorPair()) { |
+ return AccessorPair::GetComponent( |
+ Handle<AccessorPair>::cast(maybe_pair), component); |
+ } |
+ } |
+ } |
+ } |
+ |
+ return isolate->factory()->undefined_value(); |
+} |
+ |
Object* JSObject::SlowReverseLookup(Object* value) { |
if (HasFastProperties()) { |
@@ -15748,12 +15782,159 @@ |
return is_api_object; |
} |
+int JSObject::NumberOfOwnElements(PropertyFilter filter) { |
+ // Fast case for objects with no elements. |
+ if (!IsJSValue() && HasFastElements()) { |
+ uint32_t length = |
+ IsJSArray() |
+ ? static_cast<uint32_t>( |
+ Smi::cast(JSArray::cast(this)->length())->value()) |
+ : static_cast<uint32_t>(FixedArrayBase::cast(elements())->length()); |
+ if (length == 0) return 0; |
+ } |
+ // Compute the number of enumerable elements. |
+ return GetOwnElementKeys(NULL, filter); |
+} |
+ |
void JSObject::CollectOwnElementKeys(Handle<JSObject> object, |
KeyAccumulator* keys, |
PropertyFilter filter) { |
if (filter & SKIP_STRINGS) return; |
ElementsAccessor* accessor = object->GetElementsAccessor(); |
accessor->CollectElementIndices(object, keys, kMaxUInt32, filter, 0); |
+} |
+ |
+ |
+int JSObject::GetOwnElementKeys(FixedArray* storage, PropertyFilter filter) { |
+ int counter = 0; |
+ |
+ // If this is a String wrapper, add the string indices first, |
+ // as they're guaranteed to precede the elements in numerical order |
+ // and ascending order is required by ECMA-262, 6th, 9.1.12. |
+ if (IsJSValue()) { |
+ Object* val = JSValue::cast(this)->value(); |
+ if (val->IsString()) { |
+ String* str = String::cast(val); |
+ if (storage) { |
+ for (int i = 0; i < str->length(); i++) { |
+ storage->set(counter + i, Smi::FromInt(i)); |
+ } |
+ } |
+ counter += str->length(); |
+ } |
+ } |
+ |
+ switch (GetElementsKind()) { |
+ case FAST_SMI_ELEMENTS: |
+ case FAST_ELEMENTS: |
+ case FAST_HOLEY_SMI_ELEMENTS: |
+ case FAST_HOLEY_ELEMENTS: |
+ case FAST_STRING_WRAPPER_ELEMENTS: { |
+ int length = IsJSArray() ? |
+ Smi::cast(JSArray::cast(this)->length())->value() : |
+ FixedArray::cast(elements())->length(); |
+ for (int i = 0; i < length; i++) { |
+ if (!FixedArray::cast(elements())->get(i)->IsTheHole()) { |
+ if (storage != NULL) { |
+ storage->set(counter, Smi::FromInt(i)); |
+ } |
+ counter++; |
+ } |
+ } |
+ DCHECK(!storage || storage->length() >= counter); |
+ break; |
+ } |
+ case FAST_DOUBLE_ELEMENTS: |
+ case FAST_HOLEY_DOUBLE_ELEMENTS: { |
+ int length = IsJSArray() ? |
+ Smi::cast(JSArray::cast(this)->length())->value() : |
+ FixedArrayBase::cast(elements())->length(); |
+ for (int i = 0; i < length; i++) { |
+ if (!FixedDoubleArray::cast(elements())->is_the_hole(i)) { |
+ if (storage != NULL) { |
+ storage->set(counter, Smi::FromInt(i)); |
+ } |
+ counter++; |
+ } |
+ } |
+ DCHECK(!storage || storage->length() >= counter); |
+ break; |
+ } |
+ |
+#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ |
+ case TYPE##_ELEMENTS: \ |
+ |
+ TYPED_ARRAYS(TYPED_ARRAY_CASE) |
+#undef TYPED_ARRAY_CASE |
+ { |
+ int length = FixedArrayBase::cast(elements())->length(); |
+ while (counter < length) { |
+ if (storage != NULL) { |
+ storage->set(counter, Smi::FromInt(counter)); |
+ } |
+ counter++; |
+ } |
+ DCHECK(!storage || storage->length() >= counter); |
+ break; |
+ } |
+ |
+ case DICTIONARY_ELEMENTS: |
+ case SLOW_STRING_WRAPPER_ELEMENTS: { |
+ if (storage != NULL) { |
+ element_dictionary()->CopyKeysTo(storage, counter, filter, |
+ SeededNumberDictionary::SORTED); |
+ } |
+ counter += element_dictionary()->NumberOfElementsFilterAttributes(filter); |
+ break; |
+ } |
+ case FAST_SLOPPY_ARGUMENTS_ELEMENTS: |
+ case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: { |
+ FixedArray* parameter_map = FixedArray::cast(elements()); |
+ int mapped_length = parameter_map->length() - 2; |
+ FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); |
+ if (arguments->IsDictionary()) { |
+ // Copy the keys from arguments first, because Dictionary::CopyKeysTo |
+ // will insert in storage starting at index 0. |
+ SeededNumberDictionary* dictionary = |
+ SeededNumberDictionary::cast(arguments); |
+ if (storage != NULL) { |
+ dictionary->CopyKeysTo(storage, counter, filter, |
+ SeededNumberDictionary::UNSORTED); |
+ } |
+ counter += dictionary->NumberOfElementsFilterAttributes(filter); |
+ for (int i = 0; i < mapped_length; ++i) { |
+ if (!parameter_map->get(i + 2)->IsTheHole()) { |
+ if (storage != NULL) storage->set(counter, Smi::FromInt(i)); |
+ ++counter; |
+ } |
+ } |
+ if (storage != NULL) storage->SortPairs(storage, counter); |
+ |
+ } else { |
+ int backing_length = arguments->length(); |
+ int i = 0; |
+ for (; i < mapped_length; ++i) { |
+ if (!parameter_map->get(i + 2)->IsTheHole()) { |
+ if (storage != NULL) storage->set(counter, Smi::FromInt(i)); |
+ ++counter; |
+ } else if (i < backing_length && !arguments->get(i)->IsTheHole()) { |
+ if (storage != NULL) storage->set(counter, Smi::FromInt(i)); |
+ ++counter; |
+ } |
+ } |
+ for (; i < backing_length; ++i) { |
+ if (storage != NULL) storage->set(counter, Smi::FromInt(i)); |
+ ++counter; |
+ } |
+ } |
+ break; |
+ } |
+ case NO_ELEMENTS: |
+ break; |
+ } |
+ |
+ DCHECK(!storage || storage->length() == counter); |
+ return counter; |
} |
@@ -17600,6 +17781,30 @@ |
} |
} |
+ |
+template <typename Derived, typename Shape, typename Key> |
+int Dictionary<Derived, Shape, Key>::CopyKeysTo( |
+ FixedArray* storage, int index, PropertyFilter filter, |
+ typename Dictionary<Derived, Shape, Key>::SortMode sort_mode) { |
+ DCHECK(storage->length() >= NumberOfElementsFilterAttributes(filter)); |
+ int start_index = index; |
+ int capacity = this->Capacity(); |
+ for (int i = 0; i < capacity; i++) { |
+ Object* k = this->KeyAt(i); |
+ if (!this->IsKey(k) || k->FilterKey(filter)) continue; |
+ if (this->IsDeleted(i)) continue; |
+ PropertyDetails details = this->DetailsAt(i); |
+ PropertyAttributes attr = details.attributes(); |
+ if ((attr & filter) != 0) continue; |
+ storage->set(index++, k); |
+ } |
+ if (sort_mode == Dictionary::SORTED) { |
+ storage->SortPairs(storage, index); |
+ } |
+ DCHECK(storage->length() >= index); |
+ return index - start_index; |
+} |
+ |
template <typename Derived, typename Shape, typename Key> |
void Dictionary<Derived, Shape, Key>::CollectKeysTo( |
Handle<Dictionary<Derived, Shape, Key> > dictionary, KeyAccumulator* keys, |