Bug 1491890 [wpt PR 13032] - Improve the wasm idlharness test., a=testonly
☠☠ backed out by 09dd66ffc95a ☠ ☠
authormoz-wptsync-bot <wptsync@mozilla.com>
Tue, 16 Oct 2018 09:47:10 +0000
changeset 489908 a06a3fa7275ac35e4eb18e4ce79ecbc09cdadfb7
parent 489907 b4a3f1a30972168886183642c3dc795c7a9246bb
child 489909 357648610f8d6e5488843b836756db914b74cfd5
push id247
push userfmarier@mozilla.com
push dateSat, 27 Oct 2018 01:06:44 +0000
reviewerstestonly
bugs1491890, 13032
milestone64.0a1
Bug 1491890 [wpt PR 13032] - Improve the wasm idlharness test., a=testonly Automatic update from web-platform-testsIdlHarness: Extract code that checks for interface objects on self. -- IdlHarness: Support LegacyNamespace in interface object checks. -- IdlHarness: Support LegacyNamespace in class string checks. -- Fix some bugs in wasm/idlharness.any.js. -- Move wasm/idlharness.any.js to the jsapi subdirectory. It only tests the IDL from the jsapi specification. -- wpt-commits: df681aeacb197d9690fff1160e8d6362fd872000, 10c3854cbb09b63f0af8a6624dd7e87edba031ff, e77d06135f5dc72398d0a562ce53da90ad6a0968, ebefd2d309525024a8a57f435aef5ee683846013, a69af5481cdd976c9696f97d9c6547ac87ba83d0 wpt-pr: 13032
testing/web-platform/tests/resources/idlharness.js
testing/web-platform/tests/resources/test/tests/unit/IdlInterface/get_interface_object.html
testing/web-platform/tests/resources/test/tests/unit/IdlInterface/get_interface_object_owner.html
testing/web-platform/tests/resources/test/tests/unit/IdlInterface/get_legacy_namespace.html
testing/web-platform/tests/resources/test/tests/unit/IdlInterface/get_qualified_name.html
testing/web-platform/tests/wasm/idlharness.any.js
testing/web-platform/tests/wasm/jsapi/idlharness.any.js
testing/web-platform/tests/wasm/resources/load_wasm.js
--- a/testing/web-platform/tests/resources/idlharness.js
+++ b/testing/web-platform/tests/resources/idlharness.js
@@ -1251,16 +1251,58 @@ IdlInterface.prototype.get_unscopables =
 
 IdlInterface.prototype.is_global = function()
 {
     return this.extAttrs.some(function(attribute) {
         return attribute.name === "Global";
     });
 };
 
+/**
+ * Value of the LegacyNamespace extended attribute, if any.
+ *
+ * https://heycam.github.io/webidl/#LegacyNamespace
+ */
+IdlInterface.prototype.get_legacy_namespace = function()
+{
+    var legacyNamespace = this.extAttrs.find(function(attribute) {
+        return attribute.name === "LegacyNamespace";
+    });
+    return legacyNamespace ? legacyNamespace.rhs.value : undefined;
+};
+
+IdlInterface.prototype.get_interface_object_owner = function()
+{
+    var legacyNamespace = this.get_legacy_namespace();
+    return legacyNamespace ? self[legacyNamespace] : self;
+};
+
+IdlInterface.prototype.assert_interface_object_exists = function()
+{
+    var owner = this.get_legacy_namespace() || "self";
+    assert_own_property(self[owner], this.name, owner + " does not have own property " + format_value(this.name));
+};
+
+IdlInterface.prototype.get_interface_object = function() {
+    if (this.has_extended_attribute("NoInterfaceObject")) {
+        throw new IdlHarnessError(this.name + " has no interface object due to NoInterfaceObject");
+    }
+
+    return this.get_interface_object_owner()[this.name];
+};
+
+IdlInterface.prototype.get_qualified_name = function() {
+    // https://heycam.github.io/webidl/#qualified-name
+    var legacyNamespace = this.get_legacy_namespace();
+    if (legacyNamespace) {
+        return legacyNamespace + "." + this.name;
+    }
+    return this.name;
+};
+
 IdlInterface.prototype.has_to_json_regular_operation = function() {
     return this.members.some(function(m) {
         return m.is_to_json_regular_operation();
     });
 };
 
 IdlInterface.prototype.has_default_to_json_regular_operation = function() {
     return this.members.some(function(m) {
@@ -1431,29 +1473,28 @@ IdlInterface.prototype.test_self = funct
         // The property has the attributes { [[Writable]]: true,
         // [[Enumerable]]: false, [[Configurable]]: true }."
         if (this.is_callback() && !this.has_constants()) {
             return;
         }
 
         // TODO: Should we test here that the property is actually writable
         // etc., or trust getOwnPropertyDescriptor?
-        assert_own_property(self, this.name,
-                            "self does not have own property " + format_value(this.name));
-        var desc = Object.getOwnPropertyDescriptor(self, this.name);
+        this.assert_interface_object_exists();
+        var desc = Object.getOwnPropertyDescriptor(this.get_interface_object_owner(), this.name);
         assert_false("get" in desc, "self's property " + format_value(this.name) + " should not have a getter");
         assert_false("set" in desc, "self's property " + format_value(this.name) + " should not have a setter");
         assert_true(desc.writable, "self's property " + format_value(this.name) + " should be writable");
         assert_false(desc.enumerable, "self's property " + format_value(this.name) + " should not be enumerable");
         assert_true(desc.configurable, "self's property " + format_value(this.name) + " should be configurable");
 
         if (this.is_callback()) {
             // "The internal [[Prototype]] property of an interface object for
             // a callback interface must be the Function.prototype object."
-            assert_equals(Object.getPrototypeOf(self[this.name]), Function.prototype,
+            assert_equals(Object.getPrototypeOf(this.get_interface_object()), Function.prototype,
                           "prototype of self's property " + format_value(this.name) + " is not Object.prototype");
 
             return;
         }
 
         // "The interface object for a given non-callback interface is a
         // function object."
         // "If an object is defined to be a function object, then it has
@@ -1473,34 +1514,29 @@ IdlInterface.prototype.test_self = funct
 
         // "* Its @@hasInstance property is set as described in ECMA-262
         //    section 19.2.3.8, unless otherwise specified."
         // TODO
 
         // ES6 (rev 30) 19.1.3.6:
         // "Else, if O has a [[Call]] internal method, then let builtinTag be
         // "Function"."
-        assert_class_string(self[this.name], "Function", "class string of " + this.name);
+        assert_class_string(this.get_interface_object(), "Function", "class string of " + this.name);
 
         // "The [[Prototype]] internal property of an interface object for a
         // non-callback interface is determined as follows:"
-        var prototype = Object.getPrototypeOf(self[this.name]);
+        var prototype = Object.getPrototypeOf(this.get_interface_object());
         if (this.base) {
             // "* If the interface inherits from some other interface, the
             //    value of [[Prototype]] is the interface object for that other
             //    interface."
-            var has_interface_object =
-                !this.array
-                     .members[this.base]
-                     .has_extended_attribute("NoInterfaceObject");
-            if (has_interface_object) {
-                assert_own_property(self, this.base,
-                                    'should inherit from ' + this.base +
-                                    ', but self has no such property');
-                assert_equals(prototype, self[this.base],
+            var inherited_interface = this.array.members[this.base];
+            if (!inherited_interface.has_extended_attribute("NoInterfaceObject")) {
+                inherited_interface.assert_interface_object_exists();
+                assert_equals(prototype, inherited_interface.get_interface_object(),
                               'prototype of ' + this.name + ' is not ' +
                               this.base);
             }
         } else {
             // "If the interface doesn't inherit from any other interface, the
             // value of [[Prototype]] is %FunctionPrototype% ([ECMA-262],
             // section 6.1.7.4)."
             assert_equals(prototype, Function.prototype,
@@ -1508,73 +1544,72 @@ IdlInterface.prototype.test_self = funct
         }
 
         if (!this.has_extended_attribute("Constructor")) {
             // "The internal [[Call]] method of the interface object behaves as
             // follows . . .
             //
             // "If I was not declared with a [Constructor] extended attribute,
             // then throw a TypeError."
+            var interface_object = this.get_interface_object();
             assert_throws(new TypeError(), function() {
-                self[this.name]();
-            }.bind(this), "interface object didn't throw TypeError when called as a function");
+                interface_object();
+            }, "interface object didn't throw TypeError when called as a function");
             assert_throws(new TypeError(), function() {
-                new self[this.name]();
-            }.bind(this), "interface object didn't throw TypeError when called as a constructor");
+                new interface_object();
+            }, "interface object didn't throw TypeError when called as a constructor");
         }
     }.bind(this), this.name + " interface: existence and properties of interface object");
 
     if (!this.is_callback()) {
         subsetTestByKey(this.name, test, function() {
             // This function tests WebIDL as of 2014-10-25.
             // https://heycam.github.io/webidl/#es-interface-call
 
-            assert_own_property(self, this.name,
-                                "self does not have own property " + format_value(this.name));
+            this.assert_interface_object_exists();
 
             // "Interface objects for non-callback interfaces MUST have a
             // property named “length” with attributes { [[Writable]]: false,
             // [[Enumerable]]: false, [[Configurable]]: true } whose value is
             // a Number."
-            assert_own_property(self[this.name], "length");
-            var desc = Object.getOwnPropertyDescriptor(self[this.name], "length");
+            assert_own_property(this.get_interface_object(), "length");
+            var desc = Object.getOwnPropertyDescriptor(this.get_interface_object(), "length");
             assert_false("get" in desc, this.name + ".length should not have a getter");
             assert_false("set" in desc, this.name + ".length should not have a setter");
             assert_false(desc.writable, this.name + ".length should not be writable");
             assert_false(desc.enumerable, this.name + ".length should not be enumerable");
             assert_true(desc.configurable, this.name + ".length should be configurable");
 
             var constructors = this.extAttrs
                 .filter(function(attr) { return attr.name == "Constructor"; });
             var expected_length = minOverloadLength(constructors);
-            assert_equals(self[this.name].length, expected_length, "wrong value for " + this.name + ".length");
+            assert_equals(this.get_interface_object().length, expected_length, "wrong value for " + this.name + ".length");
         }.bind(this), this.name + " interface object length");
     }
 
     if (!this.is_callback() || this.has_constants()) {
         subsetTestByKey(this.name, test, function() {
             // This function tests WebIDL as of 2015-11-17.
             // https://heycam.github.io/webidl/#interface-object
 
-            assert_own_property(self, this.name,
-                                "self does not have own property " + format_value(this.name));
+            this.assert_interface_object_exists();
 
             // "All interface objects must have a property named “name” with
             // attributes { [[Writable]]: false, [[Enumerable]]: false,
             // [[Configurable]]: true } whose value is the identifier of the
             // corresponding interface."
 
-            assert_own_property(self[this.name], "name");
-            var desc = Object.getOwnPropertyDescriptor(self[this.name], "name");
+            assert_own_property(this.get_interface_object(), "name");
+            var desc = Object.getOwnPropertyDescriptor(this.get_interface_object(), "name");
             assert_false("get" in desc, this.name + ".name should not have a getter");
             assert_false("set" in desc, this.name + ".name should not have a setter");
             assert_false(desc.writable, this.name + ".name should not be writable");
             assert_false(desc.enumerable, this.name + ".name should not be enumerable");
             assert_true(desc.configurable, this.name + ".name should be configurable");
-            assert_equals(self[this.name].name, this.name, "wrong value for " + this.name + ".name");
+            assert_equals(this.get_interface_object().name, this.name, "wrong value for " + this.name + ".name");
         }.bind(this), this.name + " interface object name");
     }
 
 
     if (this.has_extended_attribute("LegacyWindowAlias")) {
         subsetTestByKey(this.name, test, function()
         {
             var aliasAttrs = this.extAttrs.filter(function(o) { return o.name === "LegacyWindowAlias"; });
@@ -1603,19 +1638,19 @@ IdlInterface.prototype.test_self = funct
                 aliases = [ rhs.value ];
             }
 
             // OK now actually check the aliases...
             var alias;
             if (exposed_in(exposure_set(this, this.exposureSet)) && 'document' in self) {
                 for (alias of aliases) {
                     assert_true(alias in self, alias + " should exist");
-                    assert_equals(self[alias], self[this.name], "self." + alias + " should be the same value as self." + this.name);
+                    assert_equals(self[alias], this.get_interface_object(), "self." + alias + " should be the same value as the interface object");
                     var desc = Object.getOwnPropertyDescriptor(self, alias);
-                    assert_equals(desc.value, self[this.name], "wrong value in " + alias + " property descriptor");
+                    assert_equals(desc.value, this.get_interface_object(), "wrong value in " + alias + " property descriptor");
                     assert_true(desc.writable, alias + " should be writable");
                     assert_false(desc.enumerable, alias + " should not be enumerable");
                     assert_true(desc.configurable, alias + " should be configurable");
                     assert_false('get' in desc, alias + " should not have a getter");
                     assert_false('set' in desc, alias + " should not have a setter");
                 }
             } else {
                 for (alias of aliases) {
@@ -1631,35 +1666,34 @@ IdlInterface.prototype.test_self = funct
     {
         // This function tests WebIDL as of 2015-01-21.
         // https://heycam.github.io/webidl/#interface-object
 
         if (this.is_callback() && !this.has_constants()) {
             return;
         }
 
-        assert_own_property(self, this.name,
-                            "self does not have own property " + format_value(this.name));
+        this.assert_interface_object_exists();
 
         if (this.is_callback()) {
-            assert_false("prototype" in self[this.name],
+            assert_false("prototype" in this.get_interface_object(),
                          this.name + ' should not have a "prototype" property');
             return;
         }
 
         // "An interface object for a non-callback interface must have a
         // property named “prototype” with attributes { [[Writable]]: false,
         // [[Enumerable]]: false, [[Configurable]]: false } whose value is an
         // object called the interface prototype object. This object has
         // properties that correspond to the regular attributes and regular
         // operations defined on the interface, and is described in more detail
         // in section 4.5.4 below."
-        assert_own_property(self[this.name], "prototype",
+        assert_own_property(this.get_interface_object(), "prototype",
                             'interface "' + this.name + '" does not have own property "prototype"');
-        var desc = Object.getOwnPropertyDescriptor(self[this.name], "prototype");
+        var desc = Object.getOwnPropertyDescriptor(this.get_interface_object(), "prototype");
         assert_false("get" in desc, this.name + ".prototype should not have a getter");
         assert_false("set" in desc, this.name + ".prototype should not have a setter");
         assert_false(desc.writable, this.name + ".prototype should not be writable");
         assert_false(desc.enumerable, this.name + ".prototype should not be enumerable");
         assert_false(desc.configurable, this.name + ".prototype should not be configurable");
 
         // Next, test that the [[Prototype]] of the interface prototype object
         // is correct. (This is made somewhat difficult by the existence of
@@ -1682,144 +1716,143 @@ IdlInterface.prototype.test_self = funct
         // "In the ECMAScript binding, the DOMException type has some additional
         // requirements:
         //
         //     "Unlike normal interface types, the interface prototype object
         //     for DOMException must have as its [[Prototype]] the intrinsic
         //     object %ErrorPrototype%."
         //
         if (this.name === "Window") {
-            assert_class_string(Object.getPrototypeOf(self[this.name].prototype),
+            assert_class_string(Object.getPrototypeOf(this.get_interface_object().prototype),
                                 'WindowProperties',
                                 'Class name for prototype of Window' +
                                 '.prototype is not "WindowProperties"');
         } else {
-            var inherit_interface, inherit_interface_has_interface_object;
+            var inherit_interface, inherit_interface_interface_object;
             if (this.base) {
                 inherit_interface = this.base;
-                inherit_interface_has_interface_object =
-                    !this.array
-                         .members[inherit_interface]
-                         .has_extended_attribute("NoInterfaceObject");
+                var parent = this.array.members[inherit_interface];
+                if (!parent.has_extended_attribute("NoInterfaceObject")) {
+                    parent.assert_interface_object_exists();
+                    inherit_interface_interface_object = parent.get_interface_object();
+                }
             } else if (this.name === "DOMException") {
                 inherit_interface = 'Error';
-                inherit_interface_has_interface_object = true;
+                inherit_interface_interface_object = self.Error;
             } else {
                 inherit_interface = 'Object';
-                inherit_interface_has_interface_object = true;
+                inherit_interface_interface_object = self.Object;
             }
-            if (inherit_interface_has_interface_object) {
-                assert_own_property(self, inherit_interface,
-                                    'should inherit from ' + inherit_interface + ', but self has no such property');
-                assert_own_property(self[inherit_interface], 'prototype',
+            if (inherit_interface_interface_object) {
+                assert_not_equals(inherit_interface_interface_object, undefined,
+                                  'should inherit from ' + inherit_interface + ', but there is no such property');
+                assert_own_property(inherit_interface_interface_object, 'prototype',
                                     'should inherit from ' + inherit_interface + ', but that object has no "prototype" property');
-                assert_equals(Object.getPrototypeOf(self[this.name].prototype),
-                              self[inherit_interface].prototype,
+                assert_equals(Object.getPrototypeOf(this.get_interface_object().prototype),
+                              inherit_interface_interface_object.prototype,
                               'prototype of ' + this.name + '.prototype is not ' + inherit_interface + '.prototype');
             } else {
                 // We can't test that we get the correct object, because this is the
                 // only way to get our hands on it. We only test that its class
                 // string, at least, is correct.
-                assert_class_string(Object.getPrototypeOf(self[this.name].prototype),
+                assert_class_string(Object.getPrototypeOf(this.get_interface_object().prototype),
                                     inherit_interface + 'Prototype',
                                     'Class name for prototype of ' + this.name +
                                     '.prototype is not "' + inherit_interface + 'Prototype"');
             }
         }
 
         // "The class string of an interface prototype object is the
-        // concatenation of the interface’s identifier and the string
+        // concatenation of the interface’s qualified identifier and the string
         // “Prototype”."
 
         // Skip these tests for now due to a specification issue about
         // prototype name.
         // https://www.w3.org/Bugs/Public/show_bug.cgi?id=28244
 
-        // assert_class_string(self[this.name].prototype, this.name + "Prototype",
+        // assert_class_string(this.get_interface_object().prototype, this.get_qualified_name() + "Prototype",
         //                     "class string of " + this.name + ".prototype");
 
         // String() should end up calling {}.toString if nothing defines a
         // stringifier.
         if (!this.has_stringifier()) {
-            // assert_equals(String(self[this.name].prototype), "[object " + this.name + "Prototype]",
+            // assert_equals(String(this.get_interface_object().prototype), "[object " + this.get_qualified_name() + "Prototype]",
             //         "String(" + this.name + ".prototype)");
         }
     }.bind(this), this.name + " interface: existence and properties of interface prototype object");
 
     // "If the interface is declared with the [Global]
     // extended attribute, or the interface is in the set of inherited
     // interfaces for any other interface that is declared with one of these
     // attributes, then the interface prototype object must be an immutable
     // prototype exotic object."
     // https://heycam.github.io/webidl/#interface-prototype-object
     if (this.is_global()) {
-        this.test_immutable_prototype("interface prototype object", self[this.name].prototype);
+        this.test_immutable_prototype("interface prototype object", this.get_interface_object().prototype);
     }
 
     subsetTestByKey(this.name, test, function()
     {
         if (this.is_callback() && !this.has_constants()) {
             return;
         }
 
-        assert_own_property(self, this.name,
-                            "self does not have own property " + format_value(this.name));
+        this.assert_interface_object_exists();
 
         if (this.is_callback()) {
-            assert_false("prototype" in self[this.name],
+            assert_false("prototype" in this.get_interface_object(),
                          this.name + ' should not have a "prototype" property');
             return;
         }
 
-        assert_own_property(self[this.name], "prototype",
+        assert_own_property(this.get_interface_object(), "prototype",
                             'interface "' + this.name + '" does not have own property "prototype"');
 
         // "If the [NoInterfaceObject] extended attribute was not specified on
         // the interface, then the interface prototype object must also have a
         // property named “constructor” with attributes { [[Writable]]: true,
         // [[Enumerable]]: false, [[Configurable]]: true } whose value is a
         // reference to the interface object for the interface."
-        assert_own_property(self[this.name].prototype, "constructor",
+        assert_own_property(this.get_interface_object().prototype, "constructor",
                             this.name + '.prototype does not have own property "constructor"');
-        var desc = Object.getOwnPropertyDescriptor(self[this.name].prototype, "constructor");
+        var desc = Object.getOwnPropertyDescriptor(this.get_interface_object().prototype, "constructor");
         assert_false("get" in desc, this.name + ".prototype.constructor should not have a getter");
         assert_false("set" in desc, this.name + ".prototype.constructor should not have a setter");
         assert_true(desc.writable, this.name + ".prototype.constructor should be writable");
         assert_false(desc.enumerable, this.name + ".prototype.constructor should not be enumerable");
         assert_true(desc.configurable, this.name + ".prototype.constructor should be configurable");
-        assert_equals(self[this.name].prototype.constructor, self[this.name],
+        assert_equals(this.get_interface_object().prototype.constructor, this.get_interface_object(),
                       this.name + '.prototype.constructor is not the same object as ' + this.name);
     }.bind(this), this.name + ' interface: existence and properties of interface prototype object\'s "constructor" property');
 
 
     subsetTestByKey(this.name, test, function()
     {
         if (this.is_callback() && !this.has_constants()) {
             return;
         }
 
-        assert_own_property(self, this.name,
-                            "self does not have own property " + format_value(this.name));
+        this.assert_interface_object_exists();
 
         if (this.is_callback()) {
-            assert_false("prototype" in self[this.name],
+            assert_false("prototype" in this.get_interface_object(),
                          this.name + ' should not have a "prototype" property');
             return;
         }
 
-        assert_own_property(self[this.name], "prototype",
+        assert_own_property(this.get_interface_object(), "prototype",
                             'interface "' + this.name + '" does not have own property "prototype"');
 
         // If the interface has any member declared with the [Unscopable] extended
         // attribute, then there must be a property on the interface prototype object
         // whose name is the @@unscopables symbol, which has the attributes
         // { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true },
         // and whose value is an object created as follows...
         var unscopables = this.get_unscopables().map(m => m.name);
-        var proto = self[this.name].prototype;
+        var proto = this.get_interface_object().prototype;
         if (unscopables.length != 0) {
             assert_own_property(
                 proto, Symbol.unscopables,
                 this.name + '.prototype should have an @@unscopables property');
             var desc = Object.getOwnPropertyDescriptor(proto, Symbol.unscopables);
             assert_false("get" in desc,
                          this.name + ".prototype[Symbol.unscopables] should not have a getter");
             assert_false("set" in desc, this.name + ".prototype[Symbol.unscopables] should not have a setter");
@@ -1831,25 +1864,28 @@ IdlInterface.prototype.test_self = funct
             assert_equals(typeof desc.value, "object",
                           this.name + '.prototype[Symbol.unscopables] should be an object');
             assert_equals(Object.getPrototypeOf(desc.value), null,
                           this.name + '.prototype[Symbol.unscopables] should have a null prototype');
             assert_equals(Object.getOwnPropertySymbols(desc.value).length,
                           0,
                           this.name + '.prototype[Symbol.unscopables] should have the right number of symbol-named properties');
 
-            // It would be nice to check that we do not have _extra_
-            // unscopables, but someone might be calling us with only a subset
-            // of the IDL the browser know about, and our subset may exclude
-            // unscopable things that really do exist.
+            // Check that we do not have _extra_ unscopables.  Checking that we
+            // have all the ones we should will happen in the per-member tests.
+            var observed = Object.getOwnPropertyNames(desc.value);
+            for (var prop of observed) {
+                assert_not_equals(unscopables.indexOf(prop),
+                                  -1,
+                                  this.name + '.prototype[Symbol.unscopables] has unexpected property "' + prop + '"');
+            }
         } else {
-            // It would be nice to assert that there is no @@unscopables on this
-            // prototype, but someone might be calling us with only a subset of
-            // the IDL the browser know about, and our subset may exclude
-            // unscopable things that really do exist.
+            assert_equals(Object.getOwnPropertyDescriptor(this.get_interface_object().prototype, Symbol.unscopables),
+                          undefined,
+                          this.name + '.prototype should not have @@unscopables');
         }
     }.bind(this), this.name + ' interface: existence and properties of interface prototype object\'s @@unscopables property');
 };
 
 IdlInterface.prototype.test_immutable_prototype = function(type, obj)
 {
     if (typeof Object.setPrototypeOf !== "function") {
         return;
@@ -1954,58 +1990,56 @@ IdlInterface.prototype.test_immutable_pr
 IdlInterface.prototype.test_member_const = function(member)
 {
     if (!this.has_constants()) {
         throw new IdlHarnessError("Internal error: test_member_const called without any constants");
     }
 
     subsetTestByKey(this.name, test, function()
     {
-        assert_own_property(self, this.name,
-                            "self does not have own property " + format_value(this.name));
+        this.assert_interface_object_exists();
 
         // "For each constant defined on an interface A, there must be
         // a corresponding property on the interface object, if it
         // exists."
-        assert_own_property(self[this.name], member.name);
+        assert_own_property(this.get_interface_object(), member.name);
         // "The value of the property is that which is obtained by
         // converting the constant’s IDL value to an ECMAScript
         // value."
-        assert_equals(self[this.name][member.name], constValue(member.value),
+        assert_equals(this.get_interface_object()[member.name], constValue(member.value),
                       "property has wrong value");
         // "The property has attributes { [[Writable]]: false,
         // [[Enumerable]]: true, [[Configurable]]: false }."
-        var desc = Object.getOwnPropertyDescriptor(self[this.name], member.name);
+        var desc = Object.getOwnPropertyDescriptor(this.get_interface_object(), member.name);
         assert_false("get" in desc, "property should not have a getter");
         assert_false("set" in desc, "property should not have a setter");
         assert_false(desc.writable, "property should not be writable");
         assert_true(desc.enumerable, "property should be enumerable");
         assert_false(desc.configurable, "property should not be configurable");
     }.bind(this), this.name + " interface: constant " + member.name + " on interface object");
 
     // "In addition, a property with the same characteristics must
     // exist on the interface prototype object."
     subsetTestByKey(this.name, test, function()
     {
-        assert_own_property(self, this.name,
-                            "self does not have own property " + format_value(this.name));
+        this.assert_interface_object_exists();
 
         if (this.is_callback()) {
-            assert_false("prototype" in self[this.name],
+            assert_false("prototype" in this.get_interface_object(),
                          this.name + ' should not have a "prototype" property');
             return;
         }
 
-        assert_own_property(self[this.name], "prototype",
+        assert_own_property(this.get_interface_object(), "prototype",
                             'interface "' + this.name + '" does not have own property "prototype"');
 
-        assert_own_property(self[this.name].prototype, member.name);
-        assert_equals(self[this.name].prototype[member.name], constValue(member.value),
+        assert_own_property(this.get_interface_object().prototype, member.name);
+        assert_equals(this.get_interface_object().prototype[member.name], constValue(member.value),
                       "property has wrong value");
-        var desc = Object.getOwnPropertyDescriptor(self[this.name], member.name);
+        var desc = Object.getOwnPropertyDescriptor(this.get_interface_object(), member.name);
         assert_false("get" in desc, "property should not have a getter");
         assert_false("set" in desc, "property should not have a setter");
         assert_false(desc.writable, "property should not be writable");
         assert_true(desc.enumerable, "property should be enumerable");
         assert_false(desc.configurable, "property should not be configurable");
     }.bind(this), this.name + " interface: constant " + member.name + " on interface prototype object");
 };
 
@@ -2018,36 +2052,35 @@ IdlInterface.prototype.test_member_attri
     var a_test = subsetTestByKey(this.name, async_test, this.name + " interface: attribute " + member.name);
     a_test.step(function()
     {
         if (this.is_callback() && !this.has_constants()) {
             a_test.done()
             return;
         }
 
-        assert_own_property(self, this.name,
-                            "self does not have own property " + format_value(this.name));
-        assert_own_property(self[this.name], "prototype",
+        this.assert_interface_object_exists();
+        assert_own_property(this.get_interface_object(), "prototype",
                             'interface "' + this.name + '" does not have own property "prototype"');
 
         if (member["static"]) {
-            assert_own_property(self[this.name], member.name,
+            assert_own_property(this.get_interface_object(), member.name,
                 "The interface object must have a property " +
                 format_value(member.name));
             a_test.done();
             return;
         }
 
         this.do_member_unscopable_asserts(member);
 
         if (this.is_global()) {
             assert_own_property(self, member.name,
                 "The global object must have a property " +
                 format_value(member.name));
-            assert_false(member.name in self[this.name].prototype,
+            assert_false(member.name in this.get_interface_object().prototype,
                 "The prototype object should not have a property " +
                 format_value(member.name));
 
             var getter = Object.getOwnPropertyDescriptor(self, member.name).get;
             assert_equals(typeof(getter), "function",
                           format_value(member.name) + " must have a getter");
 
             // Try/catch around the get here, since it can legitimately throw.
@@ -2065,44 +2098,44 @@ IdlInterface.prototype.test_member_attri
                 assert_equals(propVal, getter.call(undefined),
                               "Gets on a global should not require an explicit this");
             }
 
             // do_interface_attribute_asserts must be the last thing we do,
             // since it will call done() on a_test.
             this.do_interface_attribute_asserts(self, member, a_test);
         } else {
-            assert_true(member.name in self[this.name].prototype,
+            assert_true(member.name in this.get_interface_object().prototype,
                 "The prototype object must have a property " +
                 format_value(member.name));
 
             if (!member.has_extended_attribute("LenientThis")) {
                 if (member.idlType.generic !== "Promise") {
                     assert_throws(new TypeError(), function() {
-                        self[this.name].prototype[member.name];
+                        this.get_interface_object().prototype[member.name];
                     }.bind(this), "getting property on prototype object must throw TypeError");
                     // do_interface_attribute_asserts must be the last thing we
                     // do, since it will call done() on a_test.
-                    this.do_interface_attribute_asserts(self[this.name].prototype, member, a_test);
+                    this.do_interface_attribute_asserts(this.get_interface_object().prototype, member, a_test);
                 } else {
                     promise_rejects(a_test, new TypeError(),
-                                    self[this.name].prototype[member.name])
+                                    this.get_interface_object().prototype[member.name])
                         .then(function() {
                             // do_interface_attribute_asserts must be the last
                             // thing we do, since it will call done() on a_test.
-                            this.do_interface_attribute_asserts(self[this.name].prototype,
+                            this.do_interface_attribute_asserts(this.get_interface_object().prototype,
                                                                 member, a_test);
                         }.bind(this));
                 }
             } else {
-                assert_equals(self[this.name].prototype[member.name], undefined,
+                assert_equals(this.get_interface_object().prototype[member.name], undefined,
                               "getting property on prototype object must return undefined");
               // do_interface_attribute_asserts must be the last thing we do,
               // since it will call done() on a_test.
-              this.do_interface_attribute_asserts(self[this.name].prototype, member, a_test);
+              this.do_interface_attribute_asserts(this.get_interface_object().prototype, member, a_test);
             }
         }
     }.bind(this));
 };
 
 IdlInterface.prototype.test_member_operation = function(member)
 {
     if (!shouldRunSubTest(this.name)) {
@@ -2117,74 +2150,71 @@ IdlInterface.prototype.test_member_opera
         // This function tests WebIDL as of 2015-12-29.
         // https://heycam.github.io/webidl/#es-operations
 
         if (this.is_callback() && !this.has_constants()) {
             a_test.done();
             return;
         }
 
-        assert_own_property(self, this.name,
-                            "self does not have own property " + format_value(this.name));
+        this.assert_interface_object_exists();
 
         if (this.is_callback()) {
-            assert_false("prototype" in self[this.name],
+            assert_false("prototype" in this.get_interface_object(),
                          this.name + ' should not have a "prototype" property');
             a_test.done();
             return;
         }
 
-        assert_own_property(self[this.name], "prototype",
+        assert_own_property(this.get_interface_object(), "prototype",
                             'interface "' + this.name + '" does not have own property "prototype"');
 
         // "For each unique identifier of an exposed operation defined on the
         // interface, there must exist a corresponding property, unless the
         // effective overload set for that identifier and operation and with an
         // argument count of 0 has no entries."
 
         // TODO: Consider [Exposed].
 
         // "The location of the property is determined as follows:"
         var memberHolderObject;
         // "* If the operation is static, then the property exists on the
         //    interface object."
         if (member["static"]) {
-            assert_own_property(self[this.name], member.name,
+            assert_own_property(this.get_interface_object(), member.name,
                     "interface object missing static operation");
-            memberHolderObject = self[this.name];
+            memberHolderObject = this.get_interface_object();
         // "* Otherwise, [...] if the interface was declared with the [Global]
         //    extended attribute, then the property exists
         //    on every object that implements the interface."
         } else if (this.is_global()) {
             assert_own_property(self, member.name,
                     "global object missing non-static operation");
             memberHolderObject = self;
         // "* Otherwise, the property exists solely on the interface’s
         //    interface prototype object."
         } else {
-            assert_own_property(self[this.name].prototype, member.name,
+            assert_own_property(this.get_interface_object().prototype, member.name,
                     "interface prototype object missing non-static operation");
-            memberHolderObject = self[this.name].prototype;
+            memberHolderObject = this.get_interface_object().prototype;
         }
         this.do_member_unscopable_asserts(member);
         this.do_member_operation_asserts(memberHolderObject, member, a_test);
     }.bind(this));
 };
 
 IdlInterface.prototype.do_member_unscopable_asserts = function(member)
 {
     // Check that if the member is unscopable then it's in the
     // @@unscopables object properly.
     if (!member.isUnscopable) {
         return;
     }
 
-    var unscopables = self[this.name].prototype[Symbol.unscopables];
-    assert_equals(typeof unscopables, "object",
-                  this.name + '.prototype[Symbol.unscopables] must exist');
+    var unscopables = this.get_interface_object().prototype[Symbol.unscopables];
     var prop = member.name;
     var propDesc = Object.getOwnPropertyDescriptor(unscopables, prop);
     assert_equals(typeof propDesc, "object",
                   this.name + '.prototype[Symbol.unscopables].' + prop + ' must exist')
     assert_false("get" in propDesc,
                  this.name + '.prototype[Symbol.unscopables].' + prop + ' must have no getter');
     assert_false("set" in propDesc,
                  this.name + '.prototype[Symbol.unscopables].' + prop + ' must have no setter');
@@ -2302,63 +2332,61 @@ IdlInterface.prototype.test_to_json_oper
             assert_true(this.array.is_json_type(member.idlType), JSON.stringify(member.idlType) + " is not an appropriate return value for the toJSON operation of " + instanceName);
             this.array.assert_type_is(memberHolderObject.toJSON(), member.idlType);
         }.bind(this), "Test toJSON operation of " + instanceName);
     }
 };
 
 IdlInterface.prototype.test_member_iterable = function(member)
 {
-    var interfaceName = this.name;
     var isPairIterator = member.idlType.length === 2;
     subsetTestByKey(this.name, test, function()
     {
-        var descriptor = Object.getOwnPropertyDescriptor(self[interfaceName].prototype, Symbol.iterator);
+        var descriptor = Object.getOwnPropertyDescriptor(this.get_interface_object().prototype, Symbol.iterator);
         assert_true(descriptor.writable, "property should be writable");
         assert_true(descriptor.configurable, "property should be configurable");
         assert_false(descriptor.enumerable, "property should not be enumerable");
-        assert_equals(self[interfaceName].prototype[Symbol.iterator].name, isPairIterator ? "entries" : "values", "@@iterator function does not have the right name");
-    }, "Testing Symbol.iterator property of iterable interface " + interfaceName);
+        assert_equals(this.get_interface_object().prototype[Symbol.iterator].name, isPairIterator ? "entries" : "values", "@@iterator function does not have the right name");
+    }.bind(this), "Testing Symbol.iterator property of iterable interface " + this.name);
 
     if (isPairIterator) {
         subsetTestByKey(this.name, test, function() {
-            assert_equals(self[interfaceName].prototype[Symbol.iterator], self[interfaceName].prototype["entries"], "entries method is not the same as @@iterator");
-        }, "Testing pair iterable interface " + interfaceName);
+            assert_equals(this.get_interface_object().prototype[Symbol.iterator], this.get_interface_object().prototype["entries"], "entries method is not the same as @@iterator");
+        }.bind(this), "Testing pair iterable interface " + this.name);
     } else {
         subsetTestByKey(this.name, test, function() {
             ["entries", "keys", "values", "forEach", Symbol.Iterator].forEach(function(property) {
-                assert_equals(self[interfaceName].prototype[property], Array.prototype[property], property + " function is not the same as Array one");
-            });
-        }, "Testing value iterable interface " + interfaceName);
+                assert_equals(this.get_interface_object().prototype[property], Array.prototype[property], property + " function is not the same as Array one");
+            }.bind(this));
+        }.bind(this), "Testing value iterable interface " + this.name);
     }
 };
 
 IdlInterface.prototype.test_member_stringifier = function(member)
 {
     subsetTestByKey(this.name, test, function()
     {
         if (this.is_callback() && !this.has_constants()) {
             return;
         }
 
-        assert_own_property(self, this.name,
-                            "self does not have own property " + format_value(this.name));
+        this.assert_interface_object_exists();
 
         if (this.is_callback()) {
-            assert_false("prototype" in self[this.name],
+            assert_false("prototype" in this.get_interface_object(),
                          this.name + ' should not have a "prototype" property');
             return;
         }
 
-        assert_own_property(self[this.name], "prototype",
+        assert_own_property(this.get_interface_object(), "prototype",
                             'interface "' + this.name + '" does not have own property "prototype"');
 
         // ". . . the property exists on the interface prototype object."
-        var interfacePrototypeObject = self[this.name].prototype;
-        assert_own_property(self[this.name].prototype, "toString",
+        var interfacePrototypeObject = this.get_interface_object().prototype;
+        assert_own_property(interfacePrototypeObject, "toString",
                 "interface prototype object missing non-static operation");
 
         var stringifierUnforgeable = member.isUnforgeable;
         var desc = Object.getOwnPropertyDescriptor(interfacePrototypeObject, "toString");
         // "The property has attributes { [[Writable]]: B,
         // [[Enumerable]]: true, [[Configurable]]: B }, where B is false if the
         // stringifier is unforgeable on the interface, and true otherwise."
         assert_false("get" in desc, "property should not have a getter");
@@ -2374,26 +2402,26 @@ IdlInterface.prototype.test_member_strin
                       "property must be a function");
         // "The value of the Function object’s “length” property is the Number
         // value 0."
         assert_equals(interfacePrototypeObject.toString.length, 0,
             "property has wrong .length");
 
         // "Let O be the result of calling ToObject on the this value."
         assert_throws(new TypeError(), function() {
-            self[this.name].prototype.toString.apply(null, []);
+            interfacePrototypeObject.toString.apply(null, []);
         }, "calling stringifier with this = null didn't throw TypeError");
 
         // "If O is not an object that implements the interface on which the
         // stringifier was declared, then throw a TypeError."
         //
         // TODO: Test a platform object that implements some other
         // interface.  (Have to be sure to get inheritance right.)
         assert_throws(new TypeError(), function() {
-            self[this.name].prototype.toString.apply({}, []);
+            interfacePrototypeObject.toString.apply({}, []);
         }, "calling stringifier with this = {} didn't throw TypeError");
     }.bind(this), this.name + " interface: stringifier");
 };
 
 IdlInterface.prototype.test_members = function()
 {
     for (var i = 0; i < this.members.length; i++)
     {
@@ -2413,20 +2441,20 @@ IdlInterface.prototype.test_members = fu
         var member = this.members[i];
         if (member.untested) {
             continue;
         }
 
         if (!exposed_in(exposure_set(member, this.exposureSet))) {
             subsetTestByKey(this.name, test, function() {
                 // It's not exposed, so we shouldn't find it anywhere.
-                assert_false(member.name in self[this.name],
+                assert_false(member.name in this.get_interface_object(),
                              "The interface object must not have a property " +
                              format_value(member.name));
-                assert_false(member.name in self[this.name].prototype,
+                assert_false(member.name in this.get_interface_object().prototype,
                              "The prototype object must not have a property " +
                              format_value(member.name));
             }.bind(this), this.name + " interface: member " + member.name);
             continue;
         }
 
         switch (member.type) {
         case "const":
@@ -2532,42 +2560,41 @@ IdlInterface.prototype.test_primary_inte
     // least looks correct, even if we can't test that it's actually correct.
     if (!this.has_extended_attribute("NoInterfaceObject")
     && (typeof obj != expected_typeof || obj instanceof Object))
     {
         subsetTestByKey(this.name, test, function()
         {
             assert_equals(exception, null, "Unexpected exception when evaluating object");
             assert_equals(typeof obj, expected_typeof, "wrong typeof object");
-            assert_own_property(self, this.name,
-                                "self does not have own property " + format_value(this.name));
-            assert_own_property(self[this.name], "prototype",
+            this.assert_interface_object_exists();
+            assert_own_property(this.get_interface_object(), "prototype",
                                 'interface "' + this.name + '" does not have own property "prototype"');
 
             // "The value of the internal [[Prototype]] property of the
             // platform object is the interface prototype object of the primary
             // interface from the platform object’s associated global
             // environment."
             assert_equals(Object.getPrototypeOf(obj),
-                          self[this.name].prototype,
+                          this.get_interface_object().prototype,
                           desc + "'s prototype is not " + this.name + ".prototype");
         }.bind(this), this.name + " must be primary interface of " + desc);
     }
 
     // "The class string of a platform object that implements one or more
-    // interfaces must be the identifier of the primary interface of the
+    // interfaces must be the qualified name of the primary interface of the
     // platform object."
     subsetTestByKey(this.name, test, function()
     {
         assert_equals(exception, null, "Unexpected exception when evaluating object");
         assert_equals(typeof obj, expected_typeof, "wrong typeof object");
-        assert_class_string(obj, this.name, "class string of " + desc);
+        assert_class_string(obj, this.get_qualified_name(), "class string of " + desc);
         if (!this.has_stringifier())
         {
-            assert_equals(String(obj), "[object " + this.name + "]", "String(" + desc + ")");
+            assert_equals(String(obj), "[object " + this.get_qualified_name() + "]", "String(" + desc + ")");
         }
     }.bind(this), "Stringification of " + desc);
 };
 
 IdlInterface.prototype.test_interface_of = function(desc, obj, exception, expected_typeof)
 {
     // TODO: Indexed and named properties, more checks on interface members
     this.already_tested = true;
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/resources/test/tests/unit/IdlInterface/get_interface_object.html
@@ -0,0 +1,22 @@
+<!DOCTYPE HTML>
+<title>IdlInterface.prototype.get_interface_object()</title>
+<div id="log"></div>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/WebIDLParser.js"></script>
+<script src="/resources/idlharness.js"></script>
+<script src="../../../idl-helper.js"></script>
+<script>
+"use strict";
+test(function() {
+    window.A = {};
+    var i = interfaceFrom('interface A { };');
+    assert_equals(i.get_interface_object(), window.A);
+}, 'Interface does not have LegacyNamespace.');
+
+test(function() {
+    window.Foo = { A: {} };
+    var i = interfaceFrom('[LegacyNamespace=Foo] interface A { }; namespace Foo { };');
+    assert_equals(i.get_interface_object(), window.Foo.A);
+}, 'Interface has LegacyNamespace');
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/resources/test/tests/unit/IdlInterface/get_interface_object_owner.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML>
+<title>IdlInterface.prototype.get_interface_object_owner()</title>
+<div id="log"></div>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/WebIDLParser.js"></script>
+<script src="/resources/idlharness.js"></script>
+<script src="../../../idl-helper.js"></script>
+<script>
+"use strict";
+test(function() {
+    var i = interfaceFrom('interface A { };');
+    assert_equals(i.get_interface_object_owner(), window);
+}, 'Interface does not have LegacyNamespace.');
+
+test(function() {
+    window.Foo = {};
+    var i = interfaceFrom('[LegacyNamespace=Foo] interface A { }; namespace Foo { };');
+    assert_equals(i.get_interface_object_owner(), window.Foo);
+}, 'Interface has LegacyNamespace');
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/resources/test/tests/unit/IdlInterface/get_legacy_namespace.html
@@ -0,0 +1,20 @@
+<!DOCTYPE HTML>
+<title>IdlInterface.prototype.get_legacy_namespace()</title>
+<div id="log"></div>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/WebIDLParser.js"></script>
+<script src="/resources/idlharness.js"></script>
+<script src="../../../idl-helper.js"></script>
+<script>
+"use strict";
+test(function() {
+    var i = interfaceFrom('interface A { };');
+    assert_equals(i.get_legacy_namespace(), undefined);
+}, 'Interface does not have LegacyNamespace.');
+
+test(function() {
+    var i = interfaceFrom('[LegacyNamespace=Foo] interface A { }; namespace Foo { };');
+    assert_equals(i.get_legacy_namespace(), "Foo");
+}, 'Interface has LegacyNamespace');
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/resources/test/tests/unit/IdlInterface/get_qualified_name.html
@@ -0,0 +1,20 @@
+<!DOCTYPE HTML>
+<title>IdlInterface.prototype.get_qualified_name()</title>
+<div id="log"></div>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/WebIDLParser.js"></script>
+<script src="/resources/idlharness.js"></script>
+<script src="../../../idl-helper.js"></script>
+<script>
+"use strict";
+test(function() {
+    var i = interfaceFrom('interface A { };');
+    assert_equals(i.get_qualified_name(), "A");
+}, 'Interface does not have LegacyNamespace.');
+
+test(function() {
+    var i = interfaceFrom('[LegacyNamespace=Foo] interface A { }; namespace Foo { };');
+    assert_equals(i.get_qualified_name(), "Foo.A");
+}, 'Interface has LegacyNamespace');
+</script>
deleted file mode 100644
--- a/testing/web-platform/tests/wasm/idlharness.any.js
+++ /dev/null
@@ -1,33 +0,0 @@
-// META: script=/resources/WebIDLParser.js
-// META: script=/resources/idlharness.js
-// META: script=resources/load_wasm.js
-
-'use strict';
-
-// https://webassembly.github.io/spec/js-api/
-
-promise_test(async () => {
-  const srcs = ['wasm-js-api'];
-  const [wasm] = await Promise.all(
-    srcs.map(i => fetch(`/interfaces/${i}.idl`).then(r => r.text())));
-
-  const idl_array = new IdlArray();
-  idl_array.add_idls(wasm);
-  // Ignored errors are surfaced in idlharness.js's test_object below.
-  try {
-    self.memory = new Memory({initial: 1024});
-  } catch (e) { }
-
-  try {
-    self.mod = await createWasmModule();
-    self.instance = new Instance(self.mod);
-  } catch (e) { }
-
-  idl_array.add_objects({
-    Memory: ['memory'],
-    Module: ['mod'],
-    Instance: ['instance'],
-  });
-  idl_array.test();
-}, 'wasm-js-api interfaces.');
-
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/wasm/jsapi/idlharness.any.js
@@ -0,0 +1,40 @@
+// META: script=/resources/WebIDLParser.js
+// META: script=/resources/idlharness.js
+// META: script=../resources/load_wasm.js
+
+'use strict';
+
+// https://webassembly.github.io/spec/js-api/
+
+promise_test(async () => {
+  const srcs = ['wasm-js-api'];
+  const [wasm] = await Promise.all(
+    srcs.map(i => fetch(`/interfaces/${i}.idl`).then(r => r.text())));
+
+  const idl_array = new IdlArray();
+  idl_array.add_idls(wasm, {
+    // Note the prose requirements in the specification.
+    except: ['CompileError', 'LinkError', 'RuntimeError']
+  });
+
+  // https://github.com/web-platform-tests/wpt/issues/12850
+  idl_array.add_untested_idls('[Exposed=(Window,Worker)] interface ArrayBuffer {};');
+
+  // Ignored errors are surfaced in idlharness.js's test_object below.
+  try {
+    self.memory = new WebAssembly.Memory({initial: 1024});
+  } catch (e) { }
+
+  try {
+    self.mod = await createWasmModule();
+    self.instance = new WebAssembly.Instance(self.mod);
+  } catch (e) { }
+
+  idl_array.add_objects({
+    Memory: ['memory'],
+    Module: ['mod'],
+    Instance: ['instance'],
+  });
+  idl_array.test();
+}, 'wasm-js-api interfaces.');
+
--- a/testing/web-platform/tests/wasm/resources/load_wasm.js
+++ b/testing/web-platform/tests/wasm/resources/load_wasm.js
@@ -1,12 +1,12 @@
 // Copyright 2016 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 function createWasmModule() {
-    return fetch('incrementer.wasm')
+    return fetch('/wasm/incrementer.wasm')
         .then(response => {
             if (!response.ok) throw new Error(response.statusText);
             return response.arrayBuffer();
         })
         .then(WebAssembly.compile);
 }