| 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));
|
| }
|
| }
|
|
|
|
|