Commit 1052f503 authored by barraclough@apple.com's avatar barraclough@apple.com

Array.prototype functions should throw if delete fails

https://bugs.webkit.org/show_bug.cgi?id=80467

Reviewed by Oliver Hunt.

Source/JavaScriptCore: 

All calls to [[Delete]] from Array.prototype are specified to pass 'true' as the value of Throw.
In the case of shift/unshift, these are also missing a throw from the 'put' in the implementations
in JSArray.cpp. There are effectively three copies of each of the generic shift/unshift routines,
one in splice, one in ArrayPrototype's shift/unshift methods, and one in JSArray's shift/unshift
routines, for handling arrays with holes. These three copies should be unified.

* runtime/ArrayPrototype.cpp:
(JSC::shift):
(JSC::unshift):
    - Added - shared copies of the shift/unshift functionality.
(JSC::arrayProtoFuncPop):
    - should throw if the delete fails.
(JSC::arrayProtoFuncReverse):
    - should throw if the delete fails.
(JSC::arrayProtoFuncShift):
(JSC::arrayProtoFuncSplice):
(JSC::arrayProtoFuncUnShift):
    - use shift/unshift.
* runtime/JSArray.cpp:
(JSC::JSArray::shiftCount):
(JSC::JSArray::unshiftCount):
    - Don't try to handle arrays with holes; return a value indicating
      the generic routine should be used instead.
* runtime/JSArray.h:
    - declaration for shiftCount/unshiftCount changed.
* tests/mozilla/js1_6/Array/regress-304828.js:
    - this was asserting incorrect behaviour.

LayoutTests: 

* fast/js/mozilla/strict/15.4.4.12-expected.txt:
* fast/js/mozilla/strict/15.4.4.13-expected.txt:
* fast/js/mozilla/strict/15.4.4.6-expected.txt:
* fast/js/mozilla/strict/15.4.4.8-expected.txt:
* fast/js/mozilla/strict/15.4.4.9-expected.txt:
    - check in passing test results.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@110026 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent dd5226ac
2012-03-06 Gavin Barraclough <barraclough@apple.com>
Array.prototype functions should throw if delete fails
https://bugs.webkit.org/show_bug.cgi?id=80467
Reviewed by Oliver Hunt.
* fast/js/mozilla/strict/15.4.4.12-expected.txt:
* fast/js/mozilla/strict/15.4.4.13-expected.txt:
* fast/js/mozilla/strict/15.4.4.6-expected.txt:
* fast/js/mozilla/strict/15.4.4.8-expected.txt:
* fast/js/mozilla/strict/15.4.4.9-expected.txt:
- check in passing test results.
2012-03-06 Philippe Normand <pnormand@igalia.com>
fullscreen/video-controls is too specific to the mac port
FAIL 'use strict'; var a = arr(); [a.splice(0, 1), a] should throw an instance of TypeError
FAIL var a = arr(); [a.splice(0, 1), a] should throw an instance of TypeError
PASS 'use strict'; var a = arr(); [a.splice(0, 1), a] threw exception of type TypeError.
PASS var a = arr(); [a.splice(0, 1), a] threw exception of type TypeError.
PASS true === true
PASS 'use strict'; var o = obj(); [Array.prototype.splice.call(o, 0, 1), o] threw exception of type TypeError.
PASS var o = obj(); [Array.prototype.splice.call(o, 0, 1), o] threw exception of type TypeError.
PASS true === true
FAIL 'use strict'; var a = agap(); [a.splice(0, 1), a] should throw an instance of TypeError
FAIL var a = agap(); [a.splice(0, 1), a] should throw an instance of TypeError
PASS 'use strict'; var a = agap(); [a.splice(0, 1), a] threw exception of type TypeError.
PASS var a = agap(); [a.splice(0, 1), a] threw exception of type TypeError.
PASS true === true
FAIL 'use strict'; var o = ogap(); [Array.prototype.splice.call(o, 0, 1), o] should throw an instance of TypeError
FAIL var o = ogap(); [Array.prototype.splice.call(o, 0, 1), o] should throw an instance of TypeError
PASS 'use strict'; var o = ogap(); [Array.prototype.splice.call(o, 0, 1), o] threw exception of type TypeError.
PASS var o = ogap(); [Array.prototype.splice.call(o, 0, 1), o] threw exception of type TypeError.
PASS true === true
PASSED!
PASS successfullyParsed is true
......
FAIL 'use strict'; var a = arr(); [a.unshift(40, 50), a] should throw an instance of TypeError
FAIL var a = arr(); [a.unshift(40, 50), a] should throw an instance of TypeError
PASS 'use strict'; var a = arr(); [a.unshift(40, 50), a] threw exception of type TypeError.
PASS var a = arr(); [a.unshift(40, 50), a] threw exception of type TypeError.
PASS true === true
PASS 'use strict'; var o = obj(); [Array.prototype.unshift.call(o, 40, 50), o] threw exception of type TypeError.
PASS var o = obj(); [Array.prototype.unshift.call(o, 40, 50), o] threw exception of type TypeError.
PASS true === true
FAIL 'use strict'; var a = agap(); [a.unshift(9), a] should throw an instance of TypeError
FAIL var a = agap(); [a.unshift(9), a] should throw an instance of TypeError
PASS 'use strict'; var a = agap(); [a.unshift(9), a] threw exception of type TypeError.
PASS var a = agap(); [a.unshift(9), a] threw exception of type TypeError.
PASS true === true
FAIL 'use strict'; var o = ogap(); [Array.prototype.unshift.call(o, 9), o] should throw an instance of TypeError
FAIL var o = ogap(); [Array.prototype.unshift.call(o, 9), o] should throw an instance of TypeError
PASS 'use strict'; var o = ogap(); [Array.prototype.unshift.call(o, 9), o] threw exception of type TypeError.
PASS var o = ogap(); [Array.prototype.unshift.call(o, 9), o] threw exception of type TypeError.
PASS true === true
PASSED!
PASS successfullyParsed is true
......
PASS 'use strict'; var a = arr(); [a.pop(), a] threw exception of type TypeError.
PASS var a = arr(); [a.pop(), a] threw exception of type TypeError.
PASS true === true
FAIL 'use strict'; var o = obj(); [Array.prototype.pop.call(o), o] should throw an instance of TypeError
FAIL var o = obj(); [Array.prototype.pop.call(o), o] should throw an instance of TypeError
PASS 'use strict'; var o = obj(); [Array.prototype.pop.call(o), o] threw exception of type TypeError.
PASS var o = obj(); [Array.prototype.pop.call(o), o] threw exception of type TypeError.
PASS true === true
PASSED!
PASS successfullyParsed is true
......
......@@ -4,11 +4,11 @@ PASS true === true
PASS 'use strict'; var o = obj(); Array.prototype.reverse.call(o) threw exception of type TypeError.
PASS var o = obj(); Array.prototype.reverse.call(o) threw exception of type TypeError.
PASS true === true
FAIL 'use strict'; var a = agap(); a.reverse() should throw an instance of TypeError
FAIL var a = agap(); a.reverse() should throw an instance of TypeError
PASS 'use strict'; var a = agap(); a.reverse() threw exception of type TypeError.
PASS var a = agap(); a.reverse() threw exception of type TypeError.
PASS true === true
FAIL 'use strict'; var o = ogap(); Array.prototype.reverse.call(o) should throw an instance of TypeError
FAIL var o = ogap(); Array.prototype.reverse.call(o) should throw an instance of TypeError
PASS 'use strict'; var o = ogap(); Array.prototype.reverse.call(o) threw exception of type TypeError.
PASS var o = ogap(); Array.prototype.reverse.call(o) threw exception of type TypeError.
PASS true === true
PASSED!
PASS successfullyParsed is true
......
FAIL 'use strict'; var a = arr(); [a.shift(), a] should throw an instance of TypeError
FAIL var a = arr(); [a.shift(), a] should throw an instance of TypeError
PASS 'use strict'; var a = arr(); [a.shift(), a] threw exception of type TypeError.
PASS var a = arr(); [a.shift(), a] threw exception of type TypeError.
PASS true === true
PASS 'use strict'; var o = obj(); [Array.prototype.shift.call(o), o] threw exception of type TypeError.
PASS var o = obj(); [Array.prototype.shift.call(o), o] threw exception of type TypeError.
PASS true === true
FAIL 'use strict'; var a = agap(); [a.shift(), a] should throw an instance of TypeError
FAIL var a = agap(); [a.shift(), a] should throw an instance of TypeError
PASS 'use strict'; var a = agap(); [a.shift(), a] threw exception of type TypeError.
PASS var a = agap(); [a.shift(), a] threw exception of type TypeError.
PASS true === true
FAIL 'use strict'; var o = ogap(); [Array.prototype.shift.call(o), o] should throw an instance of TypeError
FAIL var o = ogap(); [Array.prototype.shift.call(o), o] should throw an instance of TypeError
PASS 'use strict'; var o = ogap(); [Array.prototype.shift.call(o), o] threw exception of type TypeError.
PASS var o = ogap(); [Array.prototype.shift.call(o), o] threw exception of type TypeError.
PASS true === true
PASSED!
PASS successfullyParsed is true
......
2012-03-06 Gavin Barraclough <barraclough@apple.com>
Array.prototype functions should throw if delete fails
https://bugs.webkit.org/show_bug.cgi?id=80467
Reviewed by Oliver Hunt.
All calls to [[Delete]] from Array.prototype are specified to pass 'true' as the value of Throw.
In the case of shift/unshift, these are also missing a throw from the 'put' in the implementations
in JSArray.cpp. There are effectively three copies of each of the generic shift/unshift routines,
one in splice, one in ArrayPrototype's shift/unshift methods, and one in JSArray's shift/unshift
routines, for handling arrays with holes. These three copies should be unified.
* runtime/ArrayPrototype.cpp:
(JSC::shift):
(JSC::unshift):
- Added - shared copies of the shift/unshift functionality.
(JSC::arrayProtoFuncPop):
- should throw if the delete fails.
(JSC::arrayProtoFuncReverse):
- should throw if the delete fails.
(JSC::arrayProtoFuncShift):
(JSC::arrayProtoFuncSplice):
(JSC::arrayProtoFuncUnShift):
- use shift/unshift.
* runtime/JSArray.cpp:
(JSC::JSArray::shiftCount):
(JSC::JSArray::unshiftCount):
- Don't try to handle arrays with holes; return a value indicating
the generic routine should be used instead.
* runtime/JSArray.h:
- declaration for shiftCount/unshiftCount changed.
* tests/mozilla/js1_6/Array/regress-304828.js:
- this was asserting incorrect behaviour.
2012-03-06 Raphael Kubo da Costa <kubo@profusion.mobi>
[CMake] Make the removal of transitive library dependencies work with CMake < 2.8.7.
......@@ -1309,7 +1309,7 @@ void JSArray::push(ExecState* exec, JSValue value)
checkConsistency();
}
void JSArray::shiftCount(ExecState* exec, unsigned count)
bool JSArray::shiftCount(ExecState*, unsigned count)
{
ASSERT(count > 0);
......@@ -1317,32 +1317,15 @@ void JSArray::shiftCount(ExecState* exec, unsigned count)
unsigned oldLength = storage->m_length;
if (!oldLength)
return;
if (oldLength != storage->m_numValuesInVector) {
// If m_length and m_numValuesInVector aren't the same, we have a sparse vector
// which means we need to go through each entry looking for the the "empty"
// slots and then fill them with possible properties. See ECMA spec.
// 15.4.4.9 steps 11 through 13.
for (unsigned i = count; i < oldLength; ++i) {
if ((i >= m_vectorLength) || (!m_storage->m_vector[i])) {
PropertySlot slot(this);
JSValue p = prototype();
if ((!p.isNull()) && (asObject(p)->getPropertySlot(exec, i, slot)))
methodTable()->putByIndex(this, exec, i, slot.getValue(exec, i), false); // FIXME https://bugs.webkit.org/show_bug.cgi?id=80335
}
}
storage = m_storage; // The put() above could have grown the vector and realloc'ed storage.
// If the array contains holes or is otherwise in an abnormal state,
// use the generic algorithm in ArrayPrototype.
if (oldLength != storage->m_numValuesInVector || inSparseMode())
return false;
// Need to decrement numValuesInvector based on number of real entries
for (unsigned i = 0; i < (unsigned)count; ++i)
if ((i < m_vectorLength) && (storage->m_vector[i]))
--storage->m_numValuesInVector;
} else
storage->m_numValuesInVector -= count;
if (!oldLength)
return true;
storage->m_numValuesInVector -= count;
storage->m_length -= count;
if (m_vectorLength) {
......@@ -1358,30 +1341,20 @@ void JSArray::shiftCount(ExecState* exec, unsigned count)
m_indexBias += count;
}
}
return true;
}
void JSArray::unshiftCount(ExecState* exec, unsigned count)
// Returns true if the unshift can be handled, false to fallback.
bool JSArray::unshiftCount(ExecState* exec, unsigned count)
{
ArrayStorage* storage = m_storage;
unsigned length = storage->m_length;
if (length != storage->m_numValuesInVector) {
// If m_length and m_numValuesInVector aren't the same, we have a sparse vector
// which means we need to go through each entry looking for the the "empty"
// slots and then fill them with possible properties. See ECMA spec.
// 15.4.4.13 steps 8 through 10.
for (unsigned i = 0; i < length; ++i) {
if ((i >= m_vectorLength) || (!m_storage->m_vector[i])) {
PropertySlot slot(this);
JSValue p = prototype();
if ((!p.isNull()) && (asObject(p)->getPropertySlot(exec, i, slot)))
methodTable()->putByIndex(this, exec, i, slot.getValue(exec, i), false); // FIXME https://bugs.webkit.org/show_bug.cgi?id=80335
}
}
}
storage = m_storage; // The put() above could have grown the vector and realloc'ed storage.
// If the array contains holes or is otherwise in an abnormal state,
// use the generic algorithm in ArrayPrototype.
if (length != storage->m_numValuesInVector || inSparseMode())
return false;
if (m_indexBias >= count) {
m_indexBias -= count;
char* newBaseStorage = reinterpret_cast<char*>(storage) - count * sizeof(WriteBarrier<Unknown>);
......@@ -1390,12 +1363,13 @@ void JSArray::unshiftCount(ExecState* exec, unsigned count)
m_vectorLength += count;
} else if (!unshiftCountSlowCase(exec->globalData(), count)) {
throwOutOfMemoryError(exec);
return;
return true;
}
WriteBarrier<Unknown>* vector = m_storage->m_vector;
for (unsigned i = 0; i < count; i++)
vector[i].clear();
return true;
}
void JSArray::visitChildren(JSCell* cell, SlotVisitor& visitor)
......
......@@ -187,8 +187,8 @@ namespace JSC {
void push(ExecState*, JSValue);
JSValue pop(ExecState*);
void shiftCount(ExecState*, unsigned count);
void unshiftCount(ExecState*, unsigned count);
bool shiftCount(ExecState*, unsigned count);
bool unshiftCount(ExecState*, unsigned count);
bool canGetIndex(unsigned i) { return i < m_vectorLength && m_storage->m_vector[i]; }
JSValue getIndex(unsigned i)
......
......@@ -100,7 +100,7 @@ reportCompare('abc', value, summary + ': push');
// pop
value = 'abc';
expect = 'c';
expect = 'TypeError: Unable to delete property.';
try
{
actual = Array.prototype.pop.call(value);
......@@ -128,7 +128,7 @@ reportCompare('def', value, summary + ': unshift');
// shift
value = 'abc';
expect = 'a';
expect = 'TypeError: Unable to delete property.';
try
{
actual = Array.prototype.shift.call(value);
......@@ -142,7 +142,7 @@ reportCompare('abc', value, summary + ': shift');
// splice
value = 'abc';
expect = 'b';
expect = 'TypeError: Unable to delete property.';
try
{
actual = Array.prototype.splice.call(value, 1, 1) + '';
......
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