Added: trunk/JSTests/stress/array-splice-on-frozen-object.js (0 => 207322)
--- trunk/JSTests/stress/array-splice-on-frozen-object.js (rev 0)
+++ trunk/JSTests/stress/array-splice-on-frozen-object.js 2016-10-14 05:29:02 UTC (rev 207322)
@@ -0,0 +1,72 @@
+//@ runFTLNoCJIT
+
+let totalFailed = 0;
+
+function shouldEqual(testId, actual, expected) {
+ if (actual != expected) {
+ throw testId + ": ERROR: expect " + expected + ", actual " + actual;
+ }
+}
+
+function makeArray() {
+ return ['unmodifiable'];
+}
+
+function makeArrayLikeObject() {
+ var obj = {};
+ obj[0] = 'unmodifiable';
+ obj.length = 1;
+ return obj;
+}
+
+function emptyArraySourceMaker() {
+ return [];
+}
+
+function singleElementArraySourceMaker() {
+ return ['modified_1'];
+}
+
+// Make test functions with unique codeblocks.
+function makeSpliceWithNoArgsTest(testId) {
+ return new Function("arr", "arr.splice(); return " + testId + ";");
+}
+function makeSpliceTest(testId) {
+ return new Function("arr", "arr.splice(0); return " + testId + ";");
+}
+
+let numIterations = 10000;
+
+function runTest(testId, testMaker, targetMaker, sourceMaker, expectedValue, expectedException) {
+ var test = testMaker(testId);
+ noInline(test);
+
+ for (var i = 0; i < numIterations; i++) {
+ var exception = undefined;
+
+ var obj = targetMaker();
+ obj = Object.freeze(obj);
+
+ var arr = sourceMaker();
+ arr.constructor = { [Symbol.species]: function() { return obj; } };
+
+ try {
+ test(arr);
+ } catch (e) {
+ exception = "" + e;
+ exception = exception.substr(0, 10); // Search for "TypeError:".
+ }
+ shouldEqual(testId, exception, expectedException);
+ shouldEqual(testId, obj[0], expectedValue);
+ }
+}
+
+runTest(10010, makeSpliceWithNoArgsTest, makeArray, emptyArraySourceMaker, "unmodifiable", "TypeError:");
+runTest(10011, makeSpliceWithNoArgsTest, makeArray, singleElementArraySourceMaker, "unmodifiable", "TypeError:");
+runTest(10020, makeSpliceWithNoArgsTest, makeArrayLikeObject, emptyArraySourceMaker, "unmodifiable", "TypeError:");
+runTest(10021, makeSpliceWithNoArgsTest, makeArrayLikeObject, singleElementArraySourceMaker, "unmodifiable", "TypeError:");
+
+runTest(10110, makeSpliceTest, makeArray, emptyArraySourceMaker, "unmodifiable", "TypeError:");
+runTest(10111, makeSpliceTest, makeArray, singleElementArraySourceMaker, "unmodifiable", "TypeError:");
+runTest(10120, makeSpliceTest, makeArrayLikeObject, emptyArraySourceMaker, "unmodifiable", "TypeError:");
+runTest(10121, makeSpliceTest, makeArrayLikeObject, singleElementArraySourceMaker, "unmodifiable", "TypeError:");
Modified: trunk/Source/_javascript_Core/runtime/ArrayPrototype.cpp (207321 => 207322)
--- trunk/Source/_javascript_Core/runtime/ArrayPrototype.cpp 2016-10-14 04:09:33 UTC (rev 207321)
+++ trunk/Source/_javascript_Core/runtime/ArrayPrototype.cpp 2016-10-14 05:29:02 UTC (rev 207322)
@@ -922,9 +922,12 @@
}
unsigned actualStart = argumentClampedIndexFromStartOrEnd(exec, 0, length);
+ RETURN_IF_EXCEPTION(scope, encodedJSValue());
unsigned actualDeleteCount = length - actualStart;
+ unsigned insertCount = 0;
if (exec->argumentCount() > 1) {
+ insertCount = exec->argumentCount() - 2;
double deleteCount = exec->uncheckedArgument(1).toInteger(exec);
if (deleteCount < 0)
actualDeleteCount = 0;
@@ -934,9 +937,13 @@
actualDeleteCount = static_cast<unsigned>(deleteCount);
}
+ // FIXME: Need to implement step 8 of the spec https://tc39.github.io/ecma262/#sec-array.prototype.splice here.
+ // https://bugs.webkit.org/show_bug.cgi?id=163417
+
std::pair<SpeciesConstructResult, JSObject*> speciesResult = speciesConstructArray(exec, thisObj, actualDeleteCount);
+ ASSERT(!scope.exception() || speciesResult.first == SpeciesConstructResult::Exception);
if (speciesResult.first == SpeciesConstructResult::Exception)
- return JSValue::encode(jsUndefined());
+ return encodedJSValue();
JSObject* result = nullptr;
if (speciesResult.first == SpeciesConstructResult::FastPath && isJSArray(thisObj) && length == getLength(exec, thisObj))
@@ -966,10 +973,14 @@
continue;
result->initializeIndex(vm, k, v);
}
+ ASSERT(!scope.exception());
}
+ setLength(exec, vm, result, actualDeleteCount);
+ RETURN_IF_EXCEPTION(scope, encodedJSValue());
}
- unsigned itemCount = std::max<int>(exec->argumentCount() - 2, 0);
+ unsigned itemCount = insertCount;
+ ASSERT(itemCount == static_cast<unsigned>(std::max<int>(exec->argumentCount() - 2, 0)));
if (itemCount < actualDeleteCount) {
shift<JSArray::ShiftCountForSplice>(exec, thisObj, actualStart, actualDeleteCount, itemCount, length);
RETURN_IF_EXCEPTION(scope, encodedJSValue());