REGRESSION: 2x regression on Dromaeo DOM query tests
authorrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 16 Dec 2013 05:56:25 +0000 (05:56 +0000)
committerrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 16 Dec 2013 05:56:25 +0000 (05:56 +0000)
https://bugs.webkit.org/show_bug.cgi?id=125377

Reviewed by Filip Pizlo.

PerformanceTests:

Added a micro-benchmark for updating a named property on document.

* Bindings/update-name-getter.html: Added.
* Skipped:

Source/JavaScriptCore:

The bug was caused by JSC not JIT'ing property access on "document" due to its type info having
HasImpureGetOwnPropertySlot flag.

Fixed the bug by new type info flag NewImpurePropertyFiresWatchpoints, which allows the baseline
JIT to generate byte code for access properties on an object with named properties (a.k.a.
custom name getter) in DOM. When a new named property appears on the object, VM is notified via
VM::addImpureProperty and fires StructureStubClearingWatchpoint added during the repatch.

* bytecode/GetByIdStatus.cpp:
(JSC::GetByIdStatus::computeFromLLInt): Take the slow path if we have any object with impure
properties in the prototype chain.
(JSC::GetByIdStatus::computeForChain): Ditto.

* jit/Repatch.cpp:
(JSC::repatchByIdSelfAccess): Throw away the byte code when a new impure property is added on any
object in the prototype chain via StructureStubClearingWatchpoint.
(JSC::generateProtoChainAccessStub): Ditto.
(JSC::tryCacheGetByID):
(JSC::tryBuildGetByIDList):
(JSC::tryRepatchIn): Ditto.

* runtime/JSTypeInfo.h: Added NewImpurePropertyFiresWatchpoints.
(JSC::TypeInfo::newImpurePropertyFiresWatchpoints): Added.

* runtime/Operations.h:
(JSC::normalizePrototypeChainForChainAccess): Don't exit early if VM will be notified of new
impure property even if the object had impure properties.

* runtime/Structure.h:
(JSC::Structure::takesSlowPathInDFGForImpureProperty): Added. Wraps hasImpureGetOwnPropertySlot and
asserts that newImpurePropertyFiresWatchpoints is true whenever hasImpureGetOwnPropertySlot is true.

* runtime/VM.cpp:
(JSC::VM::registerWatchpointForImpureProperty): Added.
(JSC::VM::addImpureProperty): Added. HTMLDocument calls it to notify JSC of a new impure property.

* runtime/VM.h:

Source/WebCore:

The bug was caused by JSC not JIT'ing property accesses on document because of its having
custom named getter (named properties).  This resulted in resolution of methods on document
such as getElementById to happen inside the interpreter.

Fixed the bug by using the new JSC type info flag which tells JSC to JIT property access on
document, and then notifying JSC whenever a new named property appeared on document.

Tests: js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-2.html
       js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-3.html
       js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-4.html
       js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-2.html
       js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-3.html
       js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-4.html

* bindings/js/JSDOMBinding.cpp:
(WebCore::addImpureProperty): Wraps VM::addImpureProperty.
* bindings/js/JSDOMBinding.h:
* bindings/scripts/CodeGeneratorJS.pm:
(GenerateHeader): Added the support for NewImpurePropertyFiresWatchpoints.
* bindings/scripts/IDLAttributes.txt: Ditto.
* html/HTMLDocument.cpp:
(WebCore::HTMLDocument::addDocumentNamedItem): Calls addImpureProperty.
* html/HTMLDocument.idl: Added NewImpurePropertyFiresWatchpoints.

LayoutTests:

Added more regression tests for throwing away byte code when a new named property appears.

* js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-expected: Rebaselined.
* js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps.html: Fixed the test to use dfgShouldBe.
* js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-2-expected.txt: Added.
* js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-2.html: Added.
* js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-3-expected.txt: Added.
* js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-3.html: Added.
* js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-4-expected.txt: Added.
* js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-4.html: Added.
* js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-5-expected.txt: Added.
* js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-5.html: Added.
* js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-2-expected.txt: Added.
* js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-2.html: Added.
* js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-3-expected.txt: Added.
* js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-3.html: Added.
* js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-4-expected.txt: Added.
* js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-4.html: Added.
* js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-5-expected.txt: Added.
* js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-5.html: Added.
* js/dom/script-tests/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps.js: Removed.

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

38 files changed:
LayoutTests/ChangeLog
LayoutTests/js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-2-expected.txt [new file with mode: 0644]
LayoutTests/js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-2.html [new file with mode: 0644]
LayoutTests/js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-3-expected.txt [new file with mode: 0644]
LayoutTests/js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-3.html [new file with mode: 0644]
LayoutTests/js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-4-expected.txt [new file with mode: 0644]
LayoutTests/js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-4.html [new file with mode: 0644]
LayoutTests/js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-5-expected.txt [new file with mode: 0644]
LayoutTests/js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-5.html [new file with mode: 0644]
LayoutTests/js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-expected.txt
LayoutTests/js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps.html
LayoutTests/js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-2-expected.txt [new file with mode: 0644]
LayoutTests/js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-2.html [new file with mode: 0644]
LayoutTests/js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-3-expected.txt [new file with mode: 0644]
LayoutTests/js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-3.html [new file with mode: 0644]
LayoutTests/js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-4-expected.txt [new file with mode: 0644]
LayoutTests/js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-4.html [new file with mode: 0644]
LayoutTests/js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-5-expected.txt [new file with mode: 0644]
LayoutTests/js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-5.html [new file with mode: 0644]
LayoutTests/js/dom/script-tests/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps.js [deleted file]
PerformanceTests/Bindings/update-name-getter.html [new file with mode: 0644]
PerformanceTests/ChangeLog
PerformanceTests/Skipped
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/bytecode/GetByIdStatus.cpp
Source/JavaScriptCore/jit/Repatch.cpp
Source/JavaScriptCore/runtime/JSTypeInfo.h
Source/JavaScriptCore/runtime/Operations.h
Source/JavaScriptCore/runtime/Structure.h
Source/JavaScriptCore/runtime/VM.cpp
Source/JavaScriptCore/runtime/VM.h
Source/WebCore/ChangeLog
Source/WebCore/bindings/js/JSDOMBinding.cpp
Source/WebCore/bindings/js/JSDOMBinding.h
Source/WebCore/bindings/scripts/CodeGeneratorJS.pm
Source/WebCore/bindings/scripts/IDLAttributes.txt
Source/WebCore/html/HTMLDocument.cpp
Source/WebCore/html/HTMLDocument.idl

index f547d3c..73358a7 100644 (file)
@@ -1,3 +1,32 @@
+2013-12-15  Ryosuke Niwa  <rniwa@webkit.org>
+
+        REGRESSION: 2x regression on Dromaeo DOM query tests
+        https://bugs.webkit.org/show_bug.cgi?id=125377
+
+        Reviewed by Filip Pizlo.
+
+        Added more regression tests for throwing away byte code when a new named property appears.
+        
+        * js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-expected: Rebaselined.
+        * js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps.html: Fixed the test to use dfgShouldBe.
+        * js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-2-expected.txt: Added.
+        * js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-2.html: Added.
+        * js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-3-expected.txt: Added.
+        * js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-3.html: Added.
+        * js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-4-expected.txt: Added.
+        * js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-4.html: Added.
+        * js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-5-expected.txt: Added.
+        * js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-5.html: Added.
+        * js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-2-expected.txt: Added.
+        * js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-2.html: Added.
+        * js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-3-expected.txt: Added.
+        * js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-3.html: Added.
+        * js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-4-expected.txt: Added.
+        * js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-4.html: Added.
+        * js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-5-expected.txt: Added.
+        * js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-5.html: Added.
+        * js/dom/script-tests/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps.js: Removed.
+
 2013-12-15  Rob Buis  <rob.buis@samsung.com>
 
         [CSS Shapes] shape-outside animation does not handle 'auto' well
diff --git a/LayoutTests/js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-2-expected.txt b/LayoutTests/js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-2-expected.txt
new file mode 100644 (file)
index 0000000..a5e4dc7
--- /dev/null
@@ -0,0 +1,11 @@
+Tests what happens when you make prototype chain accesses with impure GetOwnPropertySlot traps in the way.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS typeof f() is "function" on all iterations including after DFG tier-up.
+PASS typeof f() is "object"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-2.html b/LayoutTests/js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-2.html
new file mode 100644 (file)
index 0000000..c3f7244
--- /dev/null
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src="../../resources/js-test-pre.js"></script>
+<script>
+
+description("Tests what happens when you make prototype chain accesses with impure GetOwnPropertySlot traps in the way.");
+
+var obj = {};
+obj.__proto__ = document;
+
+function f() {
+    return obj.getElementsByTagName;
+}
+
+dfgShouldBe(f, "typeof f()", "\"function\"");
+
+var img = new Image();
+img.name = "getElementsByTagName";
+document.body.appendChild(img);
+
+shouldBe("typeof f()", "\"object\"");
+
+</script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-3-expected.txt b/LayoutTests/js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-3-expected.txt
new file mode 100644 (file)
index 0000000..34b61e3
--- /dev/null
@@ -0,0 +1,11 @@
+Tests what happens when you make prototype chain accesses with impure GetOwnPropertySlot traps in the way.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS typeof f() is "object" on all iterations including after DFG tier-up.
+PASS document.body.removeChild(img); typeof f() is "function"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-3.html b/LayoutTests/js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-3.html
new file mode 100644 (file)
index 0000000..0d0259f
--- /dev/null
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src="../../resources/js-test-pre.js"></script>
+<script>
+
+description("Tests what happens when you make prototype chain accesses with impure GetOwnPropertySlot traps in the way.");
+
+var img = new Image();
+img.name = "getElementsByTagName";
+document.body.appendChild(img);
+
+function f() {
+    return document.getElementsByTagName;
+}
+
+dfgShouldBe(f, "typeof f()", "\"object\"");
+shouldBe("document.body.removeChild(img); typeof f()", "\"function\"")
+
+</script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-4-expected.txt b/LayoutTests/js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-4-expected.txt
new file mode 100644 (file)
index 0000000..a5e4dc7
--- /dev/null
@@ -0,0 +1,11 @@
+Tests what happens when you make prototype chain accesses with impure GetOwnPropertySlot traps in the way.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS typeof f() is "function" on all iterations including after DFG tier-up.
+PASS typeof f() is "object"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-4.html b/LayoutTests/js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-4.html
new file mode 100644 (file)
index 0000000..4d1b89d
--- /dev/null
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src="../../resources/js-test-pre.js"></script>
+<script>
+
+description("Tests what happens when you make prototype chain accesses with impure GetOwnPropertySlot traps in the way.");
+
+var obj = {};
+obj.__proto__ = document;
+document.foo = function () {};
+
+function f() {
+    return obj.foo;
+}
+
+dfgShouldBe(f, "typeof f()", "\"function\"");
+
+var img = new Image();
+img.name = "foo";
+document.body.appendChild(img);
+
+shouldBe("typeof f()", "\"object\"");
+
+</script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-5-expected.txt b/LayoutTests/js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-5-expected.txt
new file mode 100644 (file)
index 0000000..a5e4dc7
--- /dev/null
@@ -0,0 +1,11 @@
+Tests what happens when you make prototype chain accesses with impure GetOwnPropertySlot traps in the way.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS typeof f() is "function" on all iterations including after DFG tier-up.
+PASS typeof f() is "object"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-5.html b/LayoutTests/js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-5.html
new file mode 100644 (file)
index 0000000..6202a75
--- /dev/null
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src="../../resources/js-test-pre.js"></script>
+<script>
+
+description("Tests what happens when you make prototype chain accesses with impure GetOwnPropertySlot traps in the way.");
+
+document.foo = function () {};
+
+function f() {
+    return document.foo;
+}
+
+dfgShouldBe(f, "typeof f()", "\"function\"");
+
+var img = new Image();
+img.name = "foo";
+document.body.appendChild(img);
+
+shouldBe("typeof f()", "\"object\"");
+
+</script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
index 450392c..a5e4dc7 100644 (file)
@@ -3,405 +3,7 @@ Tests what happens when you make prototype chain accesses with impure GetOwnProp
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "function"
-PASS typeof f() is "object"
-PASS typeof f() is "object"
-PASS typeof f() is "object"
-PASS typeof f() is "object"
-PASS typeof f() is "object"
-PASS typeof f() is "object"
-PASS typeof f() is "object"
-PASS typeof f() is "object"
-PASS typeof f() is "object"
-PASS typeof f() is "object"
-PASS typeof f() is "object"
-PASS typeof f() is "object"
-PASS typeof f() is "object"
-PASS typeof f() is "object"
-PASS typeof f() is "object"
-PASS typeof f() is "object"
-PASS typeof f() is "object"
-PASS typeof f() is "object"
-PASS typeof f() is "object"
-PASS typeof f() is "object"
-PASS typeof f() is "object"
-PASS typeof f() is "object"
-PASS typeof f() is "object"
-PASS typeof f() is "object"
-PASS typeof f() is "object"
-PASS typeof f() is "object"
-PASS typeof f() is "object"
-PASS typeof f() is "object"
-PASS typeof f() is "object"
-PASS typeof f() is "object"
-PASS typeof f() is "object"
-PASS typeof f() is "object"
-PASS typeof f() is "object"
-PASS typeof f() is "object"
-PASS typeof f() is "object"
-PASS typeof f() is "object"
-PASS typeof f() is "object"
-PASS typeof f() is "object"
-PASS typeof f() is "object"
-PASS typeof f() is "object"
-PASS typeof f() is "object"
-PASS typeof f() is "object"
-PASS typeof f() is "object"
-PASS typeof f() is "object"
-PASS typeof f() is "object"
-PASS typeof f() is "object"
-PASS typeof f() is "object"
-PASS typeof f() is "object"
-PASS typeof f() is "object"
+PASS typeof f() is "function" on all iterations including after DFG tier-up.
 PASS typeof f() is "object"
 PASS successfullyParsed is true
 
index 9582389..4627cbc 100644 (file)
@@ -1,10 +1,25 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<!DOCTYPE html>
 <html>
-<head>
-<script src="../../resources/js-test-pre.js"></script>
-</head>
 <body>
-<script src="script-tests/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps.js"></script>
+<script src="../../resources/js-test-pre.js"></script>
+<script>
+description("Tests what happens when you make prototype chain accesses with impure GetOwnPropertySlot traps in the way.");
+
+var doc = document;
+
+function f() {
+    return doc.getElementsByTagName;
+}
+
+dfgShouldBe(f, "typeof f()", "\"function\"");
+
+var img = new Image();
+img.name = "getElementsByTagName";
+document.body.appendChild(img);
+
+shouldBe("typeof f()", "\"object\"");
+
+</script>
 <script src="../../resources/js-test-post.js"></script>
 </body>
 </html>
diff --git a/LayoutTests/js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-2-expected.txt b/LayoutTests/js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-2-expected.txt
new file mode 100644 (file)
index 0000000..5e521d3
--- /dev/null
@@ -0,0 +1,49 @@
+Tests what happens when you make prototype chain accesses with impure GetOwnPropertySlot traps in the way.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "object"
+PASS typeof f() is "object"
+PASS typeof f() is "object"
+PASS typeof f() is "object"
+PASS typeof f() is "object"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-2.html b/LayoutTests/js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-2.html
new file mode 100644 (file)
index 0000000..5dd518d
--- /dev/null
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src="../../resources/js-test-pre.js"></script>
+<script>
+
+description("Tests what happens when you make prototype chain accesses with impure GetOwnPropertySlot traps in the way.");
+
+var obj = {};
+obj.__proto__ = document;
+
+function f() {
+    return obj.getElementsByTagName;
+}
+
+var expected = "\"function\"";
+for (var i = 0; i < 40; ++i) {
+    if (i == 35) {
+        var img = new Image();
+        img.name = "getElementsByTagName";
+        document.body.appendChild(img);
+        expected = "\"object\"";
+    }
+    shouldBe("typeof f()", expected);
+}
+
+</script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-3-expected.txt b/LayoutTests/js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-3-expected.txt
new file mode 100644 (file)
index 0000000..d0fa17e
--- /dev/null
@@ -0,0 +1,49 @@
+Tests what happens when you make prototype chain accesses with impure GetOwnPropertySlot traps in the way.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS typeof f() is "object"
+PASS typeof f() is "object"
+PASS typeof f() is "object"
+PASS typeof f() is "object"
+PASS typeof f() is "object"
+PASS typeof f() is "object"
+PASS typeof f() is "object"
+PASS typeof f() is "object"
+PASS typeof f() is "object"
+PASS typeof f() is "object"
+PASS typeof f() is "object"
+PASS typeof f() is "object"
+PASS typeof f() is "object"
+PASS typeof f() is "object"
+PASS typeof f() is "object"
+PASS typeof f() is "object"
+PASS typeof f() is "object"
+PASS typeof f() is "object"
+PASS typeof f() is "object"
+PASS typeof f() is "object"
+PASS typeof f() is "object"
+PASS typeof f() is "object"
+PASS typeof f() is "object"
+PASS typeof f() is "object"
+PASS typeof f() is "object"
+PASS typeof f() is "object"
+PASS typeof f() is "object"
+PASS typeof f() is "object"
+PASS typeof f() is "object"
+PASS typeof f() is "object"
+PASS typeof f() is "object"
+PASS typeof f() is "object"
+PASS typeof f() is "object"
+PASS typeof f() is "object"
+PASS typeof f() is "object"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-3.html b/LayoutTests/js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-3.html
new file mode 100644 (file)
index 0000000..bdc39fa
--- /dev/null
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src="../../resources/js-test-pre.js"></script>
+<script>
+
+description("Tests what happens when you make prototype chain accesses with impure GetOwnPropertySlot traps in the way.");
+
+var img = new Image();
+img.name = "getElementsByTagName";
+document.body.appendChild(img);
+
+function f() {
+    return document.getElementsByTagName;
+}
+
+var expected = "\"object\"";
+for (var i = 0; i < 40; ++i) {
+    if (i == 35) {
+        document.body.removeChild(img);
+        expected = "\"function\"";
+    }
+    shouldBe("typeof f()", expected);
+}
+
+</script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-4-expected.txt b/LayoutTests/js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-4-expected.txt
new file mode 100644 (file)
index 0000000..5e521d3
--- /dev/null
@@ -0,0 +1,49 @@
+Tests what happens when you make prototype chain accesses with impure GetOwnPropertySlot traps in the way.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "object"
+PASS typeof f() is "object"
+PASS typeof f() is "object"
+PASS typeof f() is "object"
+PASS typeof f() is "object"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-4.html b/LayoutTests/js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-4.html
new file mode 100644 (file)
index 0000000..a783f51
--- /dev/null
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src="../../resources/js-test-pre.js"></script>
+<script>
+
+description("Tests what happens when you make prototype chain accesses with impure GetOwnPropertySlot traps in the way.");
+
+var obj = {};
+obj.__proto__ = document;
+document.foo = function () {};
+
+function f() {
+    return obj.foo;
+}
+
+var expected = "\"function\"";
+for (var i = 0; i < 40; ++i) {
+    if (i == 35) {
+        var img = new Image();
+        img.name = "foo";
+        document.body.appendChild(img);
+        expected = "\"object\"";
+    }
+    shouldBe("typeof f()", expected);
+}
+
+</script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-5-expected.txt b/LayoutTests/js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-5-expected.txt
new file mode 100644 (file)
index 0000000..cf58759
--- /dev/null
@@ -0,0 +1,59 @@
+Tests what happens when you make prototype chain accesses with impure GetOwnPropertySlot traps in the way.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "function"
+PASS typeof f() is "object"
+PASS typeof f() is "object"
+PASS typeof f() is "object"
+PASS typeof f() is "object"
+PASS typeof f() is "object"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-5.html b/LayoutTests/js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-5.html
new file mode 100644 (file)
index 0000000..bc52d2f
--- /dev/null
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src="../../resources/js-test-pre.js"></script>
+<script>
+
+description("Tests what happens when you make prototype chain accesses with impure GetOwnPropertySlot traps in the way.");
+
+document.foo = function () {};
+
+function f() {
+    return document.foo;
+}
+
+var expected = "\"function\"";
+for (var i = 0; i < 50; ++i) {
+    if (i == 45) {
+        var img = new Image();
+        img.name = "foo";
+        document.body.appendChild(img);
+        expected = "\"object\"";
+    }
+    v = f();
+    shouldBe("typeof f()", expected);
+}
+
+</script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/dom/script-tests/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps.js b/LayoutTests/js/dom/script-tests/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps.js
deleted file mode 100644 (file)
index 1c0793e..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-description(
-"Tests what happens when you make prototype chain accesses with impure GetOwnPropertySlot traps in the way."
-);
-
-var doc = document;
-
-function f() {
-    return doc.getElementsByTagName;
-}
-
-var expected = "\"function\"";
-for (var i = 0; i < 400; ++i) {
-    if (i == 350) {
-        var img = new Image();
-        img.name = "getElementsByTagName";
-        document.body.appendChild(img);
-        expected = "\"object\"";
-    }
-    shouldBe("typeof f()", expected);
-}
-
diff --git a/PerformanceTests/Bindings/update-name-getter.html b/PerformanceTests/Bindings/update-name-getter.html
new file mode 100644 (file)
index 0000000..47d7f8f
--- /dev/null
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<body>
+<img id="foo" name="bar">
+<script src="../resources/runner.js"></script>
+<script>
+
+var imageElement = document.querySelector("img");
+
+imageElement.id = "foo";
+
+PerfTestRunner.measureRunsPerSecond({
+    description: "This benchmark covers 'getElementById' in Dromaeo/dom-query.html, and other DOM methods that return a Node object.",
+    run: function() {
+        for (var i = 0; i < 100000; i++)
+            imageElement.id =  i % 2 ? "foo1" : "foo0";
+}});
+</script>
+</body>
+</html>
index 06780de..aabb63e 100644 (file)
@@ -1,3 +1,15 @@
+2013-12-15  Ryosuke Niwa  <rniwa@webkit.org>
+
+        REGRESSION: 2x regression on Dromaeo DOM query tests
+        https://bugs.webkit.org/show_bug.cgi?id=125377
+
+        Reviewed by Filip Pizlo.
+
+        Added a micro-benchmark for updating a named property on document.
+
+        * Bindings/update-name-getter.html: Added.
+        * Skipped:
+
 2013-12-03  Manuel Rego Casasnovas  <rego@igalia.com>
 
         [CSS Regions] Fix Layout/RegionsSelection.html in Mac platform
index a921882..398aad2 100644 (file)
@@ -3,6 +3,7 @@ DOM/TraverseChildNodes.html
 Interactive/SelectAll.html
 Interactive/CopyAll.html
 Interactive/DeletingInPasswordField.html
+Bindings/update-name-getter.html
 
 # Not enabled by default on some ports
 Mutation
index 157d86a..1dee210 100644 (file)
@@ -1,3 +1,48 @@
+2013-12-15  Ryosuke Niwa  <rniwa@webkit.org>
+
+        REGRESSION: 2x regression on Dromaeo DOM query tests
+        https://bugs.webkit.org/show_bug.cgi?id=125377
+
+        Reviewed by Filip Pizlo.
+
+        The bug was caused by JSC not JIT'ing property access on "document" due to its type info having
+        HasImpureGetOwnPropertySlot flag.
+
+        Fixed the bug by new type info flag NewImpurePropertyFiresWatchpoints, which allows the baseline
+        JIT to generate byte code for access properties on an object with named properties (a.k.a.
+        custom name getter) in DOM. When a new named property appears on the object, VM is notified via
+        VM::addImpureProperty and fires StructureStubClearingWatchpoint added during the repatch.
+
+        * bytecode/GetByIdStatus.cpp:
+        (JSC::GetByIdStatus::computeFromLLInt): Take the slow path if we have any object with impure
+        properties in the prototype chain.
+        (JSC::GetByIdStatus::computeForChain): Ditto.
+
+        * jit/Repatch.cpp:
+        (JSC::repatchByIdSelfAccess): Throw away the byte code when a new impure property is added on any
+        object in the prototype chain via StructureStubClearingWatchpoint.
+        (JSC::generateProtoChainAccessStub): Ditto.
+        (JSC::tryCacheGetByID):
+        (JSC::tryBuildGetByIDList):
+        (JSC::tryRepatchIn): Ditto.
+
+        * runtime/JSTypeInfo.h: Added NewImpurePropertyFiresWatchpoints.
+        (JSC::TypeInfo::newImpurePropertyFiresWatchpoints): Added.
+
+        * runtime/Operations.h:
+        (JSC::normalizePrototypeChainForChainAccess): Don't exit early if VM will be notified of new
+        impure property even if the object had impure properties.
+
+        * runtime/Structure.h:
+        (JSC::Structure::takesSlowPathInDFGForImpureProperty): Added. Wraps hasImpureGetOwnPropertySlot and
+        asserts that newImpurePropertyFiresWatchpoints is true whenever hasImpureGetOwnPropertySlot is true.
+
+        * runtime/VM.cpp:
+        (JSC::VM::registerWatchpointForImpureProperty): Added.
+        (JSC::VM::addImpureProperty): Added. HTMLDocument calls it to notify JSC of a new impure property.
+
+        * runtime/VM.h:
+
 2013-12-15  Andy Estes  <aestes@apple.com>
 
         [iOS] Upstream changes to FeatureDefines.xcconfig
index bc415c4..ada7dda 100644 (file)
@@ -48,7 +48,10 @@ GetByIdStatus GetByIdStatus::computeFromLLInt(CodeBlock* profiledBlock, unsigned
     Structure* structure = instruction[4].u.structure.get();
     if (!structure)
         return GetByIdStatus(NoInformation, false);
-    
+
+    if (structure->takesSlowPathInDFGForImpureProperty())
+        return GetByIdStatus(NoInformation, false);
+
     unsigned attributesIgnored;
     JSCell* specificValue;
     PropertyOffset offset = structure->getConcurrently(
@@ -79,7 +82,15 @@ void GetByIdStatus::computeForChain(GetByIdStatus& result, CodeBlock* profiledBl
     // then we fall back on a polymorphic access.
     if (!result.m_chain->isStillValid())
         return;
-    
+
+    if (result.m_chain->head()->takesSlowPathInDFGForImpureProperty())
+        return;
+    size_t chainSize = result.m_chain->size();
+    for (size_t i = 0; i < chainSize; i++) {
+        if (result.m_chain->at(i)->takesSlowPathInDFGForImpureProperty())
+            return;
+    }
+
     JSObject* currentObject = result.m_chain->terminalPrototype();
     Structure* currentStructure = result.m_chain->last();
     
@@ -154,6 +165,8 @@ GetByIdStatus GetByIdStatus::computeFor(CodeBlock* profiledBlock, StubInfoMap& m
         
     case access_get_by_id_self: {
         Structure* structure = stubInfo->u.getByIdSelf.baseObjectStructure.get();
+        if (structure->takesSlowPathInDFGForImpureProperty())
+            return GetByIdStatus(TakesSlowPath, true);
         unsigned attributesIgnored;
         JSCell* specificValue;
         result.m_offset = structure->getConcurrently(
@@ -176,6 +189,9 @@ GetByIdStatus GetByIdStatus::computeFor(CodeBlock* profiledBlock, StubInfoMap& m
             ASSERT(list->list[i].isDirect);
             
             Structure* structure = list->list[i].base.get();
+            if (structure->takesSlowPathInDFGForImpureProperty())
+                return GetByIdStatus(TakesSlowPath, true);
+
             if (result.m_structureSet.contains(structure))
                 continue;
             
@@ -267,7 +283,7 @@ GetByIdStatus GetByIdStatus::computeFor(VM& vm, Structure* structure, StringImpl
     
     if (!structure->propertyAccessesAreCacheable())
         return GetByIdStatus(TakesSlowPath);
-    
+
     GetByIdStatus result;
     result.m_wasSeenInJIT = false; // To my knowledge nobody that uses computeFor(VM&, Structure*, StringImpl*) reads this field, but I might as well be honest: no, it wasn't seen in the JIT, since I computed it statically.
     unsigned attributes;
index af24e6e..d86f12c 100644 (file)
@@ -38,6 +38,7 @@
 #include "RepatchBuffer.h"
 #include "ScratchRegisterAllocator.h"
 #include "StructureRareDataInlines.h"
+#include "StructureStubClearingWatchpoint.h"
 #include "ThunkGenerators.h"
 #include <wtf/StringPrintStream.h>
 
@@ -93,8 +94,12 @@ static void repatchCall(CodeBlock* codeblock, CodeLocationCall call, FunctionPtr
     repatchCall(repatchBuffer, call, newCalleeFunction);
 }
 
-static void repatchByIdSelfAccess(CodeBlock* codeBlock, StructureStubInfo& stubInfo, Structure* structure, PropertyOffset offset, const FunctionPtr &slowPathFunction, bool compact)
+static void repatchByIdSelfAccess(VM& vm, CodeBlock* codeBlock, StructureStubInfo& stubInfo, Structure* structure, const Identifier& propertyName, PropertyOffset offset,
+    const FunctionPtr &slowPathFunction, bool compact)
 {
+    if (structure->typeInfo().newImpurePropertyFiresWatchpoints())
+        vm.registerWatchpointForImpureProperty(propertyName, stubInfo.addWatchpoint(codeBlock));
+
     RepatchBuffer repatchBuffer(codeBlock);
 
     // Only optimize once!
@@ -215,7 +220,7 @@ static void linkRestoreScratch(LinkBuffer& patchBuffer, bool needToRestoreScratc
     linkRestoreScratch(patchBuffer, needToRestoreScratch, success, fail, failureCases, stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.deltaCallToDone), stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.deltaCallToSlowCase));
 }
 
-static void generateProtoChainAccessStub(ExecState* exec, StructureStubInfo& stubInfo, StructureChain* chain, size_t count, PropertyOffset offset, Structure* structure, CodeLocationLabel successLabel, CodeLocationLabel slowCaseLabel, RefPtr<JITStubRoutine>& stubRoutine)
+static void generateProtoChainAccessStub(ExecState* exec, StructureStubInfo& stubInfo, StructureChain* chain, size_t count, PropertyOffset offset, Structure* structure, CodeLocationLabel successLabel, CodeLocationLabel slowCaseLabel, RefPtr<JITStubRoutine>& stubRoutine, const Identifier& propertyName)
 {
     VM* vm = &exec->vm();
 
@@ -242,14 +247,21 @@ static void generateProtoChainAccessStub(ExecState* exec, StructureStubInfo& stu
     MacroAssembler::JumpList failureCases;
     
     failureCases.append(stubJit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR, JSCell::structureOffset()), MacroAssembler::TrustedImmPtr(structure)));
-    
+
+    CodeBlock* codeBlock = exec->codeBlock();
+    if (structure->typeInfo().newImpurePropertyFiresWatchpoints())
+        vm->registerWatchpointForImpureProperty(propertyName, stubInfo.addWatchpoint(codeBlock));
+
     Structure* currStructure = structure;
     WriteBarrier<Structure>* it = chain->head();
     JSObject* protoObject = 0;
     for (unsigned i = 0; i < count; ++i, ++it) {
         protoObject = asObject(currStructure->prototypeForLookup(exec));
+        Structure* protoStructure = protoObject->structure();
+        if (protoStructure->typeInfo().newImpurePropertyFiresWatchpoints())
+            vm->registerWatchpointForImpureProperty(propertyName, stubInfo.addWatchpoint(codeBlock));
         addStructureTransitionCheck(
-            protoObject, protoObject->structure(), exec->codeBlock(), stubInfo, stubJit,
+            protoObject, protoStructure, codeBlock, stubInfo, stubJit,
             failureCases, scratchGPR);
         currStructure = it->get();
     }
@@ -374,7 +386,7 @@ static bool tryCacheGetByID(ExecState* exec, JSValue baseValue, const Identifier
             return true;
         }
 
-        repatchByIdSelfAccess(codeBlock, stubInfo, structure, slot.cachedOffset(), operationGetByIdBuildList, true);
+        repatchByIdSelfAccess(*vm, codeBlock, stubInfo, structure, propertyName, slot.cachedOffset(), operationGetByIdBuildList, true);
         stubInfo.initGetByIdSelf(*vm, codeBlock->ownerExecutable(), structure);
         return true;
     }
@@ -393,7 +405,7 @@ static bool tryCacheGetByID(ExecState* exec, JSValue baseValue, const Identifier
 
     StructureChain* prototypeChain = structure->prototypeChain(exec);
     
-    generateProtoChainAccessStub(exec, stubInfo, prototypeChain, count, offset, structure, stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.deltaCallToDone), stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.deltaCallToSlowCase), stubInfo.stubRoutine);
+    generateProtoChainAccessStub(exec, stubInfo, prototypeChain, count, offset, structure, stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.deltaCallToDone), stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.deltaCallToSlowCase), stubInfo.stubRoutine, propertyName);
     
     RepatchBuffer repatchBuffer(codeBlock);
     replaceWithJump(repatchBuffer, stubInfo, stubInfo.stubRoutine->code().code());
@@ -638,7 +650,7 @@ static bool tryBuildGetByIDList(ExecState* exec, JSValue baseValue, const Identi
     
     RefPtr<JITStubRoutine> stubRoutine;
     
-    generateProtoChainAccessStub(exec, stubInfo, prototypeChain, count, offset, structure, stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.deltaCallToDone), slowCase, stubRoutine);
+    generateProtoChainAccessStub(exec, stubInfo, prototypeChain, count, offset, structure, stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.deltaCallToDone), slowCase, stubRoutine, ident);
     
     polymorphicStructureList->list[listIndex].set(*vm, codeBlock->ownerExecutable(), stubRoutine, structure, true);
     
@@ -1045,7 +1057,7 @@ static bool tryCachePutByID(ExecState* exec, JSValue baseValue, const Identifier
         if (!MacroAssembler::isPtrAlignedAddressOffset(offsetRelativeToPatchedStorage(slot.cachedOffset())))
             return false;
 
-        repatchByIdSelfAccess(codeBlock, stubInfo, structure, slot.cachedOffset(), appropriateListBuildingPutByIdFunction(slot, putKind), false);
+        repatchByIdSelfAccess(*vm, codeBlock, stubInfo, structure, ident, slot.cachedOffset(), appropriateListBuildingPutByIdFunction(slot, putKind), false);
         stubInfo.initPutByIdReplace(*vm, codeBlock->ownerExecutable(), structure);
         return true;
     }
@@ -1223,14 +1235,21 @@ static bool tryRepatchIn(
             MacroAssembler::NotEqual,
             MacroAssembler::Address(baseGPR, JSCell::structureOffset()),
             MacroAssembler::TrustedImmPtr(structure)));
-        
+
+        CodeBlock* codeBlock = exec->codeBlock();
+        if (structure->typeInfo().newImpurePropertyFiresWatchpoints())
+            vm->registerWatchpointForImpureProperty(ident, stubInfo.addWatchpoint(codeBlock));
+
         Structure* currStructure = structure;
         WriteBarrier<Structure>* it = chain->head();
         for (unsigned i = 0; i < count; ++i, ++it) {
             JSObject* prototype = asObject(currStructure->prototypeForLookup(exec));
+            Structure* protoStructure = prototype->structure();
             addStructureTransitionCheck(
-                prototype, prototype->structure(), exec->codeBlock(), stubInfo, stubJit,
+                prototype, protoStructure, exec->codeBlock(), stubInfo, stubJit,
                 failureCases, scratchGPR);
+            if (protoStructure->typeInfo().newImpurePropertyFiresWatchpoints())
+                vm->registerWatchpointForImpureProperty(ident, stubInfo.addWatchpoint(codeBlock));
             currStructure = it->get();
         }
         
index 109a032..d70d651 100644 (file)
@@ -47,7 +47,8 @@ namespace JSC {
     static const unsigned OverridesGetPropertyNames = 1 << 8;
     static const unsigned ProhibitsPropertyCaching = 1 << 9;
     static const unsigned HasImpureGetOwnPropertySlot = 1 << 10;
-    static const unsigned StructureHasRareData = 1 << 11;
+    static const unsigned NewImpurePropertyFiresWatchpoints = 1 << 11;
+    static const unsigned StructureHasRareData = 1 << 12;
 
     class TypeInfo {
     public:
@@ -83,6 +84,7 @@ namespace JSC {
         bool overridesGetPropertyNames() const { return isSetOnFlags2(OverridesGetPropertyNames); }
         bool prohibitsPropertyCaching() const { return isSetOnFlags2(ProhibitsPropertyCaching); }
         bool hasImpureGetOwnPropertySlot() const { return isSetOnFlags2(HasImpureGetOwnPropertySlot); }
+        bool newImpurePropertyFiresWatchpoints() const { return isSetOnFlags2(NewImpurePropertyFiresWatchpoints); }
         bool structureHasRareData() const { return isSetOnFlags2(StructureHasRareData); }
 
         static ptrdiff_t flagsOffset()
index 1d5470b..cbc7dd1 100644 (file)
@@ -217,8 +217,9 @@ inline size_t normalizePrototypeChainForChainAccess(CallFrame* callFrame, JSValu
     while (!slotBase || slotBase != cell) {
         if (cell->isProxy())
             return InvalidPrototypeChain;
-            
-        if (cell->structure()->typeInfo().hasImpureGetOwnPropertySlot())
+
+        const TypeInfo& typeInfo = cell->structure()->typeInfo();
+        if (typeInfo.hasImpureGetOwnPropertySlot() && !typeInfo.newImpurePropertyFiresWatchpoints())
             return InvalidPrototypeChain;
             
         JSValue v = cell->structure()->prototypeForLookup(callFrame);
index ac4a77a..c73e8cb 100644 (file)
@@ -134,6 +134,14 @@ public:
 
     bool propertyAccessesAreCacheable() { return m_dictionaryKind != UncachedDictionaryKind && !typeInfo().prohibitsPropertyCaching(); }
 
+    // We use SlowPath in GetByIdStatus for structures that may get new impure properties later to prevent
+    // DFG from inlining property accesses since structures don't transition when a new impure property appears.
+    bool takesSlowPathInDFGForImpureProperty()
+    {
+        ASSERT(!typeInfo().hasImpureGetOwnPropertySlot() || typeInfo().newImpurePropertyFiresWatchpoints());
+        return typeInfo().hasImpureGetOwnPropertySlot();
+    }
+
     // Type accessors.
     const TypeInfo& typeInfo() const { ASSERT(structure()->classInfo() == info()); return m_typeInfo; }
     bool isObject() const { return typeInfo().isObject(); }
index 68fe799..19689a6 100644 (file)
@@ -765,4 +765,18 @@ void VM::dumpRegExpTrace()
 }
 #endif
 
+void VM::registerWatchpointForImpureProperty(const Identifier& propertyName, Watchpoint* watchpoint)
+{
+    auto result = m_impurePropertyWatchpointSets.add(propertyName.string(), nullptr);
+    if (result.isNewEntry)
+        result.iterator->value = adoptRef(new WatchpointSet(IsWatched));
+    result.iterator->value->add(watchpoint);
+}
+
+void VM::addImpureProperty(const String& propertyName)
+{
+    if (RefPtr<WatchpointSet> watchpointSet = m_impurePropertyWatchpointSets.take(propertyName))
+        watchpointSet->fireAll();
+}
+
 } // namespace JSC
index 3f7a10f..85e1b77 100644 (file)
 #include "ThunkGenerators.h"
 #include "TypedArrayController.h"
 #include "Watchdog.h"
+#include "Watchpoint.h"
 #include "WeakRandom.h"
 #include <wtf/BumpPointerAllocator.h>
 #include <wtf/DateMath.h>
 #include <wtf/Forward.h>
 #include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
 #include <wtf/RefCountedArray.h>
 #include <wtf/SimpleStats.h>
 #include <wtf/StackBounds.h>
 #include <wtf/ThreadSafeRefCounted.h>
 #include <wtf/ThreadSpecific.h>
 #include <wtf/WTFThreadData.h>
+#include <wtf/text/WTFString.h>
 #if ENABLE(REGEXP_TRACING)
 #include <wtf/ListHashSet.h>
 #endif
@@ -69,6 +72,7 @@ namespace JSC {
     class CommonIdentifiers;
     class ExecState;
     class HandleStack;
+    class Identifier;
     class IdentifierTable;
     class Interpreter;
     class JSGlobalObject;
@@ -92,6 +96,8 @@ namespace JSC {
     class UnlinkedFunctionExecutable;
     class UnlinkedProgramCodeBlock;
     class VMEntryScope;
+    class Watchpoint;
+    class WatchpointSet;
 
 #if ENABLE(DFG_JIT)
     namespace DFG {
@@ -474,6 +480,10 @@ namespace JSC {
         
         JS_EXPORT_PRIVATE void discardAllCode();
 
+        void registerWatchpointForImpureProperty(const Identifier&, Watchpoint*);
+        // FIXME: Use AtomicString once it got merged with Identifier.
+        JS_EXPORT_PRIVATE void addImpureProperty(const String&);
+
     private:
         friend class LLIntOffsetsExtractor;
         friend class ClearExceptionScope;
@@ -510,6 +520,8 @@ namespace JSC {
         bool m_inDefineOwnProperty;
         OwnPtr<CodeCache> m_codeCache;
         RefCountedArray<StackFrame> m_exceptionStack;
+
+        HashMap<String, RefPtr<WatchpointSet>> m_impurePropertyWatchpointSets;
     };
 
 #if ENABLE(GC_VALIDATION)
index e097af9..7d11d7c 100644 (file)
@@ -1,3 +1,34 @@
+2013-12-15  Ryosuke Niwa  <rniwa@webkit.org>
+
+        REGRESSION: 2x regression on Dromaeo DOM query tests
+        https://bugs.webkit.org/show_bug.cgi?id=125377
+
+        Reviewed by Filip Pizlo.
+
+        The bug was caused by JSC not JIT'ing property accesses on document because of its having
+        custom named getter (named properties).  This resulted in resolution of methods on document
+        such as getElementById to happen inside the interpreter.
+
+        Fixed the bug by using the new JSC type info flag which tells JSC to JIT property access on
+        document, and then notifying JSC whenever a new named property appeared on document.
+
+        Tests: js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-2.html
+               js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-3.html
+               js/dom/dfg-prototype-chain-caching-with-impure-get-own-property-slot-traps-4.html
+               js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-2.html
+               js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-3.html
+               js/dom/prototype-chain-caching-with-impure-get-own-property-slot-traps-4.html
+
+        * bindings/js/JSDOMBinding.cpp:
+        (WebCore::addImpureProperty): Wraps VM::addImpureProperty.
+        * bindings/js/JSDOMBinding.h:
+        * bindings/scripts/CodeGeneratorJS.pm:
+        (GenerateHeader): Added the support for NewImpurePropertyFiresWatchpoints.
+        * bindings/scripts/IDLAttributes.txt: Ditto.
+        * html/HTMLDocument.cpp:
+        (WebCore::HTMLDocument::addDocumentNamedItem): Calls addImpureProperty.
+        * html/HTMLDocument.idl: Added NewImpurePropertyFiresWatchpoints.
+
 2013-12-15  Brent Fulgham  <bfulgham@webkit.org>
 
         [WIn] Unreviewed build fix after r160599
index decc4d0..a32d332 100644 (file)
@@ -50,6 +50,11 @@ namespace WebCore {
 STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(DOMConstructorObject);
 STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(DOMConstructorWithDocument);
 
+void addImpureProperty(const AtomicString& propertyName)
+{
+    JSDOMWindow::commonVM()->addImpureProperty(propertyName);
+}
+
 const JSC::HashTable& getHashTableForGlobalData(VM& vm, const JSC::HashTable& staticTable)
 {
     return DOMObjectHashTableMap::mapFor(vm).get(staticTable);
index 1ea055e..097ce6b 100644 (file)
@@ -237,6 +237,8 @@ inline JSC::JSValue argumentOrNull(JSC::ExecState* exec, unsigned index)
     return index >= exec->argumentCount() ? JSC::JSValue() : exec->argument(index);
 }
 
+void addImpureProperty(const AtomicString&);
+
 const JSC::HashTable& getHashTableForGlobalData(JSC::VM&, const JSC::HashTable& staticTable);
 
 void reportException(JSC::ExecState*, JSC::JSValue exception, CachedScript* = 0);
index a68f7de..b479dc3 100644 (file)
@@ -694,6 +694,9 @@ sub GenerateHeader
     if ($hasImpureNamedGetter) {
         $structureFlags{"JSC::HasImpureGetOwnPropertySlot"} = 1;
     }
+    if ($interface->extendedAttributes->{"NewImpurePropertyFiresWatchpoints"}) {
+        $structureFlags{"JSC::NewImpurePropertyFiresWatchpoints"} = 1;
+    }
 
     # Getters
     if ($hasGetter) {
index 85fba7a..59171f3 100644 (file)
@@ -84,6 +84,7 @@ JSNoStaticTables
 JSWindowEventListener
 MasqueradesAsUndefined
 NamedConstructor=*
+NewImpurePropertyFiresWatchpoints
 NoInterfaceObject
 NotEnumerable
 NotDeletable
index 17e206e..135d7d0 100644 (file)
@@ -71,6 +71,7 @@
 #include "HTMLFrameSetElement.h"
 #include "HTMLNames.h"
 #include "InspectorInstrumentation.h"
+#include "JSDOMBinding.h"
 #include "Page.h"
 #include "ScriptController.h"
 #include "Settings.h"
@@ -328,6 +329,7 @@ static HashSet<AtomicStringImpl*>* createHtmlCaseInsensitiveAttributesSet()
 void HTMLDocument::addDocumentNamedItem(const AtomicStringImpl& name, Element& item)
 {
     m_documentNamedItem.add(name, item, *this);
+    addImpureProperty(AtomicString(const_cast<AtomicStringImpl*>(&name)));
 }
 
 void HTMLDocument::removeDocumentNamedItem(const AtomicStringImpl& name, Element& item)
index a09f006..5e889ec 100644 (file)
@@ -20,6 +20,7 @@
 
 [
     CustomNamedGetter,
+    NewImpurePropertyFiresWatchpoints,
 ] interface HTMLDocument : Document {
     [Custom] void open();
     void close();