Diff
Modified: trunk/LayoutTests/ChangeLog (109948 => 109949)
--- trunk/LayoutTests/ChangeLog 2012-03-06 20:16:45 UTC (rev 109948)
+++ trunk/LayoutTests/ChangeLog 2012-03-06 20:20:04 UTC (rev 109949)
@@ -1,3 +1,20 @@
+2012-03-06 Gavin Barraclough <[email protected]>
+
+ writable/configurable not respected for some properties of Function/String/Arguments
+ https://bugs.webkit.org/show_bug.cgi?id=80436
+
+ Reviewed by Oliver Hunt.
+
+ Special properties should behave like regular properties.
+
+ * fast/js/mozilla/strict/10.6-expected.txt:
+ * fast/js/mozilla/strict/15.3.5.1-expected.txt:
+ * fast/js/mozilla/strict/15.3.5.2-expected.txt:
+ * fast/js/mozilla/strict/15.5.5.1-expected.txt:
+ - Check in passing test results.
+ * fast/js/script-tests/arguments.js:
+ - Fix test - this was asserting incorrect behaviour.
+
2012-03-06 Stephen White <[email protected]>
Unreviewed, rolling out r109840.
Modified: trunk/LayoutTests/fast/js/mozilla/strict/10.6-expected.txt (109948 => 109949)
--- trunk/LayoutTests/fast/js/mozilla/strict/10.6-expected.txt 2012-03-06 20:16:45 UTC (rev 109948)
+++ trunk/LayoutTests/fast/js/mozilla/strict/10.6-expected.txt 2012-03-06 20:20:04 UTC (rev 109949)
@@ -28,13 +28,13 @@
return (delete arguments[0]);
})(0, 1, 2, 3); is true
PASS true === true
-FAIL 'use strict'; (function f() {
+PASS 'use strict'; (function f() {
Object.defineProperties(arguments, {1: { writable: false },
2: { configurable: false },
3: { writable: false,
configurable: false }});
return (arguments[1] = 42);
-})(0, 1, 2, 3); should throw an instance of TypeError
+})(0, 1, 2, 3); threw exception of type TypeError.
PASS (function f() {
Object.defineProperties(arguments, {1: { writable: false },
2: { configurable: false },
@@ -88,13 +88,13 @@
return (delete arguments[2]);
})(0, 1, 2, 3); is false
PASS true === true
-FAIL 'use strict'; (function f() {
+PASS 'use strict'; (function f() {
Object.defineProperties(arguments, {1: { writable: false },
2: { configurable: false },
3: { writable: false,
configurable: false }});
return (arguments[3] = 42);
-})(0, 1, 2, 3); should throw an instance of TypeError
+})(0, 1, 2, 3); threw exception of type TypeError.
PASS (function f() {
Object.defineProperties(arguments, {1: { writable: false },
2: { configurable: false },
Modified: trunk/LayoutTests/fast/js/mozilla/strict/15.3.5.1-expected.txt (109948 => 109949)
--- trunk/LayoutTests/fast/js/mozilla/strict/15.3.5.1-expected.txt 2012-03-06 20:16:45 UTC (rev 109948)
+++ trunk/LayoutTests/fast/js/mozilla/strict/15.3.5.1-expected.txt 2012-03-06 20:20:04 UTC (rev 109949)
@@ -1,4 +1,4 @@
-FAIL 'use strict'; var f = fn(); f.length = 1; f.length should throw an instance of TypeError
+PASS 'use strict'; var f = fn(); f.length = 1; f.length threw exception of type TypeError.
PASS var f = fn(); f.length = 1; f.length is 3
PASS true === true
PASS 'use strict'; var f = fn(); delete f.length threw exception of type TypeError.
Modified: trunk/LayoutTests/fast/js/mozilla/strict/15.3.5.2-expected.txt (109948 => 109949)
--- trunk/LayoutTests/fast/js/mozilla/strict/15.3.5.2-expected.txt 2012-03-06 20:16:45 UTC (rev 109948)
+++ trunk/LayoutTests/fast/js/mozilla/strict/15.3.5.2-expected.txt 2012-03-06 20:20:04 UTC (rev 109949)
@@ -1,5 +1,5 @@
-FAIL 'use strict'; var f = fn(); delete f.prototype should throw an instance of TypeError
-FAIL var f = fn(); delete f.prototype should be false. Was true.
+PASS 'use strict'; var f = fn(); delete f.prototype threw exception of type TypeError.
+PASS var f = fn(); delete f.prototype is false
PASS true === true
PASSED!
PASS successfullyParsed is true
Modified: trunk/LayoutTests/fast/js/mozilla/strict/15.5.5.1-expected.txt (109948 => 109949)
--- trunk/LayoutTests/fast/js/mozilla/strict/15.5.5.1-expected.txt 2012-03-06 20:16:45 UTC (rev 109948)
+++ trunk/LayoutTests/fast/js/mozilla/strict/15.5.5.1-expected.txt 2012-03-06 20:20:04 UTC (rev 109949)
@@ -1,4 +1,4 @@
-FAIL 'use strict'; var s = str(); s.length = 1; s.length should throw an instance of TypeError
+PASS 'use strict'; var s = str(); s.length = 1; s.length threw exception of type TypeError.
PASS var s = str(); s.length = 1; s.length is 3
PASS true === true
PASS 'use strict'; var s = str(); delete s.length threw exception of type TypeError.
Modified: trunk/LayoutTests/fast/js/script-tests/arguments.js (109948 => 109949)
--- trunk/LayoutTests/fast/js/script-tests/arguments.js 2012-03-06 20:16:45 UTC (rev 109948)
+++ trunk/LayoutTests/fast/js/script-tests/arguments.js 2012-03-06 20:20:04 UTC (rev 109949)
@@ -623,7 +623,8 @@
shouldBeTrue(String( a1 === 301 ));
shouldBeTrue(String( arguments[1] === 201 ));
- // When a2 is make read-only the value is set, but it is no longer live.
+ // When a2 is made read-only the value is set, but it is no longer live.
+ // (per 10.6 [[DefineOwnProperty]] 5.b.ii.1)
shouldBeTrue(String( a2 === 202 ));
shouldBeTrue(String( arguments[2] === 202 ));
a2 = 302;
@@ -633,14 +634,15 @@
shouldBeTrue(String( a2 === 302 ));
shouldBeTrue(String( arguments[2] === 202 ));
- // When a3 is make read-only it remains live.
+ // When a3 is made read-only, it is no longer live.
+ // (per 10.6 [[DefineOwnProperty]] 5.b.ii.1)
shouldBeTrue(String( a3 === 103 ));
shouldBeTrue(String( arguments[3] === 103 ));
a3 = 303;
shouldBeTrue(String( a3 === 303 ));
- shouldBeTrue(String( arguments[3] === 303 ));
+ shouldBeTrue(String( arguments[3] === 103 ));
arguments[3] = 403;
- shouldBeTrue(String( a3 === 403 ));
- shouldBeTrue(String( arguments[3] === 403 ));
+ shouldBeTrue(String( a3 === 303 ));
+ shouldBeTrue(String( arguments[3] === 103 ));
})(100,101,102,103);
Modified: trunk/Source/_javascript_Core/ChangeLog (109948 => 109949)
--- trunk/Source/_javascript_Core/ChangeLog 2012-03-06 20:16:45 UTC (rev 109948)
+++ trunk/Source/_javascript_Core/ChangeLog 2012-03-06 20:20:04 UTC (rev 109949)
@@ -1,3 +1,30 @@
+2012-03-06 Gavin Barraclough <[email protected]>
+
+ writable/configurable not respected for some properties of Function/String/Arguments
+ https://bugs.webkit.org/show_bug.cgi?id=80436
+
+ Reviewed by Oliver Hunt.
+
+ Special properties should behave like regular properties.
+
+ * runtime/Arguments.cpp:
+ (JSC::Arguments::defineOwnProperty):
+ - Mis-nested logic for making read-only properties non-live.
+ * runtime/JSFunction.cpp:
+ (JSC::JSFunction::put):
+ - arguments/length/caller are non-writable, non-configurable - reject appropriately.
+ (JSC::JSFunction::deleteProperty):
+ - Attempting to delete prototype/caller should fail.
+ (JSC::JSFunction::defineOwnProperty):
+ - Ensure prototype is reified on attempt to reify it.
+ - arguments/length/caller are non-writable, non-configurable - reject appropriately.
+ * runtime/JSFunction.h:
+ - added declaration for defineOwnProperty.
+ (JSFunction):
+ * runtime/StringObject.cpp:
+ (JSC::StringObject::put):
+ - length is non-writable, non-configurable - reject appropriately.
+
2012-03-06 Ulan Degenbaev <[email protected]>
TypedArray subarray call for subarray does not clamp the end index parameter properly
Modified: trunk/Source/_javascript_Core/runtime/Arguments.cpp (109948 => 109949)
--- trunk/Source/_javascript_Core/runtime/Arguments.cpp 2012-03-06 20:16:45 UTC (rev 109948)
+++ trunk/Source/_javascript_Core/runtime/Arguments.cpp 2012-03-06 20:20:04 UTC (rev 109949)
@@ -320,12 +320,15 @@
if (descriptor.isAccessorDescriptor()) {
// i. Call the [[Delete]] internal method of map passing P, and false as the arguments.
thisObject->d->deletedArguments[i] = true;
- } else if (descriptor.value()) { // b. Else i. If Desc.[[Value]] is present, then
+ } else { // b. Else
+ // i. If Desc.[[Value]] is present, then
// 1. Call the [[Put]] internal method of map passing P, Desc.[[Value]], and Throw as the arguments.
+ if (descriptor.value())
+ thisObject->argument(i).set(exec->globalData(), thisObject, descriptor.value());
// ii. If Desc.[[Writable]] is present and its value is false, then
- thisObject->argument(i).set(exec->globalData(), thisObject, descriptor.value());
+ // 1. Call the [[Delete]] internal method of map passing P and false as arguments.
if (descriptor.writablePresent() && !descriptor.writable())
- thisObject->d->deletedArguments[i] = true; // 1. Call the [[Delete]] internal method of map passing P and false as arguments.
+ thisObject->d->deletedArguments[i] = true;
}
}
Modified: trunk/Source/_javascript_Core/runtime/JSFunction.cpp (109948 => 109949)
--- trunk/Source/_javascript_Core/runtime/JSFunction.cpp 2012-03-06 20:16:45 UTC (rev 109948)
+++ trunk/Source/_javascript_Core/runtime/JSFunction.cpp 2012-03-06 20:20:04 UTC (rev 109949)
@@ -337,8 +337,11 @@
Base::put(thisObject, exec, propertyName, value, slot);
return;
}
- if (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length)
+ if (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length || propertyName == exec->propertyNames().caller) {
+ if (slot.isStrictMode())
+ throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
return;
+ }
Base::put(thisObject, exec, propertyName, value, slot);
}
@@ -347,11 +350,64 @@
JSFunction* thisObject = jsCast<JSFunction*>(cell);
if (thisObject->isHostFunction())
return Base::deleteProperty(thisObject, exec, propertyName);
- if (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length)
+ if (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length || propertyName == exec->propertyNames().prototype || propertyName == exec->propertyNames().caller)
return false;
return Base::deleteProperty(thisObject, exec, propertyName);
}
+bool JSFunction::defineOwnProperty(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor, bool throwException)
+{
+ JSFunction* thisObject = jsCast<JSFunction*>(object);
+ if (thisObject->isHostFunction())
+ return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
+
+ if (propertyName == exec->propertyNames().prototype) {
+ // Make sure prototype has been reified, such that it can only be overwritten
+ // following the rules set out in ECMA-262 8.12.9.
+ PropertySlot slot;
+ thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, propertyName, slot);
+ } else if (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length || propertyName == exec->propertyNames().caller) {
+ if (!object->isExtensible()) {
+ if (throwException)
+ throwError(exec, createTypeError(exec, "Attempting to define property on object that is not extensible."));
+ return false;
+ }
+ if (descriptor.configurablePresent() && descriptor.configurable()) {
+ if (throwException)
+ throwError(exec, createTypeError(exec, "Attempting to configurable attribute of unconfigurable property."));
+ return false;
+ }
+ if (descriptor.enumerablePresent() && descriptor.enumerable()) {
+ if (throwException)
+ throwError(exec, createTypeError(exec, "Attempting to change enumerable attribute of unconfigurable property."));
+ return false;
+ }
+ if (descriptor.isAccessorDescriptor()) {
+ if (throwException)
+ throwError(exec, createTypeError(exec, "Attempting to change access mechanism for an unconfigurable property."));
+ return false;
+ }
+ if (descriptor.writablePresent() && descriptor.writable()) {
+ if (throwException)
+ throwError(exec, createTypeError(exec, "Attempting to change writable attribute of unconfigurable property."));
+ return false;
+ }
+ if (!descriptor.value())
+ return true;
+ if (propertyName == exec->propertyNames().arguments && sameValue(exec, descriptor.value(), exec->interpreter()->retrieveArgumentsFromVMCode(exec, thisObject)))
+ return true;
+ if (propertyName == exec->propertyNames().length && sameValue(exec, descriptor.value(), jsNumber(thisObject->jsExecutable()->parameterCount())))
+ return true;
+ if (propertyName == exec->propertyNames().caller && sameValue(exec, descriptor.value(), exec->interpreter()->retrieveCallerFromVMCode(exec, thisObject)))
+ return true;
+ if (throwException)
+ throwError(exec, createTypeError(exec, "Attempting to change value of a readonly property."));
+ return false;
+ }
+
+ return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
+}
+
// ECMA 13.2.2 [[Construct]]
ConstructType JSFunction::getConstructData(JSCell* cell, ConstructData& constructData)
{
Modified: trunk/Source/_javascript_Core/runtime/JSFunction.h (109948 => 109949)
--- trunk/Source/_javascript_Core/runtime/JSFunction.h 2012-03-06 20:16:45 UTC (rev 109948)
+++ trunk/Source/_javascript_Core/runtime/JSFunction.h 2012-03-06 20:20:04 UTC (rev 109949)
@@ -133,6 +133,7 @@
static bool getOwnPropertySlot(JSCell*, ExecState*, const Identifier&, PropertySlot&);
static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&);
static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode = ExcludeDontEnumProperties);
+ static bool defineOwnProperty(JSObject*, ExecState*, const Identifier& propertyName, PropertyDescriptor&, bool shouldThrow);
static void put(JSCell*, ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
Modified: trunk/Source/_javascript_Core/runtime/StringObject.cpp (109948 => 109949)
--- trunk/Source/_javascript_Core/runtime/StringObject.cpp 2012-03-06 20:16:45 UTC (rev 109948)
+++ trunk/Source/_javascript_Core/runtime/StringObject.cpp 2012-03-06 20:20:04 UTC (rev 109949)
@@ -21,6 +21,7 @@
#include "config.h"
#include "StringObject.h"
+#include "Error.h"
#include "PropertyNameArray.h"
namespace JSC {
@@ -68,11 +69,56 @@
void StringObject::put(JSCell* cell, ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
{
- if (propertyName == exec->propertyNames().length)
+ if (propertyName == exec->propertyNames().length) {
+ if (slot.isStrictMode())
+ throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
return;
+ }
JSObject::put(cell, exec, propertyName, value, slot);
}
+bool StringObject::defineOwnProperty(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor, bool throwException)
+{
+ StringObject* thisObject = jsCast<StringObject*>(object);
+
+ if (propertyName == exec->propertyNames().length) {
+ if (!object->isExtensible()) {
+ if (throwException)
+ throwError(exec, createTypeError(exec, "Attempting to define property on object that is not extensible."));
+ return false;
+ }
+ if (descriptor.configurablePresent() && descriptor.configurable()) {
+ if (throwException)
+ throwError(exec, createTypeError(exec, "Attempting to configurable attribute of unconfigurable property."));
+ return false;
+ }
+ if (descriptor.enumerablePresent() && descriptor.enumerable()) {
+ if (throwException)
+ throwError(exec, createTypeError(exec, "Attempting to change enumerable attribute of unconfigurable property."));
+ return false;
+ }
+ if (descriptor.isAccessorDescriptor()) {
+ if (throwException)
+ throwError(exec, createTypeError(exec, "Attempting to change access mechanism for an unconfigurable property."));
+ return false;
+ }
+ if (descriptor.writablePresent() && descriptor.writable()) {
+ if (throwException)
+ throwError(exec, createTypeError(exec, "Attempting to change writable attribute of unconfigurable property."));
+ return false;
+ }
+ if (!descriptor.value())
+ return true;
+ if (propertyName == exec->propertyNames().length && sameValue(exec, descriptor.value(), jsNumber(thisObject->internalValue()->length())))
+ return true;
+ if (throwException)
+ throwError(exec, createTypeError(exec, "Attempting to change value of a readonly property."));
+ return false;
+ }
+
+ return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
+}
+
bool StringObject::deleteProperty(JSCell* cell, ExecState* exec, const Identifier& propertyName)
{
StringObject* thisObject = jsCast<StringObject*>(cell);
Modified: trunk/Source/_javascript_Core/runtime/StringObject.h (109948 => 109949)
--- trunk/Source/_javascript_Core/runtime/StringObject.h 2012-03-06 20:16:45 UTC (rev 109948)
+++ trunk/Source/_javascript_Core/runtime/StringObject.h 2012-03-06 20:20:04 UTC (rev 109949)
@@ -53,6 +53,7 @@
static bool deleteProperty(JSCell*, ExecState*, const Identifier& propertyName);
static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+ static bool defineOwnProperty(JSObject*, ExecState*, const Identifier& propertyName, PropertyDescriptor&, bool shouldThrow);
static const JS_EXPORTDATA ClassInfo s_info;