summaryrefslogtreecommitdiffstats
path: root/js/src/jit-test/tests/basic/bug1403679.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jit-test/tests/basic/bug1403679.js')
-rw-r--r--js/src/jit-test/tests/basic/bug1403679.js195
1 files changed, 195 insertions, 0 deletions
diff --git a/js/src/jit-test/tests/basic/bug1403679.js b/js/src/jit-test/tests/basic/bug1403679.js
new file mode 100644
index 0000000000..72bb046203
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug1403679.js
@@ -0,0 +1,195 @@
+load(libdir + "asserts.js");
+
+const thisGlobal = this;
+const otherGlobalSameCompartment = newGlobal({sameCompartmentAs: thisGlobal});
+const otherGlobalNewCompartment = newGlobal({newCompartment: true});
+
+const globals = [thisGlobal, otherGlobalSameCompartment, otherGlobalNewCompartment];
+
+function testWithOptions(fn, variants = [undefined]) {
+ for (let variant of variants) {
+ for (let global of globals) {
+ for (let options of [
+ {},
+ {proxy: true},
+ {object: new FakeDOMObject()},
+ ]) {
+ fn(options, global, variant);
+ }
+ }
+ }
+}
+
+function testWithGlobals(fn) {
+ for (let global of globals) {
+ fn(global);
+ }
+}
+
+function testBasic(options, global) {
+ let {object: source, transplant} = transplantableObject(options);
+
+ // Validate that |source| is an object and |transplant| is a function.
+ assertEq(typeof source, "object");
+ assertEq(typeof transplant, "function");
+
+ // |source| is created in the current global.
+ assertEq(objectGlobal(source), this);
+
+ // |source|'s prototype is %ObjectPrototype%, unless it's a FakeDOMObject.
+ let oldPrototype;
+ if (options.object) {
+ oldPrototype = FakeDOMObject.prototype;
+ } else {
+ oldPrototype = Object.prototype;
+ }
+ assertEq(Object.getPrototypeOf(source), oldPrototype);
+
+ // Properties can be created on |source|.
+ assertEq(source.foo, undefined);
+ source.foo = 1;
+ assertEq(source.foo, 1);
+
+ // Calling |transplant| transplants the object and then returns undefined.
+ assertEq(transplant(global), undefined);
+
+ // |source| was moved into the new global. If the new global is in a
+ // different compartment, |source| is a now a CCW.
+ if (global !== otherGlobalNewCompartment) {
+ assertEq(objectGlobal(source), global);
+ } else {
+ assertEq(objectGlobal(source), null);
+ assertEq(isProxy(source), true);
+ }
+
+ // The properties are copied over to the swapped object.
+ assertEq(source.foo, 1);
+
+ // The prototype was changed to %ObjectPrototype% of |global| or the
+ // FakeDOMObject.prototype.
+ let newPrototype;
+ if (options.object) {
+ newPrototype = global.FakeDOMObject.prototype;
+ } else {
+ newPrototype = global.Object.prototype;
+ }
+ assertEq(Object.getPrototypeOf(source), newPrototype);
+}
+testWithOptions(testBasic);
+
+// Objects can be transplanted multiple times between globals.
+function testTransplantMulti(options, global1, global2) {
+ let {object: source, transplant} = transplantableObject(options);
+
+ transplant(global1);
+ transplant(global2);
+}
+testWithOptions(testTransplantMulti, globals);
+
+// Test the case when the source object already has a wrapper in the target global.
+function testHasWrapperInTarget(options, global) {
+ let {object: source, transplant} = transplantableObject(options);
+
+ // Create a wrapper for |source| in the other global.
+ global.p = source;
+ assertEq(global.eval("p"), source);
+
+ if (options.proxy) {
+ // It's a proxy object either way.
+ assertEq(global.eval("isProxy(p)"), true);
+ } else {
+ if (global === otherGlobalNewCompartment) {
+ // |isProxy| returns true because |p| is a CCW.
+ assertEq(global.eval("isProxy(p)"), true);
+ } else {
+ // |isProxy| returns false because |p| is not a CCW.
+ assertEq(global.eval("isProxy(p)"), false);
+ }
+ }
+
+ // And now transplant it into that global.
+ transplant(global);
+
+ assertEq(global.eval("p"), source);
+
+ if (options.proxy) {
+ // It's a proxy object either way.
+ assertEq(global.eval("isProxy(p)"), true);
+ } else {
+ // The previous CCW was replaced with a same-compartment object.
+ assertEq(global.eval("isProxy(p)"), false);
+ }
+}
+testWithOptions(testHasWrapperInTarget);
+
+// Test the case when the source object has a wrapper, but in a different compartment.
+function testHasWrapperOtherCompartment(options, global) {
+ let thirdGlobal = newGlobal({newCompartment: true});
+ let {object: source, transplant} = transplantableObject(options);
+
+ // Create a wrapper for |source| in the new global.
+ thirdGlobal.p = source;
+ assertEq(thirdGlobal.eval("p"), source);
+
+ // And now transplant the object.
+ transplant(global);
+
+ assertEq(thirdGlobal.eval("p"), source);
+}
+testWithOptions(testHasWrapperOtherCompartment);
+
+// Ensure a transplanted object is correctly handled by (weak) collections.
+function testCollections(options, global, AnySet) {
+ let {object, transplant} = transplantableObject(options);
+
+ let set = new AnySet();
+
+ assertEq(set.has(object), false);
+ set.add(object);
+ assertEq(set.has(object), true);
+
+ transplant(global);
+
+ assertEq(set.has(object), true);
+}
+testWithOptions(testCollections, [Set, WeakSet]);
+
+// Ensure DOM object slot is correctly transplanted.
+function testDOMObjectSlot(global) {
+ let domObject = new FakeDOMObject();
+ let expectedValue = domObject.x;
+ assertEq(typeof expectedValue, "number");
+
+ let {object, transplant} = transplantableObject({object: domObject});
+ assertEq(object, domObject);
+
+ transplant(global);
+
+ assertEq(object, domObject);
+ assertEq(domObject.x, expectedValue);
+}
+testWithGlobals(testDOMObjectSlot);
+
+function testArgumentValidation() {
+ // Throws an error if too many arguments are present.
+ assertThrowsInstanceOf(() => transplantableObject(thisGlobal, {}), Error);
+
+ let {object, transplant} = transplantableObject();
+
+ // Throws an error if called with no arguments.
+ assertThrowsInstanceOf(() => transplant(), Error);
+
+ // Throws an error if called with too many arguments.
+ assertThrowsInstanceOf(() => transplant(thisGlobal, {}), Error);
+
+ // Throws an error if the first argument isn't an object
+ assertThrowsInstanceOf(() => transplant(null), Error);
+
+ // Throws an error if the argument isn't a global object.
+ assertThrowsInstanceOf(() => transplant({}), Error);
+
+ // Throws an error if the 'object' option isn't a FakeDOMObject.
+ assertThrowsInstanceOf(() => transplant({object: null}), Error);
+ assertThrowsInstanceOf(() => transplant({object: {}}), Error);
+}
+testArgumentValidation();