Index: src/runtime.cc |
diff --git a/src/runtime.cc b/src/runtime.cc |
index 38f77d07137eb06acec574d67d409cdfca073cd1..26293e5c6a06aa71c3200653d1fc9af6615cd6cb 100644 |
--- a/src/runtime.cc |
+++ b/src/runtime.cc |
@@ -9540,6 +9540,15 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) { |
} |
+static Handle<Object> NewSingleInterval(Isolate* isolate, uint32_t length) { |
+ Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2); |
+ // -1 means start of array. |
+ single_interval->set(0, Smi::FromInt(-1)); |
+ single_interval->set(1, *isolate->factory()->NewNumberFromUint(length)); |
+ return isolate->factory()->NewJSArrayWithElements(single_interval); |
+} |
+ |
+ |
// Returns an array that tells you where in the [0, length) interval an array |
// might have elements. Can either return keys (positive integers) or |
// intervals (pair of a negative integer (-start-1) followed by a |
@@ -9551,37 +9560,34 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) { |
CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0); |
CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]); |
if (array->elements()->IsDictionary()) { |
- // Create an array and get all the keys into it, then remove all the |
- // keys that are not integers in the range 0 to length-1. |
- bool threw = false; |
- Handle<FixedArray> keys = |
- GetKeysInFixedArrayFor(array, INCLUDE_PROTOS, &threw); |
- if (threw) return Failure::Exception(); |
- |
- int keys_length = keys->length(); |
- for (int i = 0; i < keys_length; i++) { |
- Object* key = keys->get(i); |
- uint32_t index = 0; |
- if (!key->ToArrayIndex(&index) || index >= length) { |
- // Zap invalid keys. |
- keys->set_undefined(i); |
+ Handle<FixedArray> keys = isolate->factory()->empty_fixed_array(); |
+ for (Handle<Object> p = array; |
+ !p->IsNull(); |
+ p = Handle<Object>(p->GetPrototype(isolate), isolate)) { |
+ if (p->IsJSProxy() || JSObject::cast(*p)->HasIndexedInterceptor()) { |
+ // Bail out if we find a proxy or interceptor, likely not worth |
+ // collecting keys in that case. |
+ return *NewSingleInterval(isolate, length); |
} |
+ Handle<JSObject> current = Handle<JSObject>::cast(p); |
+ Handle<FixedArray> current_keys = |
+ isolate->factory()->NewFixedArray( |
+ current->NumberOfLocalElements(NONE)); |
+ current->GetLocalElementKeys(*current_keys, NONE); |
+ keys = UnionOfKeys(keys, current_keys); |
+ } |
+ // Erase any keys >= length. |
+ // TODO(adamk): Remove this step when the contract of %GetArrayKeys |
+ // is changed to let this happen on the JS side. |
+ for (int i = 0; i < keys->length(); i++) { |
+ if (NumberToUint32(keys->get(i)) >= length) keys->set_undefined(i); |
} |
return *isolate->factory()->NewJSArrayWithElements(keys); |
} else { |
ASSERT(array->HasFastSmiOrObjectElements() || |
array->HasFastDoubleElements()); |
- Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2); |
- // -1 means start of array. |
- single_interval->set(0, Smi::FromInt(-1)); |
- FixedArrayBase* elements = FixedArrayBase::cast(array->elements()); |
- uint32_t actual_length = |
- static_cast<uint32_t>(elements->length()); |
- uint32_t min_length = actual_length < length ? actual_length : length; |
- Handle<Object> length_object = |
- isolate->factory()->NewNumber(static_cast<double>(min_length)); |
- single_interval->set(1, *length_object); |
- return *isolate->factory()->NewJSArrayWithElements(single_interval); |
+ uint32_t actual_length = static_cast<uint32_t>(array->elements()->length()); |
+ return *NewSingleInterval(isolate, Min(actual_length, length)); |
} |
} |