Commit b1db28d8 authored by barraclough@apple.com's avatar barraclough@apple.com

putByIndex should throw in strict mode

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

Reviewed by Filip Pizlo.

Make the MethodTable PutByIndex trap take a boolean 'shouldThrow' parameter.

Source/JavaScriptCore: 

This is a largely mechanical change, simply adding an extra parameter to a number
of functions. Some call sites need perform additional exception checks, and
operationPutByValBeyondArrayBounds needs to know whether it is strict or not.

This patch doesn't fix a missing throw from some cases of shift/unshift (this is
an existing bug), I'll follow up with a third patch to handle that.

* API/JSObjectRef.cpp:
(JSObjectSetPropertyAtIndex):
* JSCTypedArrayStubs.h:
(JSC):
* dfg/DFGOperations.cpp:
(JSC::DFG::putByVal):
* dfg/DFGOperations.h:
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* interpreter/Interpreter.cpp:
(JSC::Interpreter::privateExecute):
* jit/JITStubs.cpp:
(JSC::DEFINE_STUB_FUNCTION):
* jsc.cpp:
(GlobalObject::finishCreation):
* llint/LLIntSlowPaths.cpp:
(JSC::LLInt::LLINT_SLOW_PATH_DECL):
* runtime/Arguments.cpp:
(JSC::Arguments::putByIndex):
* runtime/Arguments.h:
(Arguments):
* runtime/ArrayPrototype.cpp:
(JSC::arrayProtoFuncPush):
(JSC::arrayProtoFuncReverse):
(JSC::arrayProtoFuncShift):
(JSC::arrayProtoFuncSort):
(JSC::arrayProtoFuncSplice):
(JSC::arrayProtoFuncUnShift):
* runtime/ClassInfo.h:
(MethodTable):
* runtime/JSArray.cpp:
(JSC::SparseArrayValueMap::put):
(JSC::JSArray::put):
(JSC::JSArray::putByIndex):
(JSC::JSArray::putByIndexBeyondVectorLength):
(JSC::JSArray::push):
(JSC::JSArray::shiftCount):
(JSC::JSArray::unshiftCount):
* runtime/JSArray.h:
(SparseArrayValueMap):
(JSArray):
* runtime/JSByteArray.cpp:
(JSC::JSByteArray::putByIndex):
* runtime/JSByteArray.h:
(JSByteArray):
* runtime/JSCell.cpp:
(JSC::JSCell::putByIndex):
* runtime/JSCell.h:
(JSCell):
* runtime/JSNotAnObject.cpp:
(JSC::JSNotAnObject::putByIndex):
* runtime/JSNotAnObject.h:
(JSNotAnObject):
* runtime/JSONObject.cpp:
(JSC::Walker::walk):
* runtime/JSObject.cpp:
(JSC::JSObject::putByIndex):
* runtime/JSObject.h:
(JSC::JSValue::putByIndex):
* runtime/RegExpConstructor.cpp:
(JSC::RegExpMatchesArray::fillArrayInstance):
* runtime/RegExpMatchesArray.h:
(JSC::RegExpMatchesArray::putByIndex):
* runtime/StringPrototype.cpp:
(JSC::stringProtoFuncSplit):

Source/WebCore: 

* bindings/js/SerializedScriptValue.cpp:
(WebCore::CloneDeserializer::putProperty):
* bindings/objc/WebScriptObject.mm:
(-[WebScriptObject setWebScriptValueAtIndex:value:]):
* bindings/scripts/CodeGeneratorJS.pm:
(GenerateHeader):
(GenerateImplementation):
* bridge/NP_jsobject.cpp:
(_NPN_SetProperty):
* bridge/jni/jni_jsobject.mm:
(JavaJSObject::setSlot):
* bridge/runtime_array.cpp:
(JSC::RuntimeArray::putByIndex):
* bridge/runtime_array.h:
(RuntimeArray):

Source/WebKit/mac: 

* Plugins/Hosted/NetscapePluginInstanceProxy.mm:
(WebKit::NetscapePluginInstanceProxy::setProperty):

Source/WebKit2: 

* WebProcess/Plugins/Netscape/NPJSObject.cpp:
(WebKit::NPJSObject::setProperty):

LayoutTests: 

* fast/js/Object-defineProperty-expected.txt:
* 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.8-expected.txt:
* fast/js/mozilla/strict/15.4.4.9-expected.txt:
* fast/js/mozilla/strict/15.5.5.2-expected.txt:
* fast/js/mozilla/strict/8.12.5-expected.txt:
* fast/js/preventExtensions-expected.txt:
* fast/js/primitive-property-access-edge-cases-expected.txt:
    - Checking in passing test results.
* fast/js/script-tests/Object-defineProperty.js:
    - Added test cases for putting to numeric properties where property is read-only,
      length is read-only, or property is accessor with missing set function.
* fast/js/script-tests/preventExtensions.js:
    - Added test case, putting numeric property to non-extensible array.
* fast/js/script-tests/primitive-property-access-edge-cases.js:
    - Enabled test cases for putting numeric properties to primitive strings.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@109866 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent ca4ea14f
2012-03-05 Gavin Barraclough <barraclough@apple.com>
putByIndex should throw in strict mode
https://bugs.webkit.org/show_bug.cgi?id=80335
Reviewed by Filip Pizlo.
Make the MethodTable PutByIndex trap take a boolean 'shouldThrow' parameter.
* fast/js/Object-defineProperty-expected.txt:
* 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.8-expected.txt:
* fast/js/mozilla/strict/15.4.4.9-expected.txt:
* fast/js/mozilla/strict/15.5.5.2-expected.txt:
* fast/js/mozilla/strict/8.12.5-expected.txt:
* fast/js/preventExtensions-expected.txt:
* fast/js/primitive-property-access-edge-cases-expected.txt:
- Checking in passing test results.
* fast/js/script-tests/Object-defineProperty.js:
- Added test cases for putting to numeric properties where property is read-only,
length is read-only, or property is accessor with missing set function.
* fast/js/script-tests/preventExtensions.js:
- Added test case, putting numeric property to non-extensible array.
* fast/js/script-tests/primitive-property-access-edge-cases.js:
- Enabled test cases for putting numeric properties to primitive strings.
2012-03-05 Adrienne Walker <enne@google.com>
Compositing overlap testing can throw layers into compositing when they should not be.
......@@ -119,6 +119,12 @@ PASS 'use strict'; var o = {}; o.readOnly = false; o.readOnly threw exception Ty
PASS Object.getOwnPropertyDescriptor(Object.defineProperty(Object.defineProperty({}, 'foo', {get: function() { return false; }, configurable: true}), 'foo', {value:false}), 'foo').writable is false
PASS Object.getOwnPropertyDescriptor(Object.defineProperty(Object.defineProperty({}, 'foo', {get: function() { return false; }, configurable: true}), 'foo', {value:false, writable: false}), 'foo').writable is false
PASS Object.getOwnPropertyDescriptor(Object.defineProperty(Object.defineProperty({}, 'foo', {get: function() { return false; }, configurable: true}), 'foo', {value:false, writable: true}), 'foo').writable is true
PASS var a = Object.defineProperty([], 'length', {writable: false}); a[0] = 42; 0 in a; is false
PASS 'use strict'; var a = Object.defineProperty([], 'length', {writable: false}); a[0] = 42; 0 in a; threw exception TypeError: Attempted to assign to readonly property..
PASS var a = Object.defineProperty([42], '0', {writable: false}); a[0] = false; a[0]; is 42
PASS 'use strict'; var a = Object.defineProperty([42], '0', {writable: false}); a[0] = false; a[0]; threw exception TypeError: Attempted to assign to readonly property..
PASS var a = Object.defineProperty([], '0', {set: undefined}); a[0] = 42; a[0]; is undefined.
PASS 'use strict'; var a = Object.defineProperty([], '0', {set: undefined}); a[0] = 42; a[0]; threw exception TypeError: Attempted to assign to readonly property..
PASS successfullyParsed is true
TEST COMPLETE
......
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 true === true
FAIL 'use strict'; var o = obj(); [Array.prototype.splice.call(o, 0, 1), o] should throw an instance of TypeError
FAIL var o = obj(); [Array.prototype.splice.call(o, 0, 1), o] should throw an instance of TypeError
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
......
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 true === true
FAIL 'use strict'; var o = obj(); [Array.prototype.unshift.call(o, 40, 50), o] should throw an instance of TypeError
FAIL var o = obj(); [Array.prototype.unshift.call(o, 40, 50), o] should throw an instance of TypeError
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
......
FAIL 'use strict'; var a = arr(); a.reverse() should throw an instance of TypeError
FAIL var a = arr(); a.reverse() should throw an instance of TypeError
PASS 'use strict'; var a = arr(); a.reverse() threw exception of type TypeError.
PASS var a = arr(); a.reverse() threw exception of type TypeError.
PASS true === true
FAIL 'use strict'; var o = obj(); Array.prototype.reverse.call(o) should throw an instance of TypeError
FAIL var o = obj(); Array.prototype.reverse.call(o) should throw an instance of TypeError
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
......
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 true === true
FAIL 'use strict'; var o = obj(); [Array.prototype.shift.call(o), o] should throw an instance of TypeError
FAIL var o = obj(); [Array.prototype.shift.call(o), o] should throw an instance of TypeError
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
......
FAIL 'use strict'; "foo"[0] = 1 should throw an instance of TypeError
PASS 'use strict'; "foo"[0] = 1 threw exception of type TypeError.
PASS "foo"[0] = 1 is 1
PASS true === true
PASS 'use strict'; delete "foo"[0] threw exception of type TypeError.
......
......@@ -25,25 +25,25 @@ PASS true === true
PASS 'use strict'; var a = arr(); a[0] = 2; a[0] is 2
PASS var a = arr(); a[0] = 2; a[0] is 2
PASS true === true
FAIL 'use strict'; var a = arr(); a[1] = 2; a[1] should throw an instance of TypeError
PASS 'use strict'; var a = arr(); a[1] = 2; a[1] threw exception of type TypeError.
PASS var a = arr(); a[1] = 2; a[1] is 1
PASS true === true
PASS 'use strict'; var a = arr(); a[2] = 2; a[2] is 2
PASS var a = arr(); a[2] = 2; a[2] is 2
PASS true === true
FAIL 'use strict'; var a = arr(); a[3] = 2; a[3] should throw an instance of TypeError
PASS 'use strict'; var a = arr(); a[3] = 2; a[3] threw exception of type TypeError.
PASS var a = arr(); a[3] = 2; a[3] is 1
PASS true === true
FAIL 'use strict'; arr()[1]++ should throw an instance of TypeError
PASS 'use strict'; arr()[1]++ threw exception of type TypeError.
PASS arr()[1]++ is 1
PASS true === true
FAIL 'use strict'; ++arr()[1] should throw an instance of TypeError
PASS 'use strict'; ++arr()[1] threw exception of type TypeError.
PASS ++arr()[1] is 2
PASS true === true
FAIL 'use strict'; arr()[1]-- should throw an instance of TypeError
PASS 'use strict'; arr()[1]-- threw exception of type TypeError.
PASS arr()[1]-- is 1
PASS true === true
FAIL 'use strict'; --arr()[1] should throw an instance of TypeError
PASS 'use strict'; --arr()[1] threw exception of type TypeError.
PASS --arr()[1] is 0
PASS true === true
PASSED!
......
......@@ -16,6 +16,7 @@ PASS "use strict"; var o = {}; Object.preventExtensions(o); o.__proto__ = { newP
PASS Object.preventExtensions(Math); Math.sqrt(4) is 2
PASS var arr = Object.preventExtensions([]); arr[0] = 42; arr[0] is undefined.
PASS var arr = Object.preventExtensions([]); arr[0] = 42; arr.length is 0
PASS "use strict"; var arr = Object.preventExtensions([]); arr[0] = 42; arr[0] threw exception TypeError: Attempted to assign to readonly property..
PASS obj.foo is 1
PASS array[0] is 0
PASS Object.getOwnPropertyDescriptor(array, "length").writable is false
......
......@@ -37,6 +37,7 @@ PASS checkNumericGetStrict(1, Number) is true
PASS checkNumericGetStrict('hello', String) is true
PASS checkNumericGetStrict(true, Boolean) is true
PASS checkNumericSetStrict(1, Number) is true
PASS checkNumericSetStrict('hello', String) is true
PASS checkNumericSetStrict(true, Boolean) is true
PASS checkNumericRead(1, Number) is true
PASS checkNumericRead('hello', String) is true
......@@ -48,6 +49,7 @@ PASS checkNumericReadStrict(1, Number) is true
PASS checkNumericReadStrict('hello', String) is true
PASS checkNumericReadStrict(true, Boolean) is true
PASS checkNumericWriteStrict(1, Number) threw exception TypeError: Attempted to assign to readonly property..
PASS checkNumericWriteStrict('hello', String) threw exception TypeError: Attempted to assign to readonly property..
PASS checkNumericWriteStrict(true, Boolean) threw exception TypeError: Attempted to assign to readonly property..
PASS didNotCrash is true
PASS successfullyParsed is true
......
......@@ -171,3 +171,15 @@ delete Object.prototype.readOnly;
shouldBeFalse("Object.getOwnPropertyDescriptor(Object.defineProperty(Object.defineProperty({}, 'foo', {get: function() { return false; }, configurable: true}), 'foo', {value:false}), 'foo').writable");
shouldBeFalse("Object.getOwnPropertyDescriptor(Object.defineProperty(Object.defineProperty({}, 'foo', {get: function() { return false; }, configurable: true}), 'foo', {value:false, writable: false}), 'foo').writable");
shouldBeTrue("Object.getOwnPropertyDescriptor(Object.defineProperty(Object.defineProperty({}, 'foo', {get: function() { return false; }, configurable: true}), 'foo', {value:false, writable: true}), 'foo').writable");
// If array length is read-only, [[Put]] should fail.
shouldBeFalse("var a = Object.defineProperty([], 'length', {writable: false}); a[0] = 42; 0 in a;");
shouldThrow("'use strict'; var a = Object.defineProperty([], 'length', {writable: false}); a[0] = 42; 0 in a;");
// If array property is read-only, [[Put]] should fail.
shouldBe("var a = Object.defineProperty([42], '0', {writable: false}); a[0] = false; a[0];", '42');
shouldThrow("'use strict'; var a = Object.defineProperty([42], '0', {writable: false}); a[0] = false; a[0];");
// If array property is an undefined setter, [[Put]] should fail.
shouldBeUndefined("var a = Object.defineProperty([], '0', {set: undefined}); a[0] = 42; a[0];");
shouldThrow("'use strict'; var a = Object.defineProperty([], '0', {set: undefined}); a[0] = 42; a[0];");
......@@ -78,6 +78,8 @@ shouldBe('Object.preventExtensions(Math); Math.sqrt(4)', '2');
// Should not be able to add properties to a preventExtensions array.
shouldBeUndefined('var arr = Object.preventExtensions([]); arr[0] = 42; arr[0]');
shouldBe('var arr = Object.preventExtensions([]); arr[0] = 42; arr.length', '0');
// In strict mode, this throws.
shouldThrow('"use strict"; var arr = Object.preventExtensions([]); arr[0] = 42; arr[0]');
// A read-only property on the prototype should prevent a [[Put]] .
function Constructor() {}
......
......@@ -172,7 +172,7 @@ shouldBeTrue("checkNumericGetStrict(1, Number)");
shouldBeTrue("checkNumericGetStrict('hello', String)");
shouldBeTrue("checkNumericGetStrict(true, Boolean)");
shouldBeTrue("checkNumericSetStrict(1, Number)");
//shouldBeTrue("checkNumericSetStrict('hello', String)"); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=80335
shouldBeTrue("checkNumericSetStrict('hello', String)");
shouldBeTrue("checkNumericSetStrict(true, Boolean)");
function checkNumericRead(x, constructor)
......@@ -209,7 +209,7 @@ shouldBeTrue("checkNumericReadStrict(1, Number)");
shouldBeTrue("checkNumericReadStrict('hello', String)");
shouldBeTrue("checkNumericReadStrict(true, Boolean)");
shouldThrow("checkNumericWriteStrict(1, Number)");
//shouldThrow("checkNumericWriteStrict('hello', String)"); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=80335
shouldThrow("checkNumericWriteStrict('hello', String)");
shouldThrow("checkNumericWriteStrict(true, Boolean)");
shouldBeTrue("didNotCrash");
......@@ -312,7 +312,7 @@ void JSObjectSetPropertyAtIndex(JSContextRef ctx, JSObjectRef object, unsigned p
JSObject* jsObject = toJS(object);
JSValue jsValue = toJS(exec, value);
jsObject->methodTable()->putByIndex(jsObject, exec, propertyIndex, jsValue);
jsObject->methodTable()->putByIndex(jsObject, exec, propertyIndex, jsValue, false);
if (exec->hadException()) {
if (exception)
*exception = toRef(exec, exec->exception());
......
2012-03-05 Gavin Barraclough <barraclough@apple.com>
putByIndex should throw in strict mode
https://bugs.webkit.org/show_bug.cgi?id=80335
Reviewed by Filip Pizlo.
Make the MethodTable PutByIndex trap take a boolean 'shouldThrow' parameter.
This is a largely mechanical change, simply adding an extra parameter to a number
of functions. Some call sites need perform additional exception checks, and
operationPutByValBeyondArrayBounds needs to know whether it is strict or not.
This patch doesn't fix a missing throw from some cases of shift/unshift (this is
an existing bug), I'll follow up with a third patch to handle that.
* API/JSObjectRef.cpp:
(JSObjectSetPropertyAtIndex):
* JSCTypedArrayStubs.h:
(JSC):
* dfg/DFGOperations.cpp:
(JSC::DFG::putByVal):
* dfg/DFGOperations.h:
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* interpreter/Interpreter.cpp:
(JSC::Interpreter::privateExecute):
* jit/JITStubs.cpp:
(JSC::DEFINE_STUB_FUNCTION):
* jsc.cpp:
(GlobalObject::finishCreation):
* llint/LLIntSlowPaths.cpp:
(JSC::LLInt::LLINT_SLOW_PATH_DECL):
* runtime/Arguments.cpp:
(JSC::Arguments::putByIndex):
* runtime/Arguments.h:
(Arguments):
* runtime/ArrayPrototype.cpp:
(JSC::arrayProtoFuncPush):
(JSC::arrayProtoFuncReverse):
(JSC::arrayProtoFuncShift):
(JSC::arrayProtoFuncSort):
(JSC::arrayProtoFuncSplice):
(JSC::arrayProtoFuncUnShift):
* runtime/ClassInfo.h:
(MethodTable):
* runtime/JSArray.cpp:
(JSC::SparseArrayValueMap::put):
(JSC::JSArray::put):
(JSC::JSArray::putByIndex):
(JSC::JSArray::putByIndexBeyondVectorLength):
(JSC::JSArray::push):
(JSC::JSArray::shiftCount):
(JSC::JSArray::unshiftCount):
* runtime/JSArray.h:
(SparseArrayValueMap):
(JSArray):
* runtime/JSByteArray.cpp:
(JSC::JSByteArray::putByIndex):
* runtime/JSByteArray.h:
(JSByteArray):
* runtime/JSCell.cpp:
(JSC::JSCell::putByIndex):
* runtime/JSCell.h:
(JSCell):
* runtime/JSNotAnObject.cpp:
(JSC::JSNotAnObject::putByIndex):
* runtime/JSNotAnObject.h:
(JSNotAnObject):
* runtime/JSONObject.cpp:
(JSC::Walker::walk):
* runtime/JSObject.cpp:
(JSC::JSObject::putByIndex):
* runtime/JSObject.h:
(JSC::JSValue::putByIndex):
* runtime/RegExpConstructor.cpp:
(JSC::RegExpMatchesArray::fillArrayInstance):
* runtime/RegExpMatchesArray.h:
(JSC::RegExpMatchesArray::putByIndex):
* runtime/StringPrototype.cpp:
(JSC::stringProtoFuncSplit):
2012-03-05 Yuqiang Xian <yuqiang.xian@intel.com>
PredictNone is incorrectly treated as isDoublePrediction
......@@ -151,7 +151,7 @@ void JS##name##Array::indexSetter(JSC::ExecState* exec, unsigned index, JSC::JSV
m_impl->set(index, value.toNumber(exec));\
}\
\
void JS##name##Array::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, JSValue value)\
void JS##name##Array::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, JSValue value, bool)\
{\
JS##name##Array* thisObject = jsCast<JS##name##Array*>(cell);\
ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);\
......
......@@ -158,7 +158,7 @@ static inline void putByVal(ExecState* exec, JSValue baseValue, uint32_t index,
return;
}
JSArray::putByIndex(array, exec, index, value);
JSArray::putByIndex(array, exec, index, value, strict);
return;
}
......@@ -474,14 +474,24 @@ void DFG_OPERATION operationPutByValCellNonStrict(ExecState* exec, JSCell* cell,
operationPutByValInternal<false>(exec, JSValue::encode(cell), encodedProperty, encodedValue);
}
void DFG_OPERATION operationPutByValBeyondArrayBounds(ExecState* exec, JSArray* array, int32_t index, EncodedJSValue encodedValue)
void DFG_OPERATION operationPutByValBeyondArrayBoundsStrict(ExecState* exec, JSArray* array, int32_t index, EncodedJSValue encodedValue)
{
JSGlobalData* globalData = &exec->globalData();
NativeCallFrameTracer tracer(globalData, exec);
// We should only get here if index is outside the existing vector.
ASSERT(!array->canSetIndex(index));
JSArray::putByIndex(array, exec, index, JSValue::decode(encodedValue));
JSArray::putByIndex(array, exec, index, JSValue::decode(encodedValue), true);
}
void DFG_OPERATION operationPutByValBeyondArrayBoundsNonStrict(ExecState* exec, JSArray* array, int32_t index, EncodedJSValue encodedValue)
{
JSGlobalData* globalData = &exec->globalData();
NativeCallFrameTracer tracer(globalData, exec);
// We should only get here if index is outside the existing vector.
ASSERT(!array->canSetIndex(index));
JSArray::putByIndex(array, exec, index, JSValue::decode(encodedValue), false);
}
EncodedJSValue DFG_OPERATION operationArrayPush(ExecState* exec, EncodedJSValue encodedValue, JSArray* array)
......
......@@ -119,7 +119,8 @@ void DFG_OPERATION operationPutByValStrict(ExecState*, EncodedJSValue encodedBas
void DFG_OPERATION operationPutByValNonStrict(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue);
void DFG_OPERATION operationPutByValCellStrict(ExecState*, JSCell*, EncodedJSValue encodedProperty, EncodedJSValue encodedValue);
void DFG_OPERATION operationPutByValCellNonStrict(ExecState*, JSCell*, EncodedJSValue encodedProperty, EncodedJSValue encodedValue);
void DFG_OPERATION operationPutByValBeyondArrayBounds(ExecState*, JSArray*, int32_t index, EncodedJSValue encodedValue);
void DFG_OPERATION operationPutByValBeyondArrayBoundsStrict(ExecState*, JSArray*, int32_t index, EncodedJSValue encodedValue);
void DFG_OPERATION operationPutByValBeyondArrayBoundsNonStrict(ExecState*, JSArray*, int32_t index, EncodedJSValue encodedValue);
EncodedJSValue DFG_OPERATION operationArrayPush(ExecState*, EncodedJSValue encodedValue, JSArray*);
EncodedJSValue DFG_OPERATION operationArrayPop(ExecState*, JSArray*);
void DFG_OPERATION operationPutByIdStrict(ExecState*, EncodedJSValue encodedValue, JSCell* base, Identifier*);
......
......@@ -2379,7 +2379,7 @@ void SpeculativeJIT::compile(Node& node)
// Code to handle put beyond array bounds.
silentSpillAllRegisters(scratchReg);
callOperation(operationPutByValBeyondArrayBounds, baseReg, propertyReg, valueTagReg, valuePayloadReg);
callOperation(m_jit.codeBlock()->isStrictMode() ? operationPutByValBeyondArrayBoundsStrict : operationPutByValBeyondArrayBoundsNonStrict, baseReg, propertyReg, valueTagReg, valuePayloadReg);
silentFillAllRegisters(scratchReg);
JITCompiler::Jump wasBeyondArrayBounds = m_jit.jump();
......
......@@ -2425,7 +2425,7 @@ void SpeculativeJIT::compile(Node& node)
// Code to handle put beyond array bounds.
silentSpillAllRegisters(scratchReg);
callOperation(operationPutByValBeyondArrayBounds, baseReg, propertyReg, valueReg);
callOperation(m_jit.codeBlock()->isStrictMode() ? operationPutByValBeyondArrayBoundsStrict : operationPutByValBeyondArrayBoundsNonStrict, baseReg, propertyReg, valueReg);
silentFillAllRegisters(scratchReg);
JITCompiler::Jump wasBeyondArrayBounds = m_jit.jump();
......
......@@ -3777,7 +3777,7 @@ skip_id_custom_self:
if (jsArray->canSetIndex(i))
jsArray->setIndex(*globalData, i, callFrame->r(value).jsValue());
else
jsArray->JSArray::putByIndex(jsArray, callFrame, i, callFrame->r(value).jsValue());
jsArray->JSArray::putByIndex(jsArray, callFrame, i, callFrame->r(value).jsValue(), codeBlock->isStrictMode());
} else if (isJSByteArray(baseValue) && asByteArray(baseValue)->canAccessIndex(i)) {
JSByteArray* jsByteArray = asByteArray(baseValue);
JSValue jsValue = callFrame->r(value).jsValue();
......
......@@ -2553,7 +2553,7 @@ DEFINE_STUB_FUNCTION(void, op_put_by_val)
if (jsArray->canSetIndex(i))
jsArray->setIndex(*globalData, i, value);
else
JSArray::putByIndex(jsArray, callFrame, i, value);
JSArray::putByIndex(jsArray, callFrame, i, value, callFrame->codeBlock()->isStrictMode());
} else if (isJSByteArray(baseValue) && asByteArray(baseValue)->canAccessIndex(i)) {
JSByteArray* jsByteArray = asByteArray(baseValue);
ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_put_by_val_byte_array));
......
......@@ -206,9 +206,9 @@ protected:
addConstructableFunction(globalData, "Float64Array", constructJSFloat64Array, 1);
#endif
JSObject* array = constructEmptyArray(globalExec());
JSArray* array = constructEmptyArray(globalExec());
for (size_t i = 0; i < arguments.size(); ++i)
array->methodTable()->putByIndex(array, globalExec(), i, jsString(globalExec(), arguments[i]));
array->putDirectIndex(globalExec(), i, jsString(globalExec(), arguments[i]), false);
putDirect(globalData, Identifier(globalExec(), "arguments"), array);
}
......
......@@ -1044,7 +1044,7 @@ LLINT_SLOW_PATH_DECL(slow_path_put_by_val)
if (jsArray->canSetIndex(i))
jsArray->setIndex(globalData, i, value);
else
JSArray::putByIndex(jsArray, exec, i, value);
JSArray::putByIndex(jsArray, exec, i, value, exec->codeBlock()->isStrictMode());
LLINT_END();
}
if (isJSByteArray(baseValue)
......
......@@ -196,7 +196,7 @@ void Arguments::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyN
JSObject::getOwnPropertyNames(thisObject, exec, propertyNames, mode);
}
void Arguments::putByIndex(JSCell* cell, ExecState* exec, unsigned i, JSValue value)
void Arguments::putByIndex(JSCell* cell, ExecState* exec, unsigned i, JSValue value, bool shouldThrow)
{
Arguments* thisObject = jsCast<Arguments*>(cell);
if (i < static_cast<unsigned>(thisObject->d->numArguments) && (!thisObject->d->deletedArguments || !thisObject->d->deletedArguments[i])) {
......@@ -204,7 +204,7 @@ void Arguments::putByIndex(JSCell* cell, ExecState* exec, unsigned i, JSValue va
return;
}
PutPropertySlot slot;
PutPropertySlot slot(shouldThrow);
JSObject::put(thisObject, exec, Identifier(exec, UString::number(i)), value, slot);
}
......
......@@ -114,7 +114,7 @@ namespace JSC {
static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&);
static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
static void put(JSCell*, ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue);
static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow);
static bool deleteProperty(JSCell*, ExecState*, const Identifier& propertyName);
static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName);
static bool defineOwnProperty(JSObject*, ExecState*, const Identifier& propertyName, PropertyDescriptor&, bool shouldThrow);
......
......@@ -426,12 +426,14 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncPush(ExecState* exec)
for (unsigned n = 0; n < exec->argumentCount(); n++) {
// Check for integer overflow; where safe we can do a fast put by index.
if (length + n >= length)
thisObj->methodTable()->putByIndex(thisObj, exec, length + n, exec->argument(n));
thisObj->methodTable()->putByIndex(thisObj, exec, length + n, exec->argument(n), true);
else {
PutPropertySlot slot;
Identifier propertyName(exec, JSValue(static_cast<int64_t>(length) + static_cast<int64_t>(n)).toString(exec)->value(exec));
thisObj->methodTable()->put(thisObj, exec, propertyName, exec->argument(n), slot);
}
if (exec->hadException())
return JSValue::encode(jsUndefined());
}
JSValue newLength(static_cast<int64_t>(length) + static_cast<int64_t>(exec->argumentCount()));
putProperty(exec, thisObj, exec->propertyNames().length, newLength);
......@@ -456,14 +458,18 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncReverse(ExecState* exec)
return JSValue::encode(jsUndefined());
if (obj2)
thisObj->methodTable()->putByIndex(thisObj, exec, k, obj2);
thisObj->methodTable()->putByIndex(thisObj, exec, k, obj2, true);
else
thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, k);
if (exec->hadException())
return JSValue::encode(jsUndefined());
if (obj)
thisObj->methodTable()->putByIndex(thisObj, exec, lk1, obj);
thisObj->methodTable()->putByIndex(thisObj, exec, lk1, obj, true);
else
thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, lk1);
if (exec->hadException())
return JSValue::encode(jsUndefined());
}
return JSValue::encode(thisObj);
}
......@@ -489,9 +495,11 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncShift(ExecState* exec)
if (exec->hadException())
return JSValue::encode(jsUndefined());
if (obj)
thisObj->methodTable()->putByIndex(thisObj, exec, k - 1, obj);
thisObj->methodTable()->putByIndex(thisObj, exec, k - 1, obj, true);
else
thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, k - 1);
if (exec->hadException())
return JSValue::encode(jsUndefined());
}
thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, length - 1);
}
......@@ -580,8 +588,12 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSort(ExecState* exec)
}
// Swap themin and i
if (themin > i) {
thisObj->methodTable()->putByIndex(thisObj, exec, i, minObj);
thisObj->methodTable()->putByIndex(thisObj, exec, themin, iObj);
thisObj->methodTable()->putByIndex(thisObj, exec, i, minObj, true);
if (exec->hadException())
return JSValue::encode(jsUndefined());
thisObj->methodTable()->putByIndex(thisObj, exec, themin, iObj, true);
if (exec->hadException())
return JSValue::encode(jsUndefined());
}
}
return JSValue::encode(thisObj);
......@@ -637,9 +649,11 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState* exec)
if (exec->hadException())
return JSValue::encode(jsUndefined());
if (v)
thisObj->methodTable()->putByIndex(thisObj, exec, k + additionalArgs, v);
thisObj->methodTable()->putByIndex(thisObj, exec, k + additionalArgs, v, true);
else
thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, k + additionalArgs);
if (exec->hadException())
return JSValue::encode(jsUndefined());
}
for (unsigned k = length; k > length - deleteCount + additionalArgs; --k)
thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, k - 1);
......@@ -653,15 +667,20 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState* exec)
if (exec->hadException())
return JSValue::encode(jsUndefined());
if (obj)
thisObj->methodTable()->putByIndex(thisObj, exec, k + additionalArgs - 1, obj);
thisObj->methodTable()->putByIndex(thisObj, exec, k + additionalArgs - 1, obj, true);
else
thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, k + additionalArgs - 1);
if (exec->hadException())
return JSValue::encode(jsUndefined());
}
}
}
}
for (unsigned k = 0; k < additionalArgs; ++k)
thisObj->methodTable()->putByIndex(thisObj, exec, k + begin, exec->argument(k + 2));
for (unsigned k = 0; k < additionalArgs; ++k) {
thisObj->methodTable()->putByIndex(thisObj, exec, k + begin, exec->argument(k + 2), true);
if (exec->hadException())
return JSValue::encode(jsUndefined());
}
putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(length - deleteCount + additionalArgs));
return JSValue::encode(result);
......@@ -686,14 +705,19 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncUnShift(ExecState* exec)
if (exec->hadException())
return JSValue::encode(jsUndefined());
if (v)
thisObj->methodTable()->putByIndex(thisObj, exec, k + nrArgs - 1, v);
thisObj->methodTable()->putByIndex(thisObj, exec, k + nrArgs - 1, v, true);
else
thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, k + nrArgs - 1);
if (exec->hadException())
return JSValue::encode(jsUndefined());
}
}
}
for (unsigned k = 0; k < nrArgs; ++k)
thisObj->methodTable()->putByIndex(thisObj, exec, k, exec->argument(k));
for (unsigned k = 0; k < nrArgs; ++k) {
thisObj->methodTable()->putByIndex(thisObj, exec, k, exec->argument(k), true);
if (exec->hadException())
return JSValue::encode(jsUndefined());
}
JSValue result = jsNumber(length + nrArgs);
putProperty(exec, thisObj, exec->propertyNames().length, result);
return JSValue::encode(result);
......
......@@ -48,7 +48,7 @@ namespace JSC {
typedef void (*PutFunctionPtr)(JSCell*, ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
PutFunctionPtr put;
typedef void (*PutByIndexFunctionPtr)(JSCell*, ExecState*, unsigned propertyName, JSValue);
typedef void (*PutByIndexFunctionPtr)(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow);
PutByIndexFunctionPtr putByIndex;
typedef bool (*DeletePropertyFunctionPtr)(JSCell*, ExecState*, const Identifier&);
......
......@@ -207,7 +207,7 @@ inline std::pair<SparseArrayValueMap::iterator, bool> SparseArrayValueMap::add(J
return result;
}
inline void SparseArrayValueMap::put(ExecState* exec, JSArray* array, unsigned i, JSValue value)
inline void SparseArrayValueMap::put(ExecState* exec, JSArray* array, unsigned i, JSValue value, bool shouldThrow)
{
std::pair<SparseArrayValueMap::iterator, bool> result = add(array, i);
SparseArrayEntry& entry = result.first->second;
......@@ -217,14 +217,15 @@ inline void SparseArrayValueMap::put(ExecState* exec, JSArray* array, unsigned i