Title: [108651] trunk
Revision
108651
Author
[email protected]
Date
2012-02-23 11:43:07 -0800 (Thu, 23 Feb 2012)

Log Message

Object.isSealed / Object.isFrozen don't work for native objects
https://bugs.webkit.org/show_bug.cgi?id=79331

Reviewed by Sam Weinig.

Need to inspect all properties, including static ones.
This exposes a couple of bugs in Array & Arguments:
    - getOwnPropertyDescriptor doesn't correctly report the writable attribute of array length.
    - Arguments object's defineOwnProperty does not handle callee/caller/length correctly.

Source/_javascript_Core: 

* runtime/Arguments.cpp:
(JSC::Arguments::defineOwnProperty):
    - Add handling for callee/caller/length.
* runtime/JSArray.cpp:
(JSC::JSArray::getOwnPropertyDescriptor):
    - report length's writability correctly.
* runtime/ObjectConstructor.cpp:
(JSC::objectConstructorSeal):
(JSC::objectConstructorFreeze):
(JSC::objectConstructorIsSealed):
(JSC::objectConstructorIsFrozen):
    - Add spec-based implementation for non-final objects.

LayoutTests: 

* fast/js/preventExtensions-expected.txt:
* fast/js/script-tests/preventExtensions.js:
    - Added tests.

Modified Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (108650 => 108651)


--- trunk/LayoutTests/ChangeLog	2012-02-23 19:41:12 UTC (rev 108650)
+++ trunk/LayoutTests/ChangeLog	2012-02-23 19:43:07 UTC (rev 108651)
@@ -1,5 +1,21 @@
 2012-02-23  Gavin Barraclough  <[email protected]>
 
+        Object.isSealed / Object.isFrozen don't work for native objects
+        https://bugs.webkit.org/show_bug.cgi?id=79331
+
+        Reviewed by Sam Weinig.
+
+        Need to inspect all properties, including static ones.
+        This exposes a couple of bugs in Array & Arguments:
+            - getOwnPropertyDescriptor doesn't correctly report the writable attribute of array length.
+            - Arguments object's defineOwnProperty does not handle callee/caller/length correctly.
+
+        * fast/js/preventExtensions-expected.txt:
+        * fast/js/script-tests/preventExtensions.js:
+            - Added tests.
+
+2012-02-23  Gavin Barraclough  <[email protected]>
+
         pop of array hole should get from the prototype chain
         https://bugs.webkit.org/show_bug.cgi?id=79338
 

Modified: trunk/LayoutTests/fast/js/preventExtensions-expected.txt (108650 => 108651)


--- trunk/LayoutTests/fast/js/preventExtensions-expected.txt	2012-02-23 19:41:12 UTC (rev 108650)
+++ trunk/LayoutTests/fast/js/preventExtensions-expected.txt	2012-02-23 19:43:07 UTC (rev 108651)
@@ -18,7 +18,10 @@
 PASS var arr = Object.preventExtensions([]); arr[0] = 42; arr.length is 0
 PASS obj.foo is 1
 PASS array[0] is 0
+PASS Object.getOwnPropertyDescriptor(array, "length").writable is false
 PASS args[0] is 0
+PASS Object.getOwnPropertyDescriptor(args, "length").writable is false
+PASS Object.getOwnPropertyDescriptor(args, "callee").writable is false
 PASS successfullyParsed is true
 
 TEST COMPLETE

Modified: trunk/LayoutTests/fast/js/script-tests/preventExtensions.js (108650 => 108651)


--- trunk/LayoutTests/fast/js/script-tests/preventExtensions.js	2012-02-23 19:41:12 UTC (rev 108650)
+++ trunk/LayoutTests/fast/js/script-tests/preventExtensions.js	2012-02-23 19:43:07 UTC (rev 108651)
@@ -91,8 +91,11 @@
 var array = freeze([0,1,2]);
 array[0] = 3;
 shouldBe('array[0]', '0');
+shouldBeFalse('Object.getOwnPropertyDescriptor(array, "length").writable')
 
 // Check that freezing arguments objects works correctly.
 var args = freeze((function(){ return arguments; })(0,1,2));
 args[0] = 3;
 shouldBe('args[0]', '0');
+shouldBeFalse('Object.getOwnPropertyDescriptor(args, "length").writable')
+shouldBeFalse('Object.getOwnPropertyDescriptor(args, "callee").writable')

Modified: trunk/Source/_javascript_Core/ChangeLog (108650 => 108651)


--- trunk/Source/_javascript_Core/ChangeLog	2012-02-23 19:41:12 UTC (rev 108650)
+++ trunk/Source/_javascript_Core/ChangeLog	2012-02-23 19:43:07 UTC (rev 108651)
@@ -1,5 +1,30 @@
 2012-02-23  Gavin Barraclough  <[email protected]>
 
+        Object.isSealed / Object.isFrozen don't work for native objects
+        https://bugs.webkit.org/show_bug.cgi?id=79331
+
+        Reviewed by Sam Weinig.
+
+        Need to inspect all properties, including static ones.
+        This exposes a couple of bugs in Array & Arguments:
+            - getOwnPropertyDescriptor doesn't correctly report the writable attribute of array length.
+            - Arguments object's defineOwnProperty does not handle callee/caller/length correctly.
+
+        * runtime/Arguments.cpp:
+        (JSC::Arguments::defineOwnProperty):
+            - Add handling for callee/caller/length.
+        * runtime/JSArray.cpp:
+        (JSC::JSArray::getOwnPropertyDescriptor):
+            - report length's writability correctly.
+        * runtime/ObjectConstructor.cpp:
+        (JSC::objectConstructorSeal):
+        (JSC::objectConstructorFreeze):
+        (JSC::objectConstructorIsSealed):
+        (JSC::objectConstructorIsFrozen):
+            - Add spec-based implementation for non-final objects.
+
+2012-02-23  Gavin Barraclough  <[email protected]>
+
         pop of array hole should get from the prototype chain
         https://bugs.webkit.org/show_bug.cgi?id=79338
 

Modified: trunk/Source/_javascript_Core/runtime/Arguments.cpp (108650 => 108651)


--- trunk/Source/_javascript_Core/runtime/Arguments.cpp	2012-02-23 19:41:12 UTC (rev 108650)
+++ trunk/Source/_javascript_Core/runtime/Arguments.cpp	2012-02-23 19:43:07 UTC (rev 108651)
@@ -302,13 +302,13 @@
 
 bool Arguments::defineOwnProperty(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor, bool shouldThrow)
 {
-    if (!Base::defineOwnProperty(object, exec, propertyName, descriptor, shouldThrow))
-        return false;
-
     Arguments* thisObject = jsCast<Arguments*>(object);
     bool isArrayIndex;
     unsigned i = propertyName.toArrayIndex(isArrayIndex);
     if (isArrayIndex && i < thisObject->d->numArguments) {
+        if (!Base::defineOwnProperty(object, exec, propertyName, descriptor, shouldThrow))
+            return false;
+
         if (!thisObject->d->deletedArguments) {
             thisObject->d->deletedArguments = adoptArrayPtr(new bool[thisObject->d->numArguments]);
             memset(thisObject->d->deletedArguments.get(), 0, sizeof(bool) * thisObject->d->numArguments);
@@ -328,8 +328,38 @@
                     thisObject->d->deletedArguments[i] = true; // 1. Call the [[Delete]] internal method of map passing P and false as arguments.
             }
         }
+
+        return true;
     }
-    return true;
+
+    if (propertyName == exec->propertyNames().length && !thisObject->d->overrodeLength) {
+        thisObject->d->overrodeLength = true;
+        if (!descriptor.isAccessorDescriptor()) {
+            if (!descriptor.value())
+                descriptor.setValue(jsNumber(thisObject->d->numArguments));
+            if (!descriptor.configurablePresent())
+                descriptor.setConfigurable(true);
+        }
+        if (!descriptor.configurablePresent())
+            descriptor.setConfigurable(true);
+    }
+
+    if (propertyName == exec->propertyNames().callee && !thisObject->d->overrodeCallee) {
+        thisObject->d->overrodeCallee = true;
+        if (!descriptor.isAccessorDescriptor()) {
+            if (!descriptor.value())
+                descriptor.setValue(thisObject->d->callee.get());
+            if (!descriptor.configurablePresent())
+                descriptor.setConfigurable(true);
+        }
+        if (!descriptor.configurablePresent())
+            descriptor.setConfigurable(true);
+    }
+
+    if (propertyName == exec->propertyNames().caller && thisObject->d->isStrictMode)
+        thisObject->createStrictModeCallerIfNecessary(exec);
+
+    return Base::defineOwnProperty(object, exec, propertyName, descriptor, shouldThrow);
 }
 
 void Arguments::tearOff(CallFrame* callFrame)

Modified: trunk/Source/_javascript_Core/runtime/JSArray.cpp (108650 => 108651)


--- trunk/Source/_javascript_Core/runtime/JSArray.cpp	2012-02-23 19:41:12 UTC (rev 108650)
+++ trunk/Source/_javascript_Core/runtime/JSArray.cpp	2012-02-23 19:43:07 UTC (rev 108651)
@@ -694,7 +694,7 @@
 {
     JSArray* thisObject = jsCast<JSArray*>(object);
     if (propertyName == exec->propertyNames().length) {
-        descriptor.setDescriptor(jsNumber(thisObject->length()), DontDelete | DontEnum);
+        descriptor.setDescriptor(jsNumber(thisObject->length()), thisObject->isLengthWritable() ? DontDelete | DontEnum : DontDelete | DontEnum | ReadOnly);
         return true;
     }
 

Modified: trunk/Source/_javascript_Core/runtime/ObjectConstructor.cpp (108650 => 108651)


--- trunk/Source/_javascript_Core/runtime/ObjectConstructor.cpp	2012-02-23 19:41:12 UTC (rev 108650)
+++ trunk/Source/_javascript_Core/runtime/ObjectConstructor.cpp	2012-02-23 19:43:07 UTC (rev 108651)
@@ -365,30 +365,31 @@
         return throwVMError(exec, createTypeError(exec, "Object.seal can only be called on Objects."));
     JSObject* object = asObject(obj);
 
-    if (isJSFinalObject(obj))
+    if (isJSFinalObject(object)) {
         object->seal(exec->globalData());
-    else {
-        // 2. For each named own property name P of O,
-        PropertyNameArray properties(exec);
-        object->methodTable()->getOwnPropertyNames(object, exec, properties, IncludeDontEnumProperties);
-        PropertyNameArray::const_iterator end = properties.end();
-        for (PropertyNameArray::const_iterator iter = properties.begin(); iter != end; ++iter) {
-            // a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P.
-            PropertyDescriptor desc;
-            if (!object->methodTable()->getOwnPropertyDescriptor(object, exec, *iter, desc))
-                continue;
-            // b. If desc.[[Configurable]] is true, set desc.[[Configurable]] to false.
-            desc.setConfigurable(false);
-            // c. Call the [[DefineOwnProperty]] internal method of O with P, desc, and true as arguments.
-            object->methodTable()->defineOwnProperty(object, exec, *iter, desc, true);
-            if (exec->hadException())
-                return JSValue::encode(obj);
-        }
+        return JSValue::encode(obj);
+    }
 
-        // 3. Set the [[Extensible]] internal property of O to false.
-        object->preventExtensions(exec->globalData());
+    // 2. For each named own property name P of O,
+    PropertyNameArray properties(exec);
+    object->methodTable()->getOwnPropertyNames(object, exec, properties, IncludeDontEnumProperties);
+    PropertyNameArray::const_iterator end = properties.end();
+    for (PropertyNameArray::const_iterator iter = properties.begin(); iter != end; ++iter) {
+        // a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P.
+        PropertyDescriptor desc;
+        if (!object->methodTable()->getOwnPropertyDescriptor(object, exec, *iter, desc))
+            continue;
+        // b. If desc.[[Configurable]] is true, set desc.[[Configurable]] to false.
+        desc.setConfigurable(false);
+        // c. Call the [[DefineOwnProperty]] internal method of O with P, desc, and true as arguments.
+        object->methodTable()->defineOwnProperty(object, exec, *iter, desc, true);
+        if (exec->hadException())
+            return JSValue::encode(obj);
     }
 
+    // 3. Set the [[Extensible]] internal property of O to false.
+    object->preventExtensions(exec->globalData());
+
     // 4. Return O.
     return JSValue::encode(obj);
 }
@@ -401,34 +402,35 @@
         return throwVMError(exec, createTypeError(exec, "Object.freeze can only be called on Objects."));
     JSObject* object = asObject(obj);
 
-    if (isJSFinalObject(obj))
+    if (isJSFinalObject(object)) {
         object->freeze(exec->globalData());
-    else {
-        // 2. For each named own property name P of O,
-        PropertyNameArray properties(exec);
-        object->methodTable()->getOwnPropertyNames(object, exec, properties, IncludeDontEnumProperties);
-        PropertyNameArray::const_iterator end = properties.end();
-        for (PropertyNameArray::const_iterator iter = properties.begin(); iter != end; ++iter) {
-            // a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P.
-            PropertyDescriptor desc;
-            if (!object->methodTable()->getOwnPropertyDescriptor(object, exec, *iter, desc))
-                continue;
-            // b. If IsDataDescriptor(desc) is true, then
-            // i. If desc.[[Writable]] is true, set desc.[[Writable]] to false.
-            if (desc.isDataDescriptor())
-                desc.setWritable(false);
-            // c. If desc.[[Configurable]] is true, set desc.[[Configurable]] to false.
-            desc.setConfigurable(false);
-            // d. Call the [[DefineOwnProperty]] internal method of O with P, desc, and true as arguments.
-            object->methodTable()->defineOwnProperty(object, exec, *iter, desc, true);
-            if (exec->hadException())
-                return JSValue::encode(obj);
-        }
+        return JSValue::encode(obj);
+    }
 
-        // 3. Set the [[Extensible]] internal property of O to false.
-        object->preventExtensions(exec->globalData());
+    // 2. For each named own property name P of O,
+    PropertyNameArray properties(exec);
+    object->methodTable()->getOwnPropertyNames(object, exec, properties, IncludeDontEnumProperties);
+    PropertyNameArray::const_iterator end = properties.end();
+    for (PropertyNameArray::const_iterator iter = properties.begin(); iter != end; ++iter) {
+        // a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P.
+        PropertyDescriptor desc;
+        if (!object->methodTable()->getOwnPropertyDescriptor(object, exec, *iter, desc))
+            continue;
+        // b. If IsDataDescriptor(desc) is true, then
+        // i. If desc.[[Writable]] is true, set desc.[[Writable]] to false.
+        if (desc.isDataDescriptor())
+            desc.setWritable(false);
+        // c. If desc.[[Configurable]] is true, set desc.[[Configurable]] to false.
+        desc.setConfigurable(false);
+        // d. Call the [[DefineOwnProperty]] internal method of O with P, desc, and true as arguments.
+        object->methodTable()->defineOwnProperty(object, exec, *iter, desc, true);
+        if (exec->hadException())
+            return JSValue::encode(obj);
     }
 
+    // 3. Set the [[Extensible]] internal property of O to false.
+    object->preventExtensions(exec->globalData());
+
     // 4. Return O.
     return JSValue::encode(obj);
 }
@@ -444,18 +446,63 @@
 
 EncodedJSValue JSC_HOST_CALL objectConstructorIsSealed(ExecState* exec)
 {
+    // 1. If Type(O) is not Object throw a TypeError exception.
     JSValue obj = exec->argument(0);
     if (!obj.isObject())
         return throwVMError(exec, createTypeError(exec, "Object.isSealed can only be called on Objects."));
-    return JSValue::encode(jsBoolean(asObject(obj)->isSealed(exec->globalData())));
+    JSObject* object = asObject(obj);
+
+    if (isJSFinalObject(object))
+        return JSValue::encode(jsBoolean(object->isSealed(exec->globalData())));
+
+    // 2. For each named own property name P of O,
+    PropertyNameArray properties(exec);
+    object->methodTable()->getOwnPropertyNames(object, exec, properties, IncludeDontEnumProperties);
+    PropertyNameArray::const_iterator end = properties.end();
+    for (PropertyNameArray::const_iterator iter = properties.begin(); iter != end; ++iter) {
+        // a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P.
+        PropertyDescriptor desc;
+        if (!object->methodTable()->getOwnPropertyDescriptor(object, exec, *iter, desc))
+            continue;
+        // b. If desc.[[Configurable]] is true, then return false.
+        if (desc.configurable())
+            return JSValue::encode(jsBoolean(false));
+    }
+
+    // 3. If the [[Extensible]] internal property of O is false, then return true.
+    // 4. Otherwise, return false.
+    return JSValue::encode(jsBoolean(!object->isExtensible()));
 }
 
 EncodedJSValue JSC_HOST_CALL objectConstructorIsFrozen(ExecState* exec)
 {
+    // 1. If Type(O) is not Object throw a TypeError exception.
     JSValue obj = exec->argument(0);
     if (!obj.isObject())
         return throwVMError(exec, createTypeError(exec, "Object.isFrozen can only be called on Objects."));
-    return JSValue::encode(jsBoolean(asObject(obj)->isFrozen(exec->globalData())));
+    JSObject* object = asObject(obj);
+
+    if (isJSFinalObject(object))
+        return JSValue::encode(jsBoolean(object->isFrozen(exec->globalData())));
+
+    // 2. For each named own property name P of O,
+    PropertyNameArray properties(exec);
+    object->methodTable()->getOwnPropertyNames(object, exec, properties, IncludeDontEnumProperties);
+    PropertyNameArray::const_iterator end = properties.end();
+    for (PropertyNameArray::const_iterator iter = properties.begin(); iter != end; ++iter) {
+        // a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P.
+        PropertyDescriptor desc;
+        if (!object->methodTable()->getOwnPropertyDescriptor(object, exec, *iter, desc))
+            continue;
+        // b. If IsDataDescriptor(desc) is true then
+        // i. If desc.[[Writable]] is true, return false. c. If desc.[[Configurable]] is true, then return false.
+        if ((desc.isDataDescriptor() && desc.writable()) || desc.configurable())
+            return JSValue::encode(jsBoolean(false));
+    }
+
+    // 3. If the [[Extensible]] internal property of O is false, then return true.
+    // 4. Otherwise, return false.
+    return JSValue::encode(jsBoolean(!object->isExtensible()));
 }
 
 EncodedJSValue JSC_HOST_CALL objectConstructorIsExtensible(ExecState* exec)
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to