Title: [225845] trunk
Revision
225845
Author
[email protected]
Date
2017-12-13 09:29:21 -0800 (Wed, 13 Dec 2017)

Log Message

Fix how JSFunction handles "caller" and "arguments" for functions that don't have those properties
https://bugs.webkit.org/show_bug.cgi?id=163579
<rdar://problem/35455798>

Reviewed by Mark Lam.

JSTests:

* stress/caller-and-arguments-properties-for-functions-that-dont-have-them.js: Added.
(assert):
(test1):
(i.test1):
(i.test1.C):
(i.test1.async.foo):
(i.test1.foo):
(test2):

Source/_javascript_Core:

Some functions in _javascript_ do not have the "caller" and "arguments" properties.
For example, strict functions do not. When reading our code that dealt with these
types of functions, it was simply all wrong. We were doing weird things depending
on the method table hook. This patch fixes this by doing what we should've been
doing all along: when the JSFunction does not own the "caller"/"arguments" property,
it should defer to its base class implementation for the various method table hooks.

* runtime/JSFunction.cpp:
(JSC::JSFunction::put):
(JSC::JSFunction::deleteProperty):
(JSC::JSFunction::defineOwnProperty):

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (225844 => 225845)


--- trunk/JSTests/ChangeLog	2017-12-13 17:19:24 UTC (rev 225844)
+++ trunk/JSTests/ChangeLog	2017-12-13 17:29:21 UTC (rev 225845)
@@ -1,5 +1,22 @@
 2017-12-13  Saam Barati  <[email protected]>
 
+        Fix how JSFunction handles "caller" and "arguments" for functions that don't have those properties
+        https://bugs.webkit.org/show_bug.cgi?id=163579
+        <rdar://problem/35455798>
+
+        Reviewed by Mark Lam.
+
+        * stress/caller-and-arguments-properties-for-functions-that-dont-have-them.js: Added.
+        (assert):
+        (test1):
+        (i.test1):
+        (i.test1.C):
+        (i.test1.async.foo):
+        (i.test1.foo):
+        (test2):
+
+2017-12-13  Saam Barati  <[email protected]>
+
         TypeCheckHoistingPhase needs to emit a CheckStructureOrEmpty if it's doing it for |this|
         https://bugs.webkit.org/show_bug.cgi?id=180734
         <rdar://problem/35640547>

Added: trunk/JSTests/stress/caller-and-arguments-properties-for-functions-that-dont-have-them.js (0 => 225845)


--- trunk/JSTests/stress/caller-and-arguments-properties-for-functions-that-dont-have-them.js	                        (rev 0)
+++ trunk/JSTests/stress/caller-and-arguments-properties-for-functions-that-dont-have-them.js	2017-12-13 17:29:21 UTC (rev 225845)
@@ -0,0 +1,74 @@
+function assert(b) {
+    if (!b)
+        throw new Error;
+}
+
+function test1(f) {
+    f.__proto__ = {};
+    Object.defineProperty(f, "caller", {value:42});
+    assert(f.caller === 42);
+    Object.defineProperty(f, "arguments", {value:32});
+    assert(f.arguments === 32);
+}
+for (let i = 0; i < 1000; ++i) {
+    test1(function () { "use strict"; });
+    test1(class C { });
+    test1(() => undefined);
+    test1(async function foo(){});
+    test1(function* foo() { });
+}
+
+function test2(f, p = {}) {
+    f.__proto__ = p;
+    f.caller = 42;
+    assert(f.caller === 42);
+    f.arguments = 44;
+    assert(f.arguments === 44);
+}
+
+{
+    let proxy = new Proxy({}, {
+        has(...args) {
+            throw new Error("Should not be called!");
+        }
+    });
+    for (let i = 0; i < 1000; ++i) {
+        test2(function () { "use strict"; }, proxy);
+        test2(class C { }, proxy);
+        test2(() => undefined, proxy);
+        test2(async function foo(){}, proxy);
+        test2(function* foo() { }, proxy);
+    }
+}
+
+for (let i = 0; i < 1000; ++i) {
+    test2(function () { "use strict"; });
+    test2(class C { });
+    test2(() => undefined);
+    test2(async function foo(){});
+    test2(function* foo() { });
+}
+
+function test3(f) {
+    f.__proto__ = {};
+    f.caller = 42;
+    assert(f.caller === 42);
+    assert(f.hasOwnProperty("caller"));
+    assert(delete f.caller === true);
+    assert(f.caller === undefined);
+    assert(!f.hasOwnProperty("caller"));
+
+    f.arguments = 44;
+    assert(f.arguments === 44);
+    assert(f.hasOwnProperty("arguments"));
+    assert(delete f.arguments === true);
+    assert(f.arguments === undefined);
+    assert(!f.hasOwnProperty("arguments"));
+}
+for (let i = 0; i < 1000; ++i) {
+    test3(function () { "use strict"; });
+    test3(class C { });
+    test3(() => undefined);
+    test3(async function foo(){});
+    test3(function* foo() { });
+}

Modified: trunk/Source/_javascript_Core/ChangeLog (225844 => 225845)


--- trunk/Source/_javascript_Core/ChangeLog	2017-12-13 17:19:24 UTC (rev 225844)
+++ trunk/Source/_javascript_Core/ChangeLog	2017-12-13 17:29:21 UTC (rev 225845)
@@ -1,5 +1,25 @@
 2017-12-13  Saam Barati  <[email protected]>
 
+        Fix how JSFunction handles "caller" and "arguments" for functions that don't have those properties
+        https://bugs.webkit.org/show_bug.cgi?id=163579
+        <rdar://problem/35455798>
+
+        Reviewed by Mark Lam.
+
+        Some functions in _javascript_ do not have the "caller" and "arguments" properties.
+        For example, strict functions do not. When reading our code that dealt with these
+        types of functions, it was simply all wrong. We were doing weird things depending
+        on the method table hook. This patch fixes this by doing what we should've been
+        doing all along: when the JSFunction does not own the "caller"/"arguments" property,
+        it should defer to its base class implementation for the various method table hooks.
+
+        * runtime/JSFunction.cpp:
+        (JSC::JSFunction::put):
+        (JSC::JSFunction::deleteProperty):
+        (JSC::JSFunction::defineOwnProperty):
+
+2017-12-13  Saam Barati  <[email protected]>
+
         TypeCheckHoistingPhase needs to emit a CheckStructureOrEmpty if it's doing it for |this|
         https://bugs.webkit.org/show_bug.cgi?id=180734
         <rdar://problem/35640547>

Modified: trunk/Source/_javascript_Core/runtime/JSFunction.cpp (225844 => 225845)


--- trunk/Source/_javascript_Core/runtime/JSFunction.cpp	2017-12-13 17:19:24 UTC (rev 225844)
+++ trunk/Source/_javascript_Core/runtime/JSFunction.cpp	2017-12-13 17:29:21 UTC (rev 225845)
@@ -471,17 +471,11 @@
     }
 
     if (propertyName == vm.propertyNames->arguments || propertyName == vm.propertyNames->caller) {
-        slot.disableCaching();
         if (!thisObject->jsExecutable()->hasCallerAndArgumentsProperties()) {
-            // This will trigger the property to be reified, if this is not already the case!
-            // FIXME: Investigate if the `hasProperty()` call is even needed, as in the `!hasCallerAndArgumentsProperties()` case,
-            // these properties are not lazy and should not need to be reified. (https://bugs.webkit.org/show_bug.cgi?id=163579)
-            bool okay = thisObject->hasProperty(exec, propertyName);
-            RETURN_IF_EXCEPTION(scope, false);
-            ASSERT_UNUSED(okay, okay);
             scope.release();
             return Base::put(thisObject, exec, propertyName, value, slot);
         }
+        slot.disableCaching();
         return typeError(exec, scope, slot.isStrictMode(), ASCIILiteral(ReadonlyPropertyWriteError));
     }
     PropertyStatus propertyType = thisObject->reifyLazyPropertyIfNeeded(vm, exec, propertyName);
@@ -501,8 +495,8 @@
         // For non-host functions, don't let these properties by deleted - except by DefineOwnProperty.
         FunctionExecutable* executable = thisObject->jsExecutable();
         
-        if (propertyName == vm.propertyNames->caller || propertyName == vm.propertyNames->arguments)
-            return !executable->hasCallerAndArgumentsProperties();
+        if ((propertyName == vm.propertyNames->caller || propertyName == vm.propertyNames->arguments) && executable->hasCallerAndArgumentsProperties())
+            return false;
 
         if (propertyName == vm.propertyNames->prototype && !executable->isArrowFunction())
             return false;
@@ -539,14 +533,6 @@
     bool valueCheck;
     if (propertyName == vm.propertyNames->arguments) {
         if (!thisObject->jsExecutable()->hasCallerAndArgumentsProperties()) {
-            if (thisObject->jsExecutable()->isClass()) {
-                thisObject->reifyLazyPropertyIfNeeded(vm, exec, propertyName);
-                scope.release();
-                return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
-            }
-            PropertySlot slot(thisObject, PropertySlot::InternalMethodType::VMInquiry);
-            if (!Base::getOwnPropertySlot(thisObject, exec, propertyName, slot))
-                thisObject->putDirectAccessor(exec, propertyName, thisObject->globalObject(vm)->throwTypeErrorArgumentsCalleeAndCallerGetterSetter(), PropertyAttribute::DontDelete | PropertyAttribute::DontEnum | PropertyAttribute::Accessor);
             scope.release();
             return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
         }
@@ -553,14 +539,6 @@
         valueCheck = !descriptor.value() || sameValue(exec, descriptor.value(), retrieveArguments(exec, thisObject));
     } else if (propertyName == vm.propertyNames->caller) {
         if (!thisObject->jsExecutable()->hasCallerAndArgumentsProperties()) {
-            if (thisObject->jsExecutable()->isClass()) {
-                thisObject->reifyLazyPropertyIfNeeded(vm, exec, propertyName);
-                scope.release();
-                return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
-            }
-            PropertySlot slot(thisObject, PropertySlot::InternalMethodType::VMInquiry);
-            if (!Base::getOwnPropertySlot(thisObject, exec, propertyName, slot))
-                thisObject->putDirectAccessor(exec, propertyName, thisObject->globalObject(vm)->throwTypeErrorArgumentsCalleeAndCallerGetterSetter(), PropertyAttribute::DontDelete | PropertyAttribute::DontEnum | PropertyAttribute::Accessor);
             scope.release();
             return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
         }
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to