Object.freeze broken on latest Nightly
https://bugs.webkit.org/show_bug.cgi?id=80577

Reviewed by Oliver Hunt.

Source/JavaScriptCore: 

* runtime/Arguments.cpp:
(JSC::Arguments::defineOwnProperty):
    - defineOwnProperty was checking for correct behaviour, provided that length/callee hadn't
    been overrridden. instead, just reify length/callee & rely on JSObject::defineOwnProperty.
* runtime/JSFunction.cpp:
(JSC::JSFunction::defineOwnProperty):
    - for arguments/caller/length properties, defineOwnProperty was incorrectly asserting that
    the object must be extensible; this is incorrect since these properties should already exist
    on the object. In addition, it was asserting that the arguments/caller values must match the
    corresponding magic data properties, but for strict mode function this is incorrect. Instead,
    just reify the arguments/caller accessor & defer to JSObject::defineOwnProperty.

LayoutTests: 

* fast/js/preventExtensions-expected.txt:
* fast/js/script-tests/preventExtensions.js:
(shouldBeTrue):
(shouldBeFalse.shouldBeFalse.preventExtensionsFreezeIsFrozen):
    - Added test cases.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@111250 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 81ee26c..25adda5 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,22 @@
+2012-03-19  Gavin Barraclough  <barraclough@apple.com>
+
+        Object.freeze broken on latest Nightly
+        https://bugs.webkit.org/show_bug.cgi?id=80577
+
+        Reviewed by Oliver Hunt.
+
+        * runtime/Arguments.cpp:
+        (JSC::Arguments::defineOwnProperty):
+            - defineOwnProperty was checking for correct behaviour, provided that length/callee hadn't
+            been overrridden. instead, just reify length/callee & rely on JSObject::defineOwnProperty.
+        * runtime/JSFunction.cpp:
+        (JSC::JSFunction::defineOwnProperty):
+            - for arguments/caller/length properties, defineOwnProperty was incorrectly asserting that
+            the object must be extensible; this is incorrect since these properties should already exist
+            on the object. In addition, it was asserting that the arguments/caller values must match the
+            corresponding magic data properties, but for strict mode function this is incorrect. Instead,
+            just reify the arguments/caller accessor & defer to JSObject::defineOwnProperty.
+
 2012-03-19  Filip Pizlo  <fpizlo@apple.com>
 
         LLInt get_by_pname slow path incorrectly assumes that the operands are not constants
diff --git a/Source/JavaScriptCore/runtime/Arguments.cpp b/Source/JavaScriptCore/runtime/Arguments.cpp
index 7a53ec1..e5f54c2 100644
--- a/Source/JavaScriptCore/runtime/Arguments.cpp
+++ b/Source/JavaScriptCore/runtime/Arguments.cpp
@@ -306,6 +306,7 @@
     bool isArrayIndex;
     unsigned i = propertyName.toArrayIndex(isArrayIndex);
     if (isArrayIndex && i < thisObject->d->numArguments) {
+        object->putDirect(exec->globalData(), propertyName, thisObject->argument(i).get(), 0);
         if (!Base::defineOwnProperty(object, exec, propertyName, descriptor, shouldThrow))
             return false;
 
@@ -331,35 +332,16 @@
                     thisObject->d->deletedArguments[i] = true;
             }
         }
-
         return true;
     }
 
     if (propertyName == exec->propertyNames().length && !thisObject->d->overrodeLength) {
+        thisObject->putDirect(exec->globalData(), propertyName, jsNumber(thisObject->d->numArguments), DontEnum);
         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) {
+    } else if (propertyName == exec->propertyNames().callee && !thisObject->d->overrodeCallee) {
+        thisObject->putDirect(exec->globalData(), propertyName, thisObject->d->callee.get(), DontEnum);
         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)
+    } else if (propertyName == exec->propertyNames().caller && thisObject->d->isStrictMode)
         thisObject->createStrictModeCallerIfNecessary(exec);
 
     return Base::defineOwnProperty(object, exec, propertyName, descriptor, shouldThrow);
diff --git a/Source/JavaScriptCore/runtime/JSFunction.cpp b/Source/JavaScriptCore/runtime/JSFunction.cpp
index a588551..ecc9d31 100644
--- a/Source/JavaScriptCore/runtime/JSFunction.cpp
+++ b/Source/JavaScriptCore/runtime/JSFunction.cpp
@@ -370,46 +370,55 @@
         // 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;
+        return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
+    }
+
+    bool valueCheck;
+    if (propertyName == exec->propertyNames().arguments) {
+        if (thisObject->jsExecutable()->isStrictMode()) {
+            if (!Base::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor))
+                thisObject->putDirectAccessor(exec->globalData(), propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Accessor);
+            return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
         }
-        if (descriptor.configurablePresent() && descriptor.configurable()) {
-            if (throwException)
-                throwError(exec, createTypeError(exec, "Attempting to configurable attribute of unconfigurable property."));
-            return false;
+        valueCheck = !descriptor.value() || sameValue(exec, descriptor.value(), exec->interpreter()->retrieveArgumentsFromVMCode(exec, thisObject));
+    } else if (propertyName == exec->propertyNames().caller) {
+        if (thisObject->jsExecutable()->isStrictMode()) {
+            if (!Base::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor))
+                thisObject->putDirectAccessor(exec->globalData(), propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Accessor);
+            return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
         }
-        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;
+        valueCheck = !descriptor.value() || sameValue(exec, descriptor.value(), exec->interpreter()->retrieveCallerFromVMCode(exec, thisObject));
+    } else if (propertyName == exec->propertyNames().length)
+        valueCheck = !descriptor.value() || sameValue(exec, descriptor.value(), jsNumber(thisObject->jsExecutable()->parameterCount()));
+    else
+        return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
+     
+    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 (!valueCheck) {
         if (throwException)
             throwError(exec, createTypeError(exec, "Attempting to change value of a readonly property."));
         return false;
     }
-
-    return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
+    return true;
 }
 
 // ECMA 13.2.2 [[Construct]]