Fix setting array length to be ES5 conform.

This also refactors the way we set the length of an arrays' backing
store to use the new elements accessor interface. The actual fix is in
DictionaryElementsAccessor::SetLengthWithoutNormalize() where we first
search for non-deletable elements according to ES5 section 15.4.5.2
specifications.

Snippet from the specification: Attempting to set the length property of
an Array object to a value that is numerically less than or equal to the
largest numeric property name of an existing array indexed non-deletable
property of the array will result in the length being set to a numeric
value that is one greater than that largest numeric property name.

R=danno@chromium.org
TEST=test262/15.4.4.??-7-b-16

Review URL: http://codereview.chromium.org/8372064

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@9911 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 9b968b7d
......@@ -31,6 +31,30 @@
#include "elements.h"
#include "utils.h"
// Each concrete ElementsAccessor can handle exactly one ElementsKind,
// several abstract ElementsAccessor classes are used to allow sharing
// common code.
//
// Inheritance hierarchy:
// - ElementsAccessorBase (abstract)
// - FastElementsAccessor (abstract)
// - FastObjectElementsAccessor
// - FastDoubleElementsAccessor
// - ExternalElementsAccessor (abstract)
// - ExternalByteElementsAccessor
// - ExternalUnsignedByteElementsAccessor
// - ExternalShortElementsAccessor
// - ExternalUnsignedShortElementsAccessor
// - ExternalIntElementsAccessor
// - ExternalUnsignedIntElementsAccessor
// - ExternalFloatElementsAccessor
// - ExternalDoubleElementsAccessor
// - PixelElementsAccessor
// - DictionaryElementsAccessor
// - NonStrictArgumentsElementsAccessor
namespace v8 {
namespace internal {
......@@ -38,7 +62,7 @@ namespace internal {
ElementsAccessor** ElementsAccessor::elements_accessors_;
bool HasKey(FixedArray* array, Object* key) {
static bool HasKey(FixedArray* array, Object* key) {
int len0 = array->length();
for (int i = 0; i < len0; i++) {
Object* element = array->get(i);
......@@ -52,6 +76,14 @@ bool HasKey(FixedArray* array, Object* key) {
}
static Failure* ThrowArrayLengthRangeError(Heap* heap) {
HandleScope scope(heap->isolate());
return heap->isolate()->Throw(
*heap->isolate()->factory()->NewRangeError("invalid_array_length",
HandleVector<Object>(NULL, 0)));
}
// Base class for element handler implementations. Contains the
// the common logic for objects with different ElementsKinds.
// Subclasses must specialize method for which the element
......@@ -91,6 +123,17 @@ class ElementsAccessorBase : public ElementsAccessor {
return backing_store->GetHeap()->the_hole_value();
}
virtual MaybeObject* SetLength(JSObject* obj,
Object* length) {
ASSERT(obj->IsJSArray());
return ElementsAccessorSubclass::SetLength(
BackingStoreClass::cast(obj->elements()), obj, length);
}
static MaybeObject* SetLength(BackingStoreClass* backing_store,
JSObject* obj,
Object* length);
virtual MaybeObject* Delete(JSObject* obj,
uint32_t key,
JSReceiver::DeleteMode mode) = 0;
......@@ -222,8 +265,70 @@ class ElementsAccessorBase : public ElementsAccessor {
};
// Super class for all fast element arrays.
template<typename FastElementsAccessorSubclass,
typename BackingStore,
int ElementSize>
class FastElementsAccessor
: public ElementsAccessorBase<FastElementsAccessor, FixedArray> {
: public ElementsAccessorBase<FastElementsAccessorSubclass, BackingStore> {
protected:
friend class ElementsAccessorBase<FastElementsAccessorSubclass, BackingStore>;
// Adjusts the length of the fast backing store or returns the new length or
// undefined in case conversion to a slow backing store should be performed.
static MaybeObject* SetLengthWithoutNormalize(BackingStore* backing_store,
JSArray* array,
Object* length_object,
uint32_t length) {
uint32_t old_capacity = backing_store->length();
// Check whether the backing store should be shrunk.
if (length <= old_capacity) {
if (array->HasFastTypeElements()) {
MaybeObject* maybe_obj = array->EnsureWritableFastElements();
if (!maybe_obj->To(&backing_store)) return maybe_obj;
}
if (2 * length <= old_capacity) {
// If more than half the elements won't be used, trim the array.
if (length == 0) {
array->initialize_elements();
} else {
backing_store->set_length(length);
Address filler_start = backing_store->address() +
BackingStore::OffsetOfElementAt(length);
int filler_size = (old_capacity - length) * ElementSize;
array->GetHeap()->CreateFillerObjectAt(filler_start, filler_size);
}
} else {
// Otherwise, fill the unused tail with holes.
int old_length = FastD2I(array->length()->Number());
for (int i = length; i < old_length; i++) {
backing_store->set_the_hole(i);
}
}
return length_object;
}
// Check whether the backing store should be expanded.
uint32_t min = JSObject::NewElementsCapacity(old_capacity);
uint32_t new_capacity = length > min ? length : min;
if (!array->ShouldConvertToSlowElements(new_capacity)) {
MaybeObject* result = FastElementsAccessorSubclass::
SetFastElementsCapacityAndLength(array, new_capacity, length);
if (result->IsFailure()) return result;
return length_object;
}
// Request conversion to slow elements.
return array->GetHeap()->undefined_value();
}
};
class FastObjectElementsAccessor
: public FastElementsAccessor<FastObjectElementsAccessor,
FixedArray,
kPointerSize> {
public:
static MaybeObject* DeleteCommon(JSObject* obj,
uint32_t key) {
......@@ -272,6 +377,22 @@ class FastElementsAccessor
}
protected:
friend class FastElementsAccessor<FastObjectElementsAccessor,
FixedArray,
kPointerSize>;
static MaybeObject* SetFastElementsCapacityAndLength(JSObject* obj,
uint32_t capacity,
uint32_t length) {
JSObject::SetFastElementsCapacityMode set_capacity_mode =
obj->HasFastSmiOnlyElements()
? JSObject::kAllowSmiOnlyElements
: JSObject::kDontAllowSmiOnlyElements;
return obj->SetFastElementsCapacityAndLength(capacity,
length,
set_capacity_mode);
}
virtual MaybeObject* Delete(JSObject* obj,
uint32_t key,
JSReceiver::DeleteMode mode) {
......@@ -281,11 +402,21 @@ class FastElementsAccessor
class FastDoubleElementsAccessor
: public ElementsAccessorBase<FastDoubleElementsAccessor,
FixedDoubleArray> {
: public FastElementsAccessor<FastDoubleElementsAccessor,
FixedDoubleArray,
kDoubleSize> {
protected:
friend class ElementsAccessorBase<FastDoubleElementsAccessor,
FixedDoubleArray>;
friend class FastElementsAccessor<FastDoubleElementsAccessor,
FixedDoubleArray,
kDoubleSize>;
static MaybeObject* SetFastElementsCapacityAndLength(JSObject* obj,
uint32_t capacity,
uint32_t length) {
return obj->SetFastDoubleElementsCapacityAndLength(capacity, length);
}
virtual MaybeObject* Delete(JSObject* obj,
uint32_t key,
......@@ -329,6 +460,14 @@ class ExternalElementsAccessor
}
}
static MaybeObject* SetLength(ExternalArray* backing_store,
JSObject* obj,
Object* length) {
// External arrays do not support changing their length.
UNREACHABLE();
return obj;
}
virtual MaybeObject* Delete(JSObject* obj,
uint32_t key,
JSReceiver::DeleteMode mode) {
......@@ -396,6 +535,63 @@ class DictionaryElementsAccessor
: public ElementsAccessorBase<DictionaryElementsAccessor,
NumberDictionary> {
public:
// Adjusts the length of the dictionary backing store and returns the new
// length according to ES5 section 15.4.5.2 behavior.
static MaybeObject* SetLengthWithoutNormalize(NumberDictionary* dict,
JSArray* array,
Object* length_object,
uint32_t length) {
if (length == 0) {
// If the length of a slow array is reset to zero, we clear
// the array and flush backing storage. This has the added
// benefit that the array returns to fast mode.
Object* obj;
MaybeObject* maybe_obj = array->ResetElements();
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
} else {
uint32_t new_length = length;
uint32_t old_length = static_cast<uint32_t>(array->length()->Number());
if (new_length < old_length) {
// Find last non-deletable element in range of elements to be
// deleted and adjust range accordingly.
Heap* heap = array->GetHeap();
int capacity = dict->Capacity();
for (int i = 0; i < capacity; i++) {
Object* key = dict->KeyAt(i);
if (key->IsNumber()) {
uint32_t number = static_cast<uint32_t>(key->Number());
if (new_length <= number && number < old_length) {
PropertyDetails details = dict->DetailsAt(i);
if (details.IsDontDelete()) new_length = number + 1;
}
}
}
if (new_length != length) {
MaybeObject* maybe_object = heap->NumberFromUint32(new_length);
if (!maybe_object->To(&length_object)) return maybe_object;
}
// Remove elements that should be deleted.
int removed_entries = 0;
Object* the_hole_value = heap->the_hole_value();
for (int i = 0; i < capacity; i++) {
Object* key = dict->KeyAt(i);
if (key->IsNumber()) {
uint32_t number = static_cast<uint32_t>(key->Number());
if (new_length <= number && number < old_length) {
dict->SetEntry(i, the_hole_value, the_hole_value);
removed_entries++;
}
}
}
// Update the number of elements.
dict->ElementsRemoved(removed_entries);
}
}
return length_object;
}
static MaybeObject* DeleteCommon(JSObject* obj,
uint32_t key,
JSReceiver::DeleteMode mode) {
......@@ -505,9 +701,17 @@ class NonStrictArgumentsElementsAccessor
}
}
static MaybeObject* SetLength(FixedArray* parameter_map,
JSObject* obj,
Object* length) {
// TODO(mstarzinger): This was never implemented but will be used once we
// correctly implement [[DefineOwnProperty]] on arrays.
UNIMPLEMENTED();
return obj;
}
virtual MaybeObject* Delete(JSObject* obj,
uint32_t key
,
uint32_t key,
JSReceiver::DeleteMode mode) {
FixedArray* parameter_map = FixedArray::cast(obj->elements());
Object* probe = GetParameterMapArg(parameter_map, key);
......@@ -521,7 +725,7 @@ class NonStrictArgumentsElementsAccessor
if (arguments->IsDictionary()) {
return DictionaryElementsAccessor::DeleteCommon(obj, key, mode);
} else {
return FastElementsAccessor::DeleteCommon(obj, key);
return FastObjectElementsAccessor::DeleteCommon(obj, key);
}
}
return obj->GetHeap()->true_value();
......@@ -600,8 +804,8 @@ void ElementsAccessor::InitializeOncePerProcess() {
static struct ConcreteElementsAccessors {
// Use the fast element handler for smi-only arrays. The implementation is
// currently identical.
FastElementsAccessor fast_smi_elements_handler;
FastElementsAccessor fast_elements_handler;
FastObjectElementsAccessor fast_smi_elements_handler;
FastObjectElementsAccessor fast_elements_handler;
FastDoubleElementsAccessor fast_double_elements_handler;
DictionaryElementsAccessor dictionary_elements_handler;
NonStrictArgumentsElementsAccessor non_strict_arguments_elements_handler;
......@@ -640,4 +844,62 @@ void ElementsAccessor::InitializeOncePerProcess() {
}
template <typename ElementsAccessorSubclass, typename BackingStoreClass>
MaybeObject* ElementsAccessorBase<ElementsAccessorSubclass, BackingStoreClass>::
SetLength(BackingStoreClass* backing_store,
JSObject* obj,
Object* length) {
JSArray* array = JSArray::cast(obj);
// Fast case: The new length fits into a Smi.
MaybeObject* maybe_smi_length = length->ToSmi();
Object* smi_length = Smi::FromInt(0);
if (maybe_smi_length->ToObject(&smi_length) && smi_length->IsSmi()) {
const int value = Smi::cast(smi_length)->value();
if (value >= 0) {
Object* new_length;
MaybeObject* result = ElementsAccessorSubclass::
SetLengthWithoutNormalize(backing_store, array, smi_length, value);
if (!result->ToObject(&new_length)) return result;
ASSERT(new_length->IsSmi() || new_length->IsUndefined());
if (new_length->IsSmi()) {
array->set_length(Smi::cast(new_length));
return array;
}
} else {
return ThrowArrayLengthRangeError(array->GetHeap());
}
}
// Slow case: The new length does not fit into a Smi or conversion
// to slow elements is needed for other reasons.
if (length->IsNumber()) {
uint32_t value;
if (length->ToArrayIndex(&value)) {
NumberDictionary* dictionary;
MaybeObject* maybe_object = array->NormalizeElements();
if (!maybe_object->To(&dictionary)) return maybe_object;
Object* new_length;
MaybeObject* result = DictionaryElementsAccessor::
SetLengthWithoutNormalize(dictionary, array, length, value);
if (!result->ToObject(&new_length)) return result;
ASSERT(new_length->IsNumber());
array->set_length(new_length);
return array;
} else {
return ThrowArrayLengthRangeError(array->GetHeap());
}
}
// Fall-back case: The new length is not a number so make the array
// size one and set only element to length.
FixedArray* new_backing_store;
MaybeObject* maybe_obj = array->GetHeap()->AllocateFixedArray(1);
if (!maybe_obj->To(&new_backing_store)) return maybe_obj;
new_backing_store->set(0, length);
array->SetContent(new_backing_store);
return array;
}
} } // namespace v8::internal
......@@ -44,6 +44,11 @@ class ElementsAccessor {
JSObject* holder,
Object* receiver) = 0;
// Modifies the length data property as specified for JSArrays and resizes
// the underlying backing store accordingly.
virtual MaybeObject* SetLength(JSObject* holder,
Object* new_length) = 0;
virtual MaybeObject* Delete(JSObject* holder,
uint32_t key,
JSReceiver::DeleteMode mode) = 0;
......
......@@ -8351,61 +8351,6 @@ MaybeObject* JSObject::SetFastDoubleElementsCapacityAndLength(
}
MaybeObject* JSObject::SetSlowElements(Object* len) {
// We should never end in here with a pixel or external array.
ASSERT(!HasExternalArrayElements());
uint32_t new_length = static_cast<uint32_t>(len->Number());
FixedArrayBase* old_elements = elements();
ElementsKind elements_kind = GetElementsKind();
switch (elements_kind) {
case FAST_SMI_ONLY_ELEMENTS:
case FAST_ELEMENTS:
case FAST_DOUBLE_ELEMENTS: {
// Make sure we never try to shrink dense arrays into sparse arrays.
ASSERT(static_cast<uint32_t>(old_elements->length()) <= new_length);
MaybeObject* result = NormalizeElements();
if (result->IsFailure()) return result;
// Update length for JSArrays.
if (IsJSArray()) JSArray::cast(this)->set_length(len);
break;
}
case DICTIONARY_ELEMENTS: {
if (IsJSArray()) {
uint32_t old_length =
static_cast<uint32_t>(JSArray::cast(this)->length()->Number());
element_dictionary()->RemoveNumberEntries(new_length, old_length),
JSArray::cast(this)->set_length(len);
}
break;
}
case NON_STRICT_ARGUMENTS_ELEMENTS:
UNIMPLEMENTED();
break;
case EXTERNAL_BYTE_ELEMENTS:
case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
case EXTERNAL_SHORT_ELEMENTS:
case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
case EXTERNAL_INT_ELEMENTS:
case EXTERNAL_UNSIGNED_INT_ELEMENTS:
case EXTERNAL_FLOAT_ELEMENTS:
case EXTERNAL_DOUBLE_ELEMENTS:
case EXTERNAL_PIXEL_ELEMENTS:
UNREACHABLE();
break;
}
if (FLAG_trace_elements_transitions) {
PrintElementsTransition(stdout, elements_kind, old_elements,
DICTIONARY_ELEMENTS, elements());
}
return this;
}
MaybeObject* JSArray::Initialize(int capacity) {
Heap* heap = GetHeap();
ASSERT(capacity >= 0);
......@@ -8437,165 +8382,10 @@ void JSArray::Expand(int required_size) {
}
static Failure* ArrayLengthRangeError(Heap* heap) {
HandleScope scope(heap->isolate());
return heap->isolate()->Throw(
*FACTORY->NewRangeError("invalid_array_length",
HandleVector<Object>(NULL, 0)));
}
MaybeObject* JSObject::SetElementsLength(Object* len) {
// We should never end in here with a pixel or external array.
ASSERT(AllowsSetElementsLength());
MaybeObject* maybe_smi_length = len->ToSmi();
Object* smi_length = Smi::FromInt(0);
if (maybe_smi_length->ToObject(&smi_length) && smi_length->IsSmi()) {
const int value = Smi::cast(smi_length)->value();
if (value < 0) return ArrayLengthRangeError(GetHeap());
ElementsKind elements_kind = GetElementsKind();
switch (elements_kind) {
case FAST_SMI_ONLY_ELEMENTS:
case FAST_ELEMENTS:
case FAST_DOUBLE_ELEMENTS: {
int old_capacity = FixedArrayBase::cast(elements())->length();
if (value <= old_capacity) {
if (IsJSArray()) {
Object* obj;
if (elements_kind == FAST_ELEMENTS ||
elements_kind == FAST_SMI_ONLY_ELEMENTS) {
MaybeObject* maybe_obj = EnsureWritableFastElements();
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
if (2 * value <= old_capacity) {
// If more than half the elements won't be used, trim the array.
if (value == 0) {
initialize_elements();
} else {
Address filler_start;
int filler_size;
if (elements_kind == FAST_ELEMENTS ||
elements_kind == FAST_SMI_ONLY_ELEMENTS) {
FixedArray* fast_elements = FixedArray::cast(elements());
fast_elements->set_length(value);
filler_start = fast_elements->address() +
FixedArray::OffsetOfElementAt(value);
filler_size = (old_capacity - value) * kPointerSize;
} else {
ASSERT(GetElementsKind() == FAST_DOUBLE_ELEMENTS);
FixedDoubleArray* fast_double_elements =
FixedDoubleArray::cast(elements());
fast_double_elements->set_length(value);
filler_start = fast_double_elements->address() +
FixedDoubleArray::OffsetOfElementAt(value);
filler_size = (old_capacity - value) * kDoubleSize;
}
GetHeap()->CreateFillerObjectAt(filler_start, filler_size);
}
} else {
// Otherwise, fill the unused tail with holes.
int old_length = FastD2I(JSArray::cast(this)->length()->Number());
if (elements_kind == FAST_ELEMENTS ||
elements_kind == FAST_SMI_ONLY_ELEMENTS) {
FixedArray* fast_elements = FixedArray::cast(elements());
for (int i = value; i < old_length; i++) {
fast_elements->set_the_hole(i);
}
} else {
ASSERT(elements_kind == FAST_DOUBLE_ELEMENTS);
FixedDoubleArray* fast_double_elements =
FixedDoubleArray::cast(elements());
for (int i = value; i < old_length; i++) {
fast_double_elements->set_the_hole(i);
}
}
}
JSArray::cast(this)->set_length(Smi::cast(smi_length));
}
return this;
}
int min = NewElementsCapacity(old_capacity);
int new_capacity = value > min ? value : min;
if (!ShouldConvertToSlowElements(new_capacity)) {
MaybeObject* result;
if (elements_kind == FAST_ELEMENTS ||
elements_kind == FAST_SMI_ONLY_ELEMENTS) {
SetFastElementsCapacityMode set_capacity_mode =
elements_kind == FAST_SMI_ONLY_ELEMENTS
? kAllowSmiOnlyElements
: kDontAllowSmiOnlyElements;
result = SetFastElementsCapacityAndLength(new_capacity,
value,
set_capacity_mode);
} else {
ASSERT(elements_kind == FAST_DOUBLE_ELEMENTS);
result = SetFastDoubleElementsCapacityAndLength(new_capacity,
value);
}
if (result->IsFailure()) return result;
return this;
}
break;
}
case DICTIONARY_ELEMENTS: {
if (IsJSArray()) {
if (value == 0) {
// If the length of a slow array is reset to zero, we clear
// the array and flush backing storage. This has the added
// benefit that the array returns to fast mode.
Object* obj;
{ MaybeObject* maybe_obj = ResetElements();
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
} else {
// Remove deleted elements.
uint32_t old_length =
static_cast<uint32_t>(JSArray::cast(this)->length()->Number());
element_dictionary()->RemoveNumberEntries(value, old_length);
}
JSArray::cast(this)->set_length(Smi::cast(smi_length));
}
return this;
}
case NON_STRICT_ARGUMENTS_ELEMENTS:
case EXTERNAL_BYTE_ELEMENTS:
case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
case EXTERNAL_SHORT_ELEMENTS:
case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
case EXTERNAL_INT_ELEMENTS:
case EXTERNAL_UNSIGNED_INT_ELEMENTS:
case EXTERNAL_FLOAT_ELEMENTS:
case EXTERNAL_DOUBLE_ELEMENTS:
case EXTERNAL_PIXEL_ELEMENTS:
UNREACHABLE();
break;
}
}
// General slow case.
if (len->IsNumber()) {
uint32_t length;
if (len->ToArrayIndex(&length)) {
return SetSlowElements(len);
} else {
return ArrayLengthRangeError(GetHeap());
}
}
// len is not a number so make the array size one and
// set only element to len.
Object* obj;
MaybeObject* maybe_obj = GetHeap()->AllocateFixedArray(1);
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
FixedArray::cast(obj)->set(0, len);
maybe_obj = EnsureCanContainElements(&len, 1);
if (maybe_obj->IsFailure()) return maybe_obj;
if (IsJSArray()) JSArray::cast(this)->set_length(Smi::FromInt(1));
set_elements(FixedArray::cast(obj));
return this;
return GetElementsAccessor()->SetLength(this, len);
}
......@@ -11971,30 +11761,6 @@ MaybeObject* Dictionary<Shape, Key>::EnsureCapacity(int n, Key key) {
}
void NumberDictionary::RemoveNumberEntries(uint32_t from, uint32_t to) {
// Do nothing if the interval [from, to) is empty.
if (from >= to) return;
Heap* heap = GetHeap();
int removed_entries = 0;
Object* the_hole_value = heap->the_hole_value();
int capacity = Capacity();
for (int i = 0; i < capacity; i++) {
Object* key = KeyAt(i);
if (key->IsNumber()) {
uint32_t number = static_cast<uint32_t>(key->Number());
if (from <= number && number < to) {
SetEntry(i, the_hole_value, the_hole_value);
removed_entries++;
}
}
}
// Update the number of elements.
ElementsRemoved(removed_entries);
}
template<typename Shape, typename Key>
Object* Dictionary<Shape, Key>::DeleteProperty(int entry,
JSReceiver::DeleteMode mode) {
......
......@@ -1659,7 +1659,6 @@ class JSObject: public JSReceiver {
MUST_USE_RESULT MaybeObject* SetFastDoubleElementsCapacityAndLength(
int capacity,
int length);
MUST_USE_RESULT MaybeObject* SetSlowElements(Object* length);
// Lookup interceptors are used for handling properties controlled by host
// objects.
......@@ -2911,9 +2910,6 @@ class NumberDictionary: public Dictionary<NumberDictionaryShape, uint32_t> {
// requires_slow_elements returns false.
inline uint32_t max_number_key();
// Remove all entries were key is a number and (from <= key && key < to).
void RemoveNumberEntries(uint32_t from, uint32_t to);
// Bit masks.
static const int kRequiresSlowElementsMask = 1;
static const int kRequiresSlowElementsTagSize = 1;
......
......@@ -499,39 +499,6 @@ S15.4.4.3_A2_T1: FAIL_OK
15.2.3.6-4-623: FAIL
# Bug? ES5 Attributes - all attributes in Date.prototype.toJSON are correct
15.2.3.6-4-624: FAIL
# Bug? Array.prototype.indexOf - decreasing length of array does not delete
# non-configurable properties
15.4.4.14-9-a-19: FAIL
# Bug? Array.prototype.lastIndexOf - decreasing length of array does not delete
# non-configurable properties
15.4.4.15-8-a-19: FAIL
# Bug? Array.prototype.every - decreasing length of array does not delete
# non-configurable properties
15.4.4.16-7-b-16: FAIL
# Bug? Array.prototype.some - decreasing length of array does not delete
# non-configurable properties
15.4.4.17-7-b-16: FAIL
# Bug? Array.prototype.forEach - decreasing length of array does not delete
# non-configurable properties
15.4.4.18-7-b-16: FAIL
# Bug? Array.prototype.map - decreasing length of array does not delete
# non-configurable properties
15.4.4.19-8-b-16: FAIL
# Bug? Array.prototype.filter - decreasing length of array does not delete
# non-configurable properties
15.4.4.20-9-b-16: FAIL
# Bug? Array.prototype.reduce - decreasing length of array in step 8 does not
# delete non-configurable properties
15.4.4.21-9-b-16: FAIL
# Bug? Array.prototype.reduce - decreasing length of array does not delete
# non-configurable properties
15.4.4.21-9-b-29: FAIL
# Bug? Array.prototype.reduceRight - decreasing length of array in step 8 does
# not delete non-configurable properties
15.4.4.22-9-b-16: FAIL
# Bug? Array.prototype.reduceRight - decreasing length of array does not delete
# non-configurable properties
15.4.4.22-9-b-29: FAIL
############################ SKIPPED TESTS #############################
......
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