Commit c7854ed9 authored by Camillo Bruni's avatar Camillo Bruni Committed by Commit Bot

[builtins] Array.prototype.sort bug

Bug: chromium:743154
Change-Id: Id5b2a91a9242326b1dafccc4aeb95e18fb0fc8d8
Reviewed-on: https://chromium-review.googlesource.com/580928Reviewed-by: 's avatarIgor Sheludko <ishell@chromium.org>
Commit-Queue: Camillo Bruni <cbruni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46873}
parent 8c9b0b50
...@@ -51,8 +51,7 @@ namespace { ...@@ -51,8 +51,7 @@ namespace {
// As PrepareElementsForSort, but only on objects where elements is // As PrepareElementsForSort, but only on objects where elements is
// a dictionary, and it will stay a dictionary. Collates undefined and // a dictionary, and it will stay a dictionary. Collates undefined and
// unexisting elements below limit from position zero of the elements. // unexisting elements below limit from position zero of the elements.
Handle<Object> PrepareSlowElementsForSort(Handle<JSObject> object, Object* PrepareSlowElementsForSort(Handle<JSObject> object, uint32_t limit) {
uint32_t limit) {
DCHECK(object->HasDictionaryElements()); DCHECK(object->HasDictionaryElements());
Isolate* isolate = object->GetIsolate(); Isolate* isolate = object->GetIsolate();
// Must stay in dictionary mode, either because of requires_slow_elements, // Must stay in dictionary mode, either because of requires_slow_elements,
...@@ -66,10 +65,9 @@ Handle<Object> PrepareSlowElementsForSort(Handle<JSObject> object, ...@@ -66,10 +65,9 @@ Handle<Object> PrepareSlowElementsForSort(Handle<JSObject> object,
uint32_t undefs = 0; uint32_t undefs = 0;
uint32_t max_key = 0; uint32_t max_key = 0;
int capacity = dict->Capacity(); int capacity = dict->Capacity();
Handle<Smi> bailout(Smi::FromInt(-1), isolate); Smi* bailout = Smi::FromInt(-1);
// Entry to the new dictionary does not cause it to grow, as we have // Entry to the new dictionary does not cause it to grow, as we have
// allocated one that is large enough for all entries. // allocated one that is large enough for all entries.
DisallowHeapAllocation no_gc;
for (int i = 0; i < capacity; i++) { for (int i = 0; i < capacity; i++) {
Object* k; Object* k;
if (!dict->ToKey(isolate, i, &k)) continue; if (!dict->ToKey(isolate, i, &k)) continue;
...@@ -90,24 +88,18 @@ Handle<Object> PrepareSlowElementsForSort(Handle<JSObject> object, ...@@ -90,24 +88,18 @@ Handle<Object> PrepareSlowElementsForSort(Handle<JSObject> object,
if (key < limit) { if (key < limit) {
if (value->IsUndefined(isolate)) { if (value->IsUndefined(isolate)) {
undefs++; undefs++;
} else if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
// Adding an entry with the key beyond smi-range requires
// allocation. Bailout.
return bailout;
} else { } else {
Handle<Object> result = Handle<Object> result =
SeededNumberDictionary::Add(new_dict, pos, value, details); SeededNumberDictionary::Add(new_dict, pos, value, details);
// Add should not grow the dictionary since we allocated the right size.
DCHECK(result.is_identical_to(new_dict)); DCHECK(result.is_identical_to(new_dict));
USE(result); USE(result);
pos++; pos++;
} }
} else if (key > static_cast<uint32_t>(Smi::kMaxValue)) {
// Adding an entry with the key beyond smi-range requires
// allocation. Bailout.
return bailout;
} else { } else {
Handle<Object> result = Handle<Object> result =
SeededNumberDictionary::Add(new_dict, key, value, details); SeededNumberDictionary::Add(new_dict, key, value, details);
// Add should not grow the dictionary since we allocated the right size.
DCHECK(result.is_identical_to(new_dict)); DCHECK(result.is_identical_to(new_dict));
USE(result); USE(result);
max_key = Max(max_key, key); max_key = Max(max_key, key);
...@@ -125,6 +117,7 @@ Handle<Object> PrepareSlowElementsForSort(Handle<JSObject> object, ...@@ -125,6 +117,7 @@ Handle<Object> PrepareSlowElementsForSort(Handle<JSObject> object,
HandleScope scope(isolate); HandleScope scope(isolate);
Handle<Object> result = SeededNumberDictionary::Add( Handle<Object> result = SeededNumberDictionary::Add(
new_dict, pos, isolate->factory()->undefined_value(), no_details); new_dict, pos, isolate->factory()->undefined_value(), no_details);
// Add should not grow the dictionary since we allocated the right size.
DCHECK(result.is_identical_to(new_dict)); DCHECK(result.is_identical_to(new_dict));
USE(result); USE(result);
pos++; pos++;
...@@ -136,23 +129,21 @@ Handle<Object> PrepareSlowElementsForSort(Handle<JSObject> object, ...@@ -136,23 +129,21 @@ Handle<Object> PrepareSlowElementsForSort(Handle<JSObject> object,
new_dict->UpdateMaxNumberKey(max_key, object); new_dict->UpdateMaxNumberKey(max_key, object);
JSObject::ValidateElements(*object); JSObject::ValidateElements(*object);
AllowHeapAllocation allocate_return_value; return *isolate->factory()->NewNumberFromUint(result);
return isolate->factory()->NewNumberFromUint(result);
} }
// Collects all defined (non-hole) and non-undefined (array) elements at the // Collects all defined (non-hole) and non-undefined (array) elements at the
// start of the elements array. If the object is in dictionary mode, it is // start of the elements array. If the object is in dictionary mode, it is
// converted to fast elements mode. Undefined values are placed after // converted to fast elements mode. Undefined values are placed after
// non-undefined values. Returns the number of non-undefined values. // non-undefined values. Returns the number of non-undefined values.
Handle<Object> PrepareElementsForSort(Handle<JSObject> object, uint32_t limit) { Object* PrepareElementsForSort(Handle<JSObject> object, uint32_t limit) {
Isolate* isolate = object->GetIsolate(); Isolate* isolate = object->GetIsolate();
if (object->HasSloppyArgumentsElements() || !object->map()->is_extensible()) { if (object->HasSloppyArgumentsElements() || !object->map()->is_extensible()) {
return handle(Smi::FromInt(-1), isolate); return Smi::FromInt(-1);
} }
if (object->HasStringWrapperElements()) { if (object->HasStringWrapperElements()) {
int len = String::cast(Handle<JSValue>::cast(object)->value())->length(); int len = String::cast(Handle<JSValue>::cast(object)->value())->length();
return handle(Smi::FromInt(len), isolate); return Smi::FromInt(len);
} }
JSObject::ValidateElements(*object); JSObject::ValidateElements(*object);
...@@ -178,9 +169,7 @@ Handle<Object> PrepareElementsForSort(Handle<JSObject> object, uint32_t limit) { ...@@ -178,9 +169,7 @@ Handle<Object> PrepareElementsForSort(Handle<JSObject> object, uint32_t limit) {
JSObject::ValidateElements(*object); JSObject::ValidateElements(*object);
} else if (object->HasFixedTypedArrayElements()) { } else if (object->HasFixedTypedArrayElements()) {
// Typed arrays cannot have holes or undefined elements. // Typed arrays cannot have holes or undefined elements.
return handle( return Smi::FromInt(FixedArrayBase::cast(object->elements())->length());
Smi::FromInt(FixedArrayBase::cast(object->elements())->length()),
isolate);
} else if (!object->HasDoubleElements()) { } else if (!object->HasDoubleElements()) {
JSObject::EnsureWritableFastElements(object); JSObject::EnsureWritableFastElements(object);
} }
...@@ -195,7 +184,7 @@ Handle<Object> PrepareElementsForSort(Handle<JSObject> object, uint32_t limit) { ...@@ -195,7 +184,7 @@ Handle<Object> PrepareElementsForSort(Handle<JSObject> object, uint32_t limit) {
limit = elements_length; limit = elements_length;
} }
if (limit == 0) { if (limit == 0) {
return handle(Smi::kZero, isolate); return Smi::kZero;
} }
uint32_t result = 0; uint32_t result = 0;
...@@ -272,7 +261,7 @@ Handle<Object> PrepareElementsForSort(Handle<JSObject> object, uint32_t limit) { ...@@ -272,7 +261,7 @@ Handle<Object> PrepareElementsForSort(Handle<JSObject> object, uint32_t limit) {
} }
} }
return isolate->factory()->NewNumberFromUint(result); return *isolate->factory()->NewNumberFromUint(result);
} }
} // namespace } // namespace
...@@ -289,7 +278,7 @@ RUNTIME_FUNCTION(Runtime_RemoveArrayHoles) { ...@@ -289,7 +278,7 @@ RUNTIME_FUNCTION(Runtime_RemoveArrayHoles) {
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0); CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]); CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
if (object->IsJSProxy()) return Smi::FromInt(-1); if (object->IsJSProxy()) return Smi::FromInt(-1);
return *PrepareElementsForSort(Handle<JSObject>::cast(object), limit); return PrepareElementsForSort(Handle<JSObject>::cast(object), limit);
} }
......
// Copyright 2017 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.
Object.prototype[1] = 1.5;
var v = { length: 12, [1073741824]: 0 };
assertEquals(['1073741824', 'length'], Object.keys(v));
assertEquals(undefined, v[0]);
assertEquals(1.5, v[1]);
assertEquals(0, v[1073741824]);
// Properly handle out of range HeapNumber keys on 32bit platforms.
Array.prototype.sort.call(v);
assertEquals(['0', '1073741824', 'length'], Object.keys(v));
assertEquals(1.5, v[0]);
assertEquals(1.5, v[1]);
assertEquals(0, v[1073741824]);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment