DFG optimizations don't handle neutered arrays properly
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 1 Aug 2013 22:14:28 +0000 (22:14 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 1 Aug 2013 22:14:28 +0000 (22:14 +0000)
https://bugs.webkit.org/show_bug.cgi?id=119409

Reviewed by Mark Hahnenberg and Oliver Hunt.

Source/WebCore:

Test: fast/js/dfg-typed-array-neuter.

* bindings/js/SerializedScriptValue.cpp:
(WebCore::neuterView):
(WebCore::SerializedScriptValue::transferArrayBuffers):
(WebCore::SerializedScriptValue::create):
* bindings/js/SerializedScriptValue.h:

LayoutTests:

* fast/js/dfg-typed-array-neuter-expected.txt: Added.
* fast/js/dfg-typed-array-neuter.html: Added.
* fast/js/script-tests/dfg-typed-array-neuter.js: Added.
(foo):
(bar):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@153613 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/fast/js/dfg-typed-array-neuter-expected.txt [new file with mode: 0644]
LayoutTests/fast/js/dfg-typed-array-neuter.html [new file with mode: 0644]
LayoutTests/fast/js/script-tests/dfg-typed-array-neuter.js [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/bindings/js/SerializedScriptValue.cpp
Source/WebCore/bindings/js/SerializedScriptValue.h

index b3f2e6f..4053dca 100644 (file)
@@ -1,3 +1,16 @@
+2013-08-01  Filip Pizlo  <fpizlo@apple.com>
+
+        DFG optimizations don't handle neutered arrays properly
+        https://bugs.webkit.org/show_bug.cgi?id=119409
+
+        Reviewed by Mark Hahnenberg and Oliver Hunt.
+
+        * fast/js/dfg-typed-array-neuter-expected.txt: Added.
+        * fast/js/dfg-typed-array-neuter.html: Added.
+        * fast/js/script-tests/dfg-typed-array-neuter.js: Added.
+        (foo):
+        (bar):
+
 2013-08-01  Morten Stenshorne  <mstensho@opera.com>
 
         REGRESSION (Safari 6 - ToT): Incorrectly assumes that RenderStyle data can be shared
diff --git a/LayoutTests/fast/js/dfg-typed-array-neuter-expected.txt b/LayoutTests/fast/js/dfg-typed-array-neuter-expected.txt
new file mode 100644 (file)
index 0000000..2ae1b18
--- /dev/null
@@ -0,0 +1,17 @@
+Tests that DFG respects neutered typed arrays.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS array.length is 100
+PASS array[0] is 42
+PASS foo(array) is 100
+PASS bar(array) is 42
+PASS array.length is 0
+PASS array[0] is void 0
+PASS foo(array) is 0
+PASS bar(array) is void 0
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/js/dfg-typed-array-neuter.html b/LayoutTests/fast/js/dfg-typed-array-neuter.html
new file mode 100644 (file)
index 0000000..a20aeff
--- /dev/null
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="script-tests/dfg-typed-array-neuter.js"></script>
+<script src="resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/js/script-tests/dfg-typed-array-neuter.js b/LayoutTests/fast/js/script-tests/dfg-typed-array-neuter.js
new file mode 100644 (file)
index 0000000..929ae2b
--- /dev/null
@@ -0,0 +1,30 @@
+description(
+"Tests that DFG respects neutered typed arrays."
+);
+
+var array = new Int8Array(100);
+array[0] = 42;
+shouldBe("array.length", "100");
+shouldBe("array[0]", "42");
+
+function foo(array) { return array.length; }
+function bar(array) { return array[0]; }
+
+noInline(foo);
+noInline(bar);
+
+while (!dfgCompiled({f:[foo, bar]})) {
+    foo(array);
+    bar(array);
+}
+
+shouldBe("foo(array)", "100");
+shouldBe("bar(array)", "42");
+
+window.postMessage(array, "*", [array.buffer]);
+
+shouldBe("array.length", "0");
+shouldBe("array[0]", "void 0");
+
+shouldBe("foo(array)", "0");
+shouldBe("bar(array)", "void 0");
index eb1dda0..0f4a245 100644 (file)
@@ -1,3 +1,18 @@
+2013-08-01  Filip Pizlo  <fpizlo@apple.com>
+
+        DFG optimizations don't handle neutered arrays properly
+        https://bugs.webkit.org/show_bug.cgi?id=119409
+
+        Reviewed by Mark Hahnenberg and Oliver Hunt.
+
+        Test: fast/js/dfg-typed-array-neuter.
+
+        * bindings/js/SerializedScriptValue.cpp:
+        (WebCore::neuterView):
+        (WebCore::SerializedScriptValue::transferArrayBuffers):
+        (WebCore::SerializedScriptValue::create):
+        * bindings/js/SerializedScriptValue.h:
+
 2013-08-01  Morten Stenshorne  <mstensho@opera.com>
 
         REGRESSION (Safari 6 - ToT): Incorrectly assumes that RenderStyle data can be shared
index 3d79b03..126a04b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2009, 2013 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -54,6 +54,7 @@
 #include "NotImplemented.h"
 #include "ScriptValue.h"
 #include "SharedBuffer.h"
+#include "WebCoreJSClientData.h"
 #include <limits>
 #include <JavaScriptCore/APICast.h>
 #include <JavaScriptCore/APIShims.h>
@@ -1721,8 +1722,49 @@ SerializedScriptValue::SerializedScriptValue(Vector<uint8_t>& buffer, Vector<Str
     m_blobURLs.swap(blobURLs);
 }
 
+static void neuterView(JSCell* jsView)
+{
+    if (!jsView)
+        return;
+    
+    switch (jsView->classInfo()->typedArrayStorageType) {
+    case TypedArrayNone:
+        // This could be a DataView, for example. Assume that there are views that the
+        // DFG doesn't care about.
+        return;
+    case TypedArrayInt8:
+        jsCast<JSInt8Array*>(jsView)->m_storageLength = 0;
+        return;
+    case TypedArrayInt16:
+        jsCast<JSInt16Array*>(jsView)->m_storageLength = 0;
+        return;
+    case TypedArrayInt32:
+        jsCast<JSInt32Array*>(jsView)->m_storageLength = 0;
+        return;
+    case TypedArrayUint8:
+        jsCast<JSUint8Array*>(jsView)->m_storageLength = 0;
+        return;
+    case TypedArrayUint8Clamped:
+        jsCast<JSUint8ClampedArray*>(jsView)->m_storageLength = 0;
+        return;
+    case TypedArrayUint16:
+        jsCast<JSUint16Array*>(jsView)->m_storageLength = 0;
+        return;
+    case TypedArrayUint32:
+        jsCast<JSUint32Array*>(jsView)->m_storageLength = 0;
+        return;
+    case TypedArrayFloat32:
+        jsCast<JSFloat32Array*>(jsView)->m_storageLength = 0;
+        return;
+    case TypedArrayFloat64:
+        jsCast<JSFloat64Array*>(jsView)->m_storageLength = 0;
+        return;
+    }
+    RELEASE_ASSERT_NOT_REACHED();
+}
+
 PassOwnPtr<SerializedScriptValue::ArrayBufferContentsArray> SerializedScriptValue::transferArrayBuffers(
-    ArrayBufferArray& arrayBuffers, SerializationReturnCode& code)
+    ExecState* exec, ArrayBufferArray& arrayBuffers, SerializationReturnCode& code)
 {
     for (size_t i = 0; i < arrayBuffers.size(); i++) {
         if (arrayBuffers[i]->isNeutered()) {
@@ -1732,20 +1774,31 @@ PassOwnPtr<SerializedScriptValue::ArrayBufferContentsArray> SerializedScriptValu
     }
 
     OwnPtr<ArrayBufferContentsArray> contents = adoptPtr(new ArrayBufferContentsArray(arrayBuffers.size()));
+    Vector<RefPtr<DOMWrapperWorld> > worlds;
+    static_cast<WebCoreJSClientData*>(exec->vm().clientData)->getAllWorlds(worlds);
 
     HashSet<WTF::ArrayBuffer*> visited;
-    for (size_t i = 0; i < arrayBuffers.size(); i++) {
+    for (size_t arrayBufferIndex = 0; arrayBufferIndex < arrayBuffers.size(); arrayBufferIndex++) {
         Vector<RefPtr<ArrayBufferView> > neuteredViews;
 
-        if (visited.contains(arrayBuffers[i].get()))
+        if (visited.contains(arrayBuffers[arrayBufferIndex].get()))
             continue;
-        visited.add(arrayBuffers[i].get());
+        visited.add(arrayBuffers[arrayBufferIndex].get());
 
-        bool result = arrayBuffers[i]->transfer(contents->at(i), neuteredViews);
+        bool result = arrayBuffers[arrayBufferIndex]->transfer(contents->at(arrayBufferIndex), neuteredViews);
         if (!result) {
             code = ValidationError;
             return nullptr;
         }
+        
+        // The views may have been neutered, but their wrappers also need to be neutered, too.
+        for (size_t viewIndex = neuteredViews.size(); viewIndex--;) {
+            ArrayBufferView* view = neuteredViews[viewIndex].get();
+            for (size_t worldIndex = worlds.size(); worldIndex--;) {
+                DOMWrapperWorld* world = worlds[worldIndex].get();
+                neuterView(getCachedWrapper(world, view));
+            }
+        }
     }
     return contents.release();
 }
@@ -1762,7 +1815,7 @@ PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(ExecState* exec,
     OwnPtr<ArrayBufferContentsArray> arrayBufferContentsArray;
 
     if (arrayBuffers && serializationDidCompleteSuccessfully(code))
-        arrayBufferContentsArray = transferArrayBuffers(*arrayBuffers, code);
+        arrayBufferContentsArray = transferArrayBuffers(exec, *arrayBuffers, code);
 
     if (throwExceptions == Throwing)
         maybeThrowExceptionIfSerializationFailed(exec, code);
index 6005b12..d3cd880 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2009, 2013 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -116,7 +116,7 @@ private:
     typedef Vector<WTF::ArrayBufferContents> ArrayBufferContentsArray;
     static void maybeThrowExceptionIfSerializationFailed(JSC::ExecState*, SerializationReturnCode);
     static bool serializationDidCompleteSuccessfully(SerializationReturnCode);
-    static PassOwnPtr<ArrayBufferContentsArray> transferArrayBuffers(ArrayBufferArray&, SerializationReturnCode&);
+    static PassOwnPtr<ArrayBufferContentsArray> transferArrayBuffers(JSC::ExecState*, ArrayBufferArray&, SerializationReturnCode&);
 
     SerializedScriptValue(const Vector<unsigned char>&);
     SerializedScriptValue(Vector<unsigned char>&);