haikuwebkit/LayoutTests/fast/dom/htmlcollection-getownproper...

48 lines
1.8 KiB
HTML
Raw Permalink Normal View History

Accessing HTMLCollection.length is slow https://bugs.webkit.org/show_bug.cgi?id=148039 Reviewed by Ryosuke Niwa. Source/WebCore: Accessing was HTMLCollection.length is slow, much slower than accessing NodeList.length. The reason is that HTMLCollection's bindings code is slightly different. In particular, HTMLCollection's GetOwnPropertySlot() has an extra check to see if the PropertyName is available on the prototype before doing: 1. Check static properties (getStaticValueSlotEntryWithoutCaching()) 2. Indexed getter 3. Named getter 4. Check own properties (getStaticValueSlot()) This means that everytime the JavaScript was accessing HTMLCollection.length or HTMLCollection[index], we would check if length / index was present on the prototype before calling HTMLCollection::length() / HTMLCollection::item(i). The prototype check is fairly expensive and was making traversing an HTMLCollection much slower than traversing a NodeList. In this patch, I refactored GetOwnPropertySlot() to do: 1. Indexed getter 2. Check static properties 3. Prototype check 4. Named getter 5. Check own properties This way, the prototype check is no longer slowing down HTMLCollection traversal. What matters is that we do the prototype check *before* calling the named getter as we don't want named properties to mask properties on the prototype. Note that this patch takes the minimal approach to get the performance win while limiting the risk of breakage. Indeed, the current behavior still does not match the WebIDL specification, which seems to indicate the order should be: 1. Indexed getter 2. Check static / own properties 3. Prototype check 4. Named getter Once we match the specification, I believe we will be able to drop the JSC::HasImpureGetOwnPropertySlot flag on HTMLCollection, which currently makes HTMLCollection.length not cacheable. Right now, I believe we still need this flag because named properties can still mask own properties. Performance: /Bindings/childNodes-traversal: 5597.54 +/- 0.7% -> 5572.10 +/- 0.4% /Bindings/children-traversal: 3852.61 +/- 0.3% -> 4731.03 +/- 0.3% (~23% better) Test: fast/dom/htmlcollection-getownproperty.html * bindings/scripts/CodeGeneratorJS.pm: (GenerateGetOwnPropertySlotBody): * bindings/scripts/test/JS/JSTestEventTarget.cpp: (WebCore::JSTestEventTarget::getOwnPropertySlot): LayoutTests: * fast/dom/htmlcollection-getownproperty-expected.txt: Added. * fast/dom/htmlcollection-getownproperty.html: Added. Add new layout test covering the expected behavior of HTMLCollection's [[GetOwnProperty]]. A few checks are still failing as we don't entirely match the specification yet. * fast/dom/wrapper-classes-expected.txt: Rebaseline test as a few more checks are now passing. Canonical link: https://commits.webkit.org/166187@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188523 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-08-17 16:46:41 +00:00
<!DOCTYPE html>
<html>
<body>
<script src="../../resources/js-test-pre.js"></script>
<div id="testDiv">
<p name="toString" id="toStringP"></p>
<p name="length" id="lengthP"></p>
<p name="foo" id="fooP"></p>
<p name="0" id="0P"></p>
</div>
<script>
description("Tests that the behavior of HTMLCollection's [[GetOwnProperty]] conforms to Web IDL");
var testDiv = document.getElementById("testDiv");
var htmlCollection = testDiv.children;
debug("* Named properties should not mask properties on the prototype");
shouldBe("htmlCollection.namedItem('toString')", "document.getElementById('toStringP')");
shouldBe("htmlCollection.toString", "HTMLCollection.prototype.toString");
debug("");
debug("* Named properties should not mask static properties on HTMLCollection");
shouldBe("htmlCollection.namedItem('length')", "document.getElementById('lengthP')");
shouldBe("htmlCollection.length", "4");
debug("");
debug("* Named properties should not mask own properties on HTMLCollection");
evalAndLog("htmlCollection.foo = 'foo'");
shouldBe("htmlCollection.namedItem('foo')", "document.getElementById('fooP')")
shouldBeEqualToString("htmlCollection.foo", "foo");
debug("");
debug("* Named properties should not mask indexed properties");
shouldBe("htmlCollection.item(0)", "testDiv.firstElementChild");
shouldBe("htmlCollection[0]", "testDiv.firstElementChild");
shouldBe("htmlCollection.namedItem('0')", "document.getElementById('0P')");
shouldBe("htmlCollection['0']", "testDiv.firstElementChild");
debug("");
debug("* Own properties on HTMLCollection should mask properties on prototype");
evalAndLog("htmlCollection.toString = 'InstanceToString'");
shouldBeEqualToString("htmlCollection.toString", "InstanceToString");
</script>
<script src="../../resources/js-test-post.js"></script>
</body>
</html>