Title: [201808] trunk
Revision
201808
Author
cdu...@apple.com
Date
2016-06-08 10:31:12 -0700 (Wed, 08 Jun 2016)

Log Message

self.hasOwnProperty() does not work inside Web workers
https://bugs.webkit.org/show_bug.cgi?id=158446
<rdar://problem/26638397>

Reviewed by Geoffrey Garen.

Source/_javascript_Core:

Add a factory function to JSProxy to create a JSProxy without a target.
Also make the setTarget() method public so that the target can now be
set after creation. This is needed so that we can create a proxy for
JSWorkerGlobalScope, then create the JSWorkerGlobalScope object,
passing it the proxy and finally set the target on the proxy.

* runtime/JSProxy.h:
(JSC::JSProxy::create):

Source/WebCore:

W3C tests for workers were severely broken on WebKit because
self.hasOwnProperty() did not work inside workers. The reason is that
hasOwnProperty() (and other methods like toString()) call toThis() in
StrictMode on thisValue. However, in the case of 'self' in workers,
self was a DedicatedWorkerGlobalScope, which is a JSGlobalObject.
JSGlobalObject::toThis() returns jsUndefined() when called in strict
mode. As a result, we would end up with exceptions such as "undefined
is not an object" when calling self.hasOwnProperty() in workers.

To address the problem, this patch introduces a JSProxy whose proxy
type is PureForwardingProxyType and whose target is the
WorkerGlobalScope. This JSProxy is what we expose to the _javascript_,
instead of the JSWorkerGlobalScope itself. As a result, toThis() now
behaves as expected and self.hasOwnProperty() works inside workers.

This patch greatly improves our pass rate on several W3C tests:
http://w3c-test.org/workers/interfaces.worker: 20 passes -> 50 passes (out of 128)
http://w3c-test.org/IndexedDB/interfaces.worker 0 passes -> 145 passes (out of 156)

Tests: fast/workers/self-hasOwnProperty.html
       fast/workers/self-toString.html

* bindings/js/JSWorkerGlobalScopeBase.cpp:
(WebCore::JSWorkerGlobalScopeBase::finishCreation):
(WebCore::JSWorkerGlobalScopeBase::visitChildren):
(WebCore::toJS):
* bindings/js/JSWorkerGlobalScopeBase.h:
(WebCore::JSWorkerGlobalScopeBase::proxy):
* bindings/js/WorkerScriptController.cpp:
(WebCore::WorkerScriptController::initScript):
* bindings/scripts/CodeGeneratorJS.pm:
(GenerateHeader):
(GenerateImplementation):

LayoutTests:

Add tests to make sure that self.toString() and self.hasOwnProperty()
now work in workers.

* fast/workers/self-hasOwnProperty-expected.txt: Added.
* fast/workers/self-hasOwnProperty.html: Added.
* fast/workers/self-toString-expected.txt: Added.
* fast/workers/self-toString.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (201807 => 201808)


--- trunk/LayoutTests/ChangeLog	2016-06-08 17:21:52 UTC (rev 201807)
+++ trunk/LayoutTests/ChangeLog	2016-06-08 17:31:12 UTC (rev 201808)
@@ -1,3 +1,19 @@
+2016-06-08  Chris Dumez  <cdu...@apple.com>
+
+        self.hasOwnProperty() does not work inside Web workers
+        https://bugs.webkit.org/show_bug.cgi?id=158446
+        <rdar://problem/26638397>
+
+        Reviewed by Geoffrey Garen.
+
+        Add tests to make sure that self.toString() and self.hasOwnProperty()
+        now work in workers.
+
+        * fast/workers/self-hasOwnProperty-expected.txt: Added.
+        * fast/workers/self-hasOwnProperty.html: Added.
+        * fast/workers/self-toString-expected.txt: Added.
+        * fast/workers/self-toString.html: Added.
+
 2016-06-06  Antti Koivisto  <an...@apple.com>
 
         WebKit memory cache doesn't respect Vary header

Added: trunk/LayoutTests/fast/workers/self-hasOwnProperty-expected.txt (0 => 201808)


--- trunk/LayoutTests/fast/workers/self-hasOwnProperty-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/workers/self-hasOwnProperty-expected.txt	2016-06-08 17:31:12 UTC (rev 201808)
@@ -0,0 +1,12 @@
+Tests that self.hasOwnProperty() works in workers
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+self.hasOwnProperty('DedicatedWorkerGlobalScope'): true
+self.hasOwnProperty('WorkerGlobalScope'): true
+self.hasOwnProperty('navigator'): true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/fast/workers/self-hasOwnProperty.html (0 => 201808)


--- trunk/LayoutTests/fast/workers/self-hasOwnProperty.html	                        (rev 0)
+++ trunk/LayoutTests/fast/workers/self-hasOwnProperty.html	2016-06-08 17:31:12 UTC (rev 201808)
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<script src=""
+<script src=""
+<script>
+
+var jsTestIsAsync = true;
+
+description('Tests that self.hasOwnProperty() works in workers');
+
+var worker = createWorker();
+worker.postMessage("eval self.hasOwnProperty('DedicatedWorkerGlobalScope')");
+worker.postMessage("eval self.hasOwnProperty('WorkerGlobalScope')");
+worker.postMessage("eval self.hasOwnProperty('navigator')");
+worker.postMessage("eval DONE");
+
+worker._onmessage_ = function(evt) {
+    if (!/DONE/.test(evt.data))
+        debug(evt.data.replace(new RegExp("/.*LayoutTests"), "<...>"));
+    else
+        finishJSTest();
+};
+
+</script>
+<script src=""

Added: trunk/LayoutTests/fast/workers/self-toString-expected.txt (0 => 201808)


--- trunk/LayoutTests/fast/workers/self-toString-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/workers/self-toString-expected.txt	2016-06-08 17:31:12 UTC (rev 201808)
@@ -0,0 +1,11 @@
+Tests that self.toString() works in workers
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+self.toString(): [object DedicatedWorkerGlobalScope]
+'self: ' + self: self: [object DedicatedWorkerGlobalScope]
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/fast/workers/self-toString.html (0 => 201808)


--- trunk/LayoutTests/fast/workers/self-toString.html	                        (rev 0)
+++ trunk/LayoutTests/fast/workers/self-toString.html	2016-06-08 17:31:12 UTC (rev 201808)
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<script src=""
+<script src=""
+<script>
+
+var jsTestIsAsync = true;
+
+description('Tests that self.toString() works in workers');
+
+var worker = createWorker();
+worker.postMessage("eval self.toString()");
+worker.postMessage("eval 'self: ' + self");
+worker.postMessage("eval DONE");
+
+worker._onmessage_ = function(evt) {
+    if (!/DONE/.test(evt.data))
+        debug(evt.data.replace(new RegExp("/.*LayoutTests"), "<...>"));
+    else
+        finishJSTest();
+};
+
+</script>
+<script src=""

Modified: trunk/Source/_javascript_Core/ChangeLog (201807 => 201808)


--- trunk/Source/_javascript_Core/ChangeLog	2016-06-08 17:21:52 UTC (rev 201807)
+++ trunk/Source/_javascript_Core/ChangeLog	2016-06-08 17:31:12 UTC (rev 201808)
@@ -1,3 +1,20 @@
+2016-06-08  Chris Dumez  <cdu...@apple.com>
+
+        self.hasOwnProperty() does not work inside Web workers
+        https://bugs.webkit.org/show_bug.cgi?id=158446
+        <rdar://problem/26638397>
+
+        Reviewed by Geoffrey Garen.
+
+        Add a factory function to JSProxy to create a JSProxy without a target.
+        Also make the setTarget() method public so that the target can now be
+        set after creation. This is needed so that we can create a proxy for
+        JSWorkerGlobalScope, then create the JSWorkerGlobalScope object,
+        passing it the proxy and finally set the target on the proxy.
+
+        * runtime/JSProxy.h:
+        (JSC::JSProxy::create):
+
 2016-06-07  Filip Pizlo  <fpi...@apple.com>
 
         Add result validation to JSAir

Modified: trunk/Source/_javascript_Core/runtime/JSProxy.h (201807 => 201808)


--- trunk/Source/_javascript_Core/runtime/JSProxy.h	2016-06-08 17:21:52 UTC (rev 201807)
+++ trunk/Source/_javascript_Core/runtime/JSProxy.h	2016-06-08 17:31:12 UTC (rev 201808)
@@ -42,6 +42,13 @@
         return proxy;
     }
 
+    static JSProxy* create(VM& vm, Structure* structure)
+    {
+        JSProxy* proxy = new (NotNull, allocateCell<JSProxy>(vm.heap)) JSProxy(vm, structure);
+        proxy->finishCreation(vm);
+        return proxy;
+    }
+
     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype, JSType proxyType)
     {
         ASSERT(proxyType == ImpureProxyType || proxyType == PureForwardingProxyType);
@@ -53,6 +60,8 @@
     JSObject* target() const { return m_target.get(); }
     static ptrdiff_t targetOffset() { return OBJECT_OFFSETOF(JSProxy, m_target); }
 
+    JS_EXPORT_PRIVATE void setTarget(VM&, JSGlobalObject*);
+
 protected:
     JSProxy(VM& vm, Structure* structure)
         : JSDestructibleObject(vm, structure)
@@ -72,8 +81,6 @@
 
     JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&);
 
-    JS_EXPORT_PRIVATE void setTarget(VM&, JSGlobalObject*);
-
     JS_EXPORT_PRIVATE static String className(const JSObject*);
     JS_EXPORT_PRIVATE static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
     JS_EXPORT_PRIVATE static bool getOwnPropertySlotByIndex(JSObject*, ExecState*, unsigned, PropertySlot&);

Modified: trunk/Source/WebCore/ChangeLog (201807 => 201808)


--- trunk/Source/WebCore/ChangeLog	2016-06-08 17:21:52 UTC (rev 201807)
+++ trunk/Source/WebCore/ChangeLog	2016-06-08 17:31:12 UTC (rev 201808)
@@ -1,3 +1,45 @@
+2016-06-08  Chris Dumez  <cdu...@apple.com>
+
+        self.hasOwnProperty() does not work inside Web workers
+        https://bugs.webkit.org/show_bug.cgi?id=158446
+        <rdar://problem/26638397>
+
+        Reviewed by Geoffrey Garen.
+
+        W3C tests for workers were severely broken on WebKit because
+        self.hasOwnProperty() did not work inside workers. The reason is that
+        hasOwnProperty() (and other methods like toString()) call toThis() in
+        StrictMode on thisValue. However, in the case of 'self' in workers,
+        self was a DedicatedWorkerGlobalScope, which is a JSGlobalObject.
+        JSGlobalObject::toThis() returns jsUndefined() when called in strict
+        mode. As a result, we would end up with exceptions such as "undefined
+        is not an object" when calling self.hasOwnProperty() in workers.
+
+        To address the problem, this patch introduces a JSProxy whose proxy
+        type is PureForwardingProxyType and whose target is the
+        WorkerGlobalScope. This JSProxy is what we expose to the _javascript_,
+        instead of the JSWorkerGlobalScope itself. As a result, toThis() now
+        behaves as expected and self.hasOwnProperty() works inside workers.
+
+        This patch greatly improves our pass rate on several W3C tests:
+        http://w3c-test.org/workers/interfaces.worker: 20 passes -> 50 passes (out of 128)
+        http://w3c-test.org/IndexedDB/interfaces.worker 0 passes -> 145 passes (out of 156)
+
+        Tests: fast/workers/self-hasOwnProperty.html
+               fast/workers/self-toString.html
+
+        * bindings/js/JSWorkerGlobalScopeBase.cpp:
+        (WebCore::JSWorkerGlobalScopeBase::finishCreation):
+        (WebCore::JSWorkerGlobalScopeBase::visitChildren):
+        (WebCore::toJS):
+        * bindings/js/JSWorkerGlobalScopeBase.h:
+        (WebCore::JSWorkerGlobalScopeBase::proxy):
+        * bindings/js/WorkerScriptController.cpp:
+        (WebCore::WorkerScriptController::initScript):
+        * bindings/scripts/CodeGeneratorJS.pm:
+        (GenerateHeader):
+        (GenerateImplementation):
+
 2016-06-08  Antti Koivisto  <an...@apple.com>
 
         WebKit memory cache doesn't respect Vary header

Modified: trunk/Source/WebCore/bindings/js/JSWorkerGlobalScopeBase.cpp (201807 => 201808)


--- trunk/Source/WebCore/bindings/js/JSWorkerGlobalScopeBase.cpp	2016-06-08 17:21:52 UTC (rev 201807)
+++ trunk/Source/WebCore/bindings/js/JSWorkerGlobalScopeBase.cpp	2016-06-08 17:31:12 UTC (rev 201808)
@@ -35,6 +35,7 @@
 #include "JSWorkerGlobalScope.h"
 #include "Language.h"
 #include "WorkerGlobalScope.h"
+#include <runtime/JSCInlines.h>
 #include <runtime/JSCJSValueInlines.h>
 #include <runtime/Microtask.h>
 
@@ -52,12 +53,22 @@
 {
 }
 
-void JSWorkerGlobalScopeBase::finishCreation(VM& vm)
+void JSWorkerGlobalScopeBase::finishCreation(VM& vm, JSProxy* proxy)
 {
-    Base::finishCreation(vm);
+    m_proxy.set(vm, this, proxy);
+
+    Base::finishCreation(vm, m_proxy.get());
     ASSERT(inherits(info()));
 }
 
+void JSWorkerGlobalScopeBase::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+    JSWorkerGlobalScopeBase* thisObject = jsCast<JSWorkerGlobalScopeBase*>(cell);
+    ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+    Base::visitChildren(thisObject, visitor);
+    visitor.append(&thisObject->m_proxy);
+}
+
 void JSWorkerGlobalScopeBase::destroy(JSCell* cell)
 {
     static_cast<JSWorkerGlobalScopeBase*>(cell)->JSWorkerGlobalScopeBase::~JSWorkerGlobalScopeBase();
@@ -111,7 +122,7 @@
         return jsNull();
     JSWorkerGlobalScope* contextWrapper = script->workerGlobalScopeWrapper();
     ASSERT(contextWrapper);
-    return contextWrapper;
+    return contextWrapper->proxy();
 }
 
 JSDedicatedWorkerGlobalScope* toJSDedicatedWorkerGlobalScope(JSValue value)

Modified: trunk/Source/WebCore/bindings/js/JSWorkerGlobalScopeBase.h (201807 => 201808)


--- trunk/Source/WebCore/bindings/js/JSWorkerGlobalScopeBase.h	2016-06-08 17:21:52 UTC (rev 201807)
+++ trunk/Source/WebCore/bindings/js/JSWorkerGlobalScopeBase.h	2016-06-08 17:31:12 UTC (rev 201808)
@@ -43,6 +43,7 @@
         DECLARE_INFO;
 
         WorkerGlobalScope& wrapped() const { return *m_wrapped; }
+        JSC::JSProxy* proxy() const { ASSERT(m_proxy); return m_proxy.get(); }
         ScriptExecutionContext* scriptExecutionContext() const;
 
         static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
@@ -61,10 +62,13 @@
 
     protected:
         JSWorkerGlobalScopeBase(JSC::VM&, JSC::Structure*, RefPtr<WorkerGlobalScope>&&);
-        void finishCreation(JSC::VM&);
+        void finishCreation(JSC::VM&, JSC::JSProxy*);
 
+        static void visitChildren(JSC::JSCell*, JSC::SlotVisitor&);
+
     private:
         RefPtr<WorkerGlobalScope> m_wrapped;
+        JSC::WriteBarrier<JSC::JSProxy> m_proxy;
     };
 
     // Returns a JSWorkerGlobalScope or jsNull()

Modified: trunk/Source/WebCore/bindings/js/WorkerScriptController.cpp (201807 => 201808)


--- trunk/Source/WebCore/bindings/js/WorkerScriptController.cpp	2016-06-08 17:21:52 UTC (rev 201807)
+++ trunk/Source/WebCore/bindings/js/WorkerScriptController.cpp	2016-06-08 17:31:12 UTC (rev 201808)
@@ -88,8 +88,10 @@
         Structure* dedicatedContextPrototypeStructure = JSDedicatedWorkerGlobalScopePrototype::createStructure(*m_vm, 0, workerGlobalScopePrototype.get());
         Strong<JSDedicatedWorkerGlobalScopePrototype> dedicatedContextPrototype(*m_vm, JSDedicatedWorkerGlobalScopePrototype::create(*m_vm, 0, dedicatedContextPrototypeStructure));
         Structure* structure = JSDedicatedWorkerGlobalScope::createStructure(*m_vm, 0, dedicatedContextPrototype.get());
+        auto* proxyStructure = JSProxy::createStructure(*m_vm, nullptr, jsNull(), PureForwardingProxyType);
+        auto* proxy = JSProxy::create(*m_vm, proxyStructure);
 
-        m_workerGlobalScopeWrapper.set(*m_vm, JSDedicatedWorkerGlobalScope::create(*m_vm, structure, static_cast<DedicatedWorkerGlobalScope&>(*m_workerGlobalScope)));
+        m_workerGlobalScopeWrapper.set(*m_vm, JSDedicatedWorkerGlobalScope::create(*m_vm, structure, static_cast<DedicatedWorkerGlobalScope&>(*m_workerGlobalScope), proxy));
         workerGlobalScopePrototypeStructure->setGlobalObject(*m_vm, m_workerGlobalScopeWrapper.get());
         dedicatedContextPrototypeStructure->setGlobalObject(*m_vm, m_workerGlobalScopeWrapper.get());
         ASSERT(structure->globalObject() == m_workerGlobalScopeWrapper);
@@ -97,6 +99,9 @@
         workerGlobalScopePrototype->structure()->setGlobalObject(*m_vm, m_workerGlobalScopeWrapper.get());
         workerGlobalScopePrototype->structure()->setPrototypeWithoutTransition(*m_vm, JSEventTarget::prototype(*m_vm, m_workerGlobalScopeWrapper.get()));
         dedicatedContextPrototype->structure()->setGlobalObject(*m_vm, m_workerGlobalScopeWrapper.get());
+
+        proxy->setTarget(*m_vm, m_workerGlobalScopeWrapper.get());
+        proxy->structure()->setGlobalObject(*m_vm, m_workerGlobalScopeWrapper.get());
     }
     ASSERT(m_workerGlobalScopeWrapper->globalObject() == m_workerGlobalScopeWrapper);
     ASSERT(asObject(m_workerGlobalScopeWrapper->getPrototypeDirect())->globalObject() == m_workerGlobalScopeWrapper);

Modified: trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm (201807 => 201808)


--- trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm	2016-06-08 17:21:52 UTC (rev 201807)
+++ trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm	2016-06-08 17:31:12 UTC (rev 201808)
@@ -1101,10 +1101,10 @@
         push(@headerContent, "        return ptr;\n");
         push(@headerContent, "    }\n\n");
     } elsif ($codeGenerator->InheritsInterface($interface, "WorkerGlobalScope")) {
-        push(@headerContent, "    static $className* create(JSC::VM& vm, JSC::Structure* structure, Ref<$implType>&& impl)\n");
+        push(@headerContent, "    static $className* create(JSC::VM& vm, JSC::Structure* structure, Ref<$implType>&& impl, JSC::JSProxy* proxy)\n");
         push(@headerContent, "    {\n");
         push(@headerContent, "        $className* ptr = new (NotNull, JSC::allocateCell<$className>(vm.heap)) ${className}(vm, structure, WTFMove(impl));\n");
-        push(@headerContent, "        ptr->finishCreation(vm);\n");
+        push(@headerContent, "        ptr->finishCreation(vm, proxy);\n");
         push(@headerContent, "        vm.heap.addFinalizer(ptr, destroy);\n");
         push(@headerContent, "        return ptr;\n");
         push(@headerContent, "    }\n\n");
@@ -1416,7 +1416,7 @@
         if ($interfaceName eq "DOMWindow") {
             push(@headerContent, "    void finishCreation(JSC::VM&, JSDOMWindowShell*);\n");
         } else {
-            push(@headerContent, "    void finishCreation(JSC::VM&);\n");
+            push(@headerContent, "    void finishCreation(JSC::VM&, JSC::JSProxy*);\n");
         }
     }
 
@@ -2359,9 +2359,9 @@
             push(@implContent, "{\n");
             push(@implContent, "    Base::finishCreation(vm, shell);\n\n");
         } else {
-            push(@implContent, "void ${className}::finishCreation(VM& vm)\n");
+            push(@implContent, "void ${className}::finishCreation(VM& vm, JSProxy* proxy)\n");
             push(@implContent, "{\n");
-            push(@implContent, "    Base::finishCreation(vm);\n\n");
+            push(@implContent, "    Base::finishCreation(vm, proxy);\n\n");
         }
         # Support for RuntimeEnabled attributes on global objects.
         foreach my $attribute (@{$interface->attributes}) {
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to