Fix some array functions to behave as specified.

This fixes the handling of primitives and the order of how side effects
are visible in some array functions as specified by the ES5.

R=rossberg@chromium.org
TEST=test262

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@9549 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
mstarzinger@chromium.org 2011-10-07 14:07:33 +00:00
parent 0ce4730f92
commit e699434266
2 changed files with 66 additions and 192 deletions

View File

@ -1003,21 +1003,24 @@ function ArrayFilter(f, receiver) {
["Array.prototype.filter"]); ["Array.prototype.filter"]);
} }
// Pull out the length so that modifications to the length in the
// loop will not affect the looping and side effects are visible.
var array = ToObject(this);
var length = ToUint32(array.length);
if (!IS_SPEC_FUNCTION(f)) { if (!IS_SPEC_FUNCTION(f)) {
throw MakeTypeError('called_non_callable', [ f ]); throw MakeTypeError('called_non_callable', [ f ]);
} }
if (IS_NULL_OR_UNDEFINED(receiver)) { if (IS_NULL_OR_UNDEFINED(receiver)) {
receiver = %GetDefaultReceiver(f) || receiver; receiver = %GetDefaultReceiver(f) || receiver;
} }
// Pull out the length so that modifications to the length in the
// loop will not affect the looping.
var length = ToUint32(this.length);
var result = []; var result = [];
var result_length = 0; var result_length = 0;
for (var i = 0; i < length; i++) { for (var i = 0; i < length; i++) {
var current = this[i]; var current = array[i];
if (!IS_UNDEFINED(current) || i in this) { if (!IS_UNDEFINED(current) || i in array) {
if (%_CallFunction(receiver, current, i, this, f)) { if (%_CallFunction(receiver, current, i, array, f)) {
result[result_length++] = current; result[result_length++] = current;
} }
} }
@ -1032,19 +1035,22 @@ function ArrayForEach(f, receiver) {
["Array.prototype.forEach"]); ["Array.prototype.forEach"]);
} }
// Pull out the length so that modifications to the length in the
// loop will not affect the looping and side effects are visible.
var array = ToObject(this);
var length = TO_UINT32(array.length);
if (!IS_SPEC_FUNCTION(f)) { if (!IS_SPEC_FUNCTION(f)) {
throw MakeTypeError('called_non_callable', [ f ]); throw MakeTypeError('called_non_callable', [ f ]);
} }
if (IS_NULL_OR_UNDEFINED(receiver)) { if (IS_NULL_OR_UNDEFINED(receiver)) {
receiver = %GetDefaultReceiver(f) || receiver; receiver = %GetDefaultReceiver(f) || receiver;
} }
// Pull out the length so that modifications to the length in the
// loop will not affect the looping.
var length = TO_UINT32(this.length);
for (var i = 0; i < length; i++) { for (var i = 0; i < length; i++) {
var current = this[i]; var current = array[i];
if (!IS_UNDEFINED(current) || i in this) { if (!IS_UNDEFINED(current) || i in array) {
%_CallFunction(receiver, current, i, this, f); %_CallFunction(receiver, current, i, array, f);
} }
} }
} }
@ -1058,19 +1064,22 @@ function ArraySome(f, receiver) {
["Array.prototype.some"]); ["Array.prototype.some"]);
} }
// Pull out the length so that modifications to the length in the
// loop will not affect the looping and side effects are visible.
var array = ToObject(this);
var length = TO_UINT32(array.length);
if (!IS_SPEC_FUNCTION(f)) { if (!IS_SPEC_FUNCTION(f)) {
throw MakeTypeError('called_non_callable', [ f ]); throw MakeTypeError('called_non_callable', [ f ]);
} }
if (IS_NULL_OR_UNDEFINED(receiver)) { if (IS_NULL_OR_UNDEFINED(receiver)) {
receiver = %GetDefaultReceiver(f) || receiver; receiver = %GetDefaultReceiver(f) || receiver;
} }
// Pull out the length so that modifications to the length in the
// loop will not affect the looping.
var length = TO_UINT32(this.length);
for (var i = 0; i < length; i++) { for (var i = 0; i < length; i++) {
var current = this[i]; var current = array[i];
if (!IS_UNDEFINED(current) || i in this) { if (!IS_UNDEFINED(current) || i in array) {
if (%_CallFunction(receiver, current, i, this, f)) return true; if (%_CallFunction(receiver, current, i, array, f)) return true;
} }
} }
return false; return false;
@ -1083,19 +1092,22 @@ function ArrayEvery(f, receiver) {
["Array.prototype.every"]); ["Array.prototype.every"]);
} }
// Pull out the length so that modifications to the length in the
// loop will not affect the looping and side effects are visible.
var array = ToObject(this);
var length = TO_UINT32(array.length);
if (!IS_SPEC_FUNCTION(f)) { if (!IS_SPEC_FUNCTION(f)) {
throw MakeTypeError('called_non_callable', [ f ]); throw MakeTypeError('called_non_callable', [ f ]);
} }
if (IS_NULL_OR_UNDEFINED(receiver)) { if (IS_NULL_OR_UNDEFINED(receiver)) {
receiver = %GetDefaultReceiver(f) || receiver; receiver = %GetDefaultReceiver(f) || receiver;
} }
// Pull out the length so that modifications to the length in the
// loop will not affect the looping.
var length = TO_UINT32(this.length);
for (var i = 0; i < length; i++) { for (var i = 0; i < length; i++) {
var current = this[i]; var current = array[i];
if (!IS_UNDEFINED(current) || i in this) { if (!IS_UNDEFINED(current) || i in array) {
if (!%_CallFunction(receiver, current, i, this, f)) return false; if (!%_CallFunction(receiver, current, i, array, f)) return false;
} }
} }
return true; return true;
@ -1107,21 +1119,24 @@ function ArrayMap(f, receiver) {
["Array.prototype.map"]); ["Array.prototype.map"]);
} }
// Pull out the length so that modifications to the length in the
// loop will not affect the looping and side effects are visible.
var array = ToObject(this);
var length = TO_UINT32(array.length);
if (!IS_SPEC_FUNCTION(f)) { if (!IS_SPEC_FUNCTION(f)) {
throw MakeTypeError('called_non_callable', [ f ]); throw MakeTypeError('called_non_callable', [ f ]);
} }
if (IS_NULL_OR_UNDEFINED(receiver)) { if (IS_NULL_OR_UNDEFINED(receiver)) {
receiver = %GetDefaultReceiver(f) || receiver; receiver = %GetDefaultReceiver(f) || receiver;
} }
// Pull out the length so that modifications to the length in the
// loop will not affect the looping.
var length = TO_UINT32(this.length);
var result = new $Array(); var result = new $Array();
var accumulator = new InternalArray(length); var accumulator = new InternalArray(length);
for (var i = 0; i < length; i++) { for (var i = 0; i < length; i++) {
var current = this[i]; var current = array[i];
if (!IS_UNDEFINED(current) || i in this) { if (!IS_UNDEFINED(current) || i in array) {
accumulator[i] = %_CallFunction(receiver, current, i, this, f); accumulator[i] = %_CallFunction(receiver, current, i, array, f);
} }
} }
%MoveArrayContents(accumulator, result); %MoveArrayContents(accumulator, result);
@ -1255,19 +1270,20 @@ function ArrayReduce(callback, current) {
["Array.prototype.reduce"]); ["Array.prototype.reduce"]);
} }
// Pull out the length so that modifications to the length in the
// loop will not affect the looping and side effects are visible.
var array = ToObject(this);
var length = ToUint32(array.length);
if (!IS_SPEC_FUNCTION(callback)) { if (!IS_SPEC_FUNCTION(callback)) {
throw MakeTypeError('called_non_callable', [callback]); throw MakeTypeError('called_non_callable', [callback]);
} }
// Pull out the length so that modifications to the length in the
// loop will not affect the looping.
var length = ToUint32(this.length);
var i = 0; var i = 0;
find_initial: if (%_ArgumentsLength() < 2) { find_initial: if (%_ArgumentsLength() < 2) {
for (; i < length; i++) { for (; i < length; i++) {
current = this[i]; current = array[i];
if (!IS_UNDEFINED(current) || i in this) { if (!IS_UNDEFINED(current) || i in array) {
i++; i++;
break find_initial; break find_initial;
} }
@ -1277,9 +1293,9 @@ function ArrayReduce(callback, current) {
var receiver = %GetDefaultReceiver(callback); var receiver = %GetDefaultReceiver(callback);
for (; i < length; i++) { for (; i < length; i++) {
var element = this[i]; var element = array[i];
if (!IS_UNDEFINED(element) || i in this) { if (!IS_UNDEFINED(element) || i in array) {
current = %_CallFunction(receiver, current, element, i, this, callback); current = %_CallFunction(receiver, current, element, i, array, callback);
} }
} }
return current; return current;
@ -1291,15 +1307,20 @@ function ArrayReduceRight(callback, current) {
["Array.prototype.reduceRight"]); ["Array.prototype.reduceRight"]);
} }
// Pull out the length so that side effects are visible before the
// callback function is checked.
var array = ToObject(this);
var length = ToUint32(array.length);
if (!IS_SPEC_FUNCTION(callback)) { if (!IS_SPEC_FUNCTION(callback)) {
throw MakeTypeError('called_non_callable', [callback]); throw MakeTypeError('called_non_callable', [callback]);
} }
var i = ToUint32(this.length) - 1;
var i = length - 1;
find_initial: if (%_ArgumentsLength() < 2) { find_initial: if (%_ArgumentsLength() < 2) {
for (; i >= 0; i--) { for (; i >= 0; i--) {
current = this[i]; current = array[i];
if (!IS_UNDEFINED(current) || i in this) { if (!IS_UNDEFINED(current) || i in array) {
i--; i--;
break find_initial; break find_initial;
} }
@ -1309,9 +1330,9 @@ function ArrayReduceRight(callback, current) {
var receiver = %GetDefaultReceiver(callback); var receiver = %GetDefaultReceiver(callback);
for (; i >= 0; i--) { for (; i >= 0; i--) {
var element = this[i]; var element = array[i];
if (!IS_UNDEFINED(element) || i in this) { if (!IS_UNDEFINED(element) || i in array) {
current = %_CallFunction(receiver, current, element, i, this, callback); current = %_CallFunction(receiver, current, element, i, array, callback);
} }
} }
return current; return current;

View File

@ -1106,27 +1106,6 @@ S15.4.4.3_A2_T1: FAIL_OK
# Bug? Array.prototype.lastIndexOf terminates iteration on unhandled exception # Bug? Array.prototype.lastIndexOf terminates iteration on unhandled exception
# on an Array # on an Array
15.4.4.15-8-b-i-30: FAIL 15.4.4.15-8-b-i-30: FAIL
# Bug? Array.prototype.every applied to boolean primitive
15.4.4.16-1-3: FAIL
# Bug? Array.prototype.every applied to number primitive
15.4.4.16-1-5: FAIL
# Bug? Array.prototype.every applied to string primitive
15.4.4.16-1-7: FAIL
# Bug? Array.prototype.every - side effects produced by step 2 are visible when
# an exception occurs
15.4.4.16-4-8: FAIL
# Bug? Array.prototype.every - side effects produced by step 3 are visible when
# an exception occurs
15.4.4.16-4-9: FAIL
# Bug? Array.prototype.every - the exception is not thrown if exception was
# thrown by step 2
15.4.4.16-4-10: FAIL
# Bug? Array.prototype.every - the exception is not thrown if exception was
# thrown by step 3
15.4.4.16-4-11: FAIL
# Bug? Array.prototype.every - calling with no callbackfn is the same as passing
# undefined for callbackfn
15.4.4.16-4-15: FAIL
# Bug? Array.prototype.every - decreasing length of array does not delete # Bug? Array.prototype.every - decreasing length of array does not delete
# non-configurable properties # non-configurable properties
15.4.4.16-7-b-16: FAIL 15.4.4.16-7-b-16: FAIL
@ -1149,27 +1128,6 @@ S15.4.4.3_A2_T1: FAIL_OK
# Bug? Array.prototype.every - element changed by getter on previous iterations # Bug? Array.prototype.every - element changed by getter on previous iterations
# is observed on an Array # is observed on an Array
15.4.4.16-7-c-i-28: FAIL 15.4.4.16-7-c-i-28: FAIL
# Bug? Array.prototype.some applied to boolean primitive
15.4.4.17-1-3: FAIL
# Bug? Array.prototype.some applied to number primitive
15.4.4.17-1-5: FAIL
# Bug? Array.prototype.some applied to applied to string primitive
15.4.4.17-1-7: FAIL
# Bug? Array.prototype.some - side effects produced by step 2 are visible when
# an exception occurs
15.4.4.17-4-8: FAIL
# Bug? Array.prototype.some - side effects produced by step 3 are visible when
# an exception occurs
15.4.4.17-4-9: FAIL
# Bug? Array.prototype.some - the exception is not thrown if exception was
# thrown by step 2
15.4.4.17-4-10: FAIL
# Bug? Array.prototype.some - the exception is not thrown if exception was
# thrown by step 3
15.4.4.17-4-11: FAIL
# Bug? Array.prototype.some - calling with no callbackfn is the same as passing
# undefined for callbackfn
15.4.4.17-4-15: FAIL
# Bug? Array.prototype.some - decreasing length of array does not delete # Bug? Array.prototype.some - decreasing length of array does not delete
# non-configurable properties # non-configurable properties
15.4.4.17-7-b-16: FAIL 15.4.4.17-7-b-16: FAIL
@ -1192,27 +1150,6 @@ S15.4.4.3_A2_T1: FAIL_OK
# Bug? Array.prototype.some - element changed by getter on previous iterations # Bug? Array.prototype.some - element changed by getter on previous iterations
# is observed on an Array # is observed on an Array
15.4.4.17-7-c-i-28: FAIL 15.4.4.17-7-c-i-28: FAIL
# Bug? Array.prototype.forEach applied to boolean primitive
15.4.4.18-1-3: FAIL
# Bug? Array.prototype.forEach applied to number primitive
15.4.4.18-1-5: FAIL
# Bug? Array.prototype.forEach applied to string primitive
15.4.4.18-1-7: FAIL
# Bug? Array.prototype.forEach - side effects produced by step 2 are visible
# when an exception occurs
15.4.4.18-4-8: FAIL
# Bug? Array.prototype.forEach - side effects produced by step 3 are visible
# when an exception occurs
15.4.4.18-4-9: FAIL
# Bug? Array.prototype.forEach - the exception is not thrown if exception was
# thrown by step 2
15.4.4.18-4-10: FAIL
# Bug? Array.prototype.forEach - the exception is not thrown if exception was
# thrown by step 3
15.4.4.18-4-11: FAIL
# Bug? Array.prototype.forEach - calling with no callbackfn is the same as
# passing undefined for callbackfn
15.4.4.18-4-15: FAIL
# Bug? Array.prototype.forEach - decreasing length of array does not delete # Bug? Array.prototype.forEach - decreasing length of array does not delete
# non-configurable properties # non-configurable properties
15.4.4.18-7-b-16: FAIL 15.4.4.18-7-b-16: FAIL
@ -1235,27 +1172,6 @@ S15.4.4.3_A2_T1: FAIL_OK
# Bug? Array.prototype.forEach - element changed by getter on previous # Bug? Array.prototype.forEach - element changed by getter on previous
# iterations is observed on an Array # iterations is observed on an Array
15.4.4.18-7-c-i-28: FAIL 15.4.4.18-7-c-i-28: FAIL
# Bug? Array.prototype.map - applied to boolean primitive
15.4.4.19-1-3: FAIL
# Bug? Array.prototype.map - applied to number primitive
15.4.4.19-1-5: FAIL
# Bug? Array.prototype.map - applied to string primitive
15.4.4.19-1-7: FAIL
# Bug? Array.prototype.map - Side effects produced by step 2 are visible when an
# exception occurs
15.4.4.19-4-8: FAIL
# Bug? Array.prototype.map - Side effects produced by step 3 are visible when an
# exception occurs
15.4.4.19-4-9: FAIL
# Bug? Array.prototype.map - the exception is not thrown if exception was thrown
# by step 2
15.4.4.19-4-10: FAIL
# Bug? Array.prototype.map - the exception is not thrown if exception was thrown
# by step 3
15.4.4.19-4-11: FAIL
# Bug? Array.prototype.map - calling with no callbackfn is the same as passing
# undefined for callbackfn
15.4.4.19-4-15: FAIL
# Bug? Array.prototype.map - decreasing length of array does not delete # Bug? Array.prototype.map - decreasing length of array does not delete
# non-configurable properties # non-configurable properties
15.4.4.19-8-b-16: FAIL 15.4.4.19-8-b-16: FAIL
@ -1278,27 +1194,6 @@ S15.4.4.3_A2_T1: FAIL_OK
# Bug? Array.prototype.map - element changed by getter on previous iterations is # Bug? Array.prototype.map - element changed by getter on previous iterations is
# observed on an Array # observed on an Array
15.4.4.19-8-c-i-28: FAIL 15.4.4.19-8-c-i-28: FAIL
# Bug? Array.prototype.filter applied to boolean primitive
15.4.4.20-1-3: FAIL
# Bug? Array.prototype.filter applied to number primitive
15.4.4.20-1-5: FAIL
# Bug? Array.prototype.filter applied to string primitive
15.4.4.20-1-7: FAIL
# Bug? Array.prototype.filter - side effects produced by step 2 are visible when
# an exception occurs
15.4.4.20-4-8: FAIL
# Bug? Array.prototype.filter - side effects produced by step 3 are visible when
# an exception occurs
15.4.4.20-4-9: FAIL
# Bug? Array.prototype.filter - the exception is not thrown if exception was
# thrown by step 2
15.4.4.20-4-10: FAIL
# Bug? Array.prototype.filter - the exception is not thrown if exception was
# thrown by step 3
15.4.4.20-4-11: FAIL
# Bug? Array.prototype.filter - calling with no callbackfn is the same as
# passing undefined for callbackfn
15.4.4.20-4-15: FAIL
# Bug? Array.prototype.filter - properties can be added to prototype after # Bug? Array.prototype.filter - properties can be added to prototype after
# current position are visited on an Array-like object # current position are visited on an Array-like object
15.4.4.20-9-b-6: FAIL 15.4.4.20-9-b-6: FAIL
@ -1333,54 +1228,12 @@ S15.4.4.3_A2_T1: FAIL_OK
# Bug? Array.prototype.filter - element changed by getter on previous iterations # Bug? Array.prototype.filter - element changed by getter on previous iterations
# is observed on an Array # is observed on an Array
15.4.4.20-9-c-i-28: FAIL 15.4.4.20-9-c-i-28: FAIL
# Bug? Array.prototype.reduce applied to boolean primitive
15.4.4.21-1-3: FAIL
# Bug? Array.prototype.reduce applied to number primitive
15.4.4.21-1-5: FAIL
# Bug? Array.prototype.reduce applied to string primitive
15.4.4.21-1-7: FAIL
# Bug? Array.prototype.reduce - side effects produced by step 2 are visible when
# an exception occurs
15.4.4.21-4-8: FAIL
# Bug? Array.prototype.reduce - side effects produced by step 3 are visible when
# an exception occurs
15.4.4.21-4-9: FAIL
# Bug? Array.prototype.reduce - the exception is not thrown if exception was
# thrown by step 2
15.4.4.21-4-10: FAIL
# Bug? Array.prototype.reduce - the exception is not thrown if exception was
# thrown by step 3
15.4.4.21-4-11: FAIL
# Bug? Array.prototype.reduce - calling with no callbackfn is the same as
# passing undefined for callbackfn
15.4.4.21-4-15: FAIL
# Bug? Array.prototype.reduce - decreasing length of array in step 8 does not # Bug? Array.prototype.reduce - decreasing length of array in step 8 does not
# delete non-configurable properties # delete non-configurable properties
15.4.4.21-9-b-16: FAIL 15.4.4.21-9-b-16: FAIL
# Bug? Array.prototype.reduce - decreasing length of array does not delete # Bug? Array.prototype.reduce - decreasing length of array does not delete
# non-configurable properties # non-configurable properties
15.4.4.21-9-b-29: FAIL 15.4.4.21-9-b-29: FAIL
# Bug? Array.prototype.reduceRight applied to boolean primitive
15.4.4.22-1-3: FAIL
# Bug? Array.prototype.reduceRight applied to number primitive
15.4.4.22-1-5: FAIL
# Bug? Array.prototype.reduceRight applied to string primitive
15.4.4.22-1-7: FAIL
# Bug? Array.prototype.reduceRight - side effects produced by step 2 are visible
# when an exception occurs
15.4.4.22-4-8: FAIL
# Bug? Array.prototype.reduceRight - side effects produced by step 3 are visible
# when an exception occurs
15.4.4.22-4-9: FAIL
# Bug? Array.prototype.reduceRight - the exception is not thrown if exception
# was thrown by step 2
15.4.4.22-4-10: FAIL
# Bug? Array.prototype.reduceRight - the exception is not thrown if exception
# was thrown by step 3
15.4.4.22-4-11: FAIL
# Bug? Array.prototype.reduceRight - calling with no callbackfn is the same as
# passing undefined for callbackfn
15.4.4.22-4-15: FAIL
# Bug? Array.prototype.reduceRight - element to be retrieved is own accessor # Bug? Array.prototype.reduceRight - element to be retrieved is own accessor
# property that overrides an inherited data property on an Array # property that overrides an inherited data property on an Array
15.4.4.22-8-b-iii-1-12: FAIL 15.4.4.22-8-b-iii-1-12: FAIL