Bug 1321583 - Baldr: freeze the exports object r=bbouvier a=jcristau
authorLuke Wagner <luke@mozilla.com>
Fri, 16 Dec 2016 12:12:13 -0600
changeset 353048 9e9258e6585493be7f501186f1c43305ad9900b7
parent 353047 f6a581f5ae0b6d21f642c70822b85ecee267d70f
child 353049 2c7ec3a0c9643f03d81c353a21ad3ee3c72392fa
push id6795
push userjlund@mozilla.com
push dateMon, 23 Jan 2017 14:19:46 +0000
treeherdermozilla-esr52@76101b503191 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbbouvier, jcristau
bugs1321583
milestone52.0a2
Bug 1321583 - Baldr: freeze the exports object r=bbouvier a=jcristau MozReview-Commit-ID: IGDH7LYKMEX
js/src/jit-test/tests/wasm/basic.js
js/src/jit-test/tests/wasm/jsapi.js
js/src/jit-test/tests/wasm/table-gc.js
js/src/wasm/WasmModule.cpp
--- a/js/src/jit-test/tests/wasm/basic.js
+++ b/js/src/jit-test/tests/wasm/basic.js
@@ -13,19 +13,19 @@ var o = wasmEvalText('(module (func) (ex
 var names = Object.getOwnPropertyNames(o);
 assertEq(names.length, 1);
 assertEq(names[0], 'a');
 var desc = Object.getOwnPropertyDescriptor(o, 'a');
 assertEq(typeof desc.value, "function");
 assertEq(desc.value.name, "wasm-function[0]");
 assertEq(desc.value.length, 0);
 assertEq(desc.value(), undefined);
-assertEq(desc.writable, true);
+assertEq(desc.writable, false);
 assertEq(desc.enumerable, true);
-assertEq(desc.configurable, true);
+assertEq(desc.configurable, false);
 assertEq(desc.value(), undefined);
 
 wasmValidateText('(module (func) (func) (export "a" 0))');
 wasmValidateText('(module (func) (func) (export "a" 1))');
 wasmValidateText('(module (func $a) (func $b) (export "a" $a) (export "b" $b))');
 wasmValidateText('(module (func $a) (func $b) (export "a" $a) (export "b" $b))');
 
 wasmFailValidateText('(module (func) (export "a" 1))', /exported function index out of bounds/);
--- a/js/src/jit-test/tests/wasm/jsapi.js
+++ b/js/src/jit-test/tests/wasm/jsapi.js
@@ -196,18 +196,31 @@ assertEq(Object.getPrototypeOf(exporting
 
 // 'WebAssembly.Instance' 'exports' data property
 const instanceExportsDesc = Object.getOwnPropertyDescriptor(exportingInstance, 'exports');
 assertEq(typeof instanceExportsDesc.value, "object");
 assertEq(instanceExportsDesc.writable, true);
 assertEq(instanceExportsDesc.enumerable, true);
 assertEq(instanceExportsDesc.configurable, true);
 
+// 'WebAssembly.Instance' 'exports' object
+const exportsObj = exportingInstance.exports;
+assertEq(typeof exportsObj, "object");
+assertEq(Object.isExtensible(exportsObj), false);
+assertEq(Object.getPrototypeOf(exportsObj), null);
+assertEq(Object.keys(exportsObj).join(), "f");
+exportsObj.g = 1;
+assertEq(Object.keys(exportsObj).join(), "f");
+assertErrorMessage(() => Object.setPrototypeOf(exportsObj, {}), TypeError, /can't set prototype of this object/);
+assertEq(Object.getPrototypeOf(exportsObj), null);
+assertErrorMessage(() => Object.defineProperty(exportsObj, 'g', {}), TypeError, /Object is not extensible/);
+assertEq(Object.keys(exportsObj).join(), "f");
+
 // Exported WebAssembly functions
-const f = exportingInstance.exports.f;
+const f = exportsObj.f;
 assertEq(f instanceof Function, true);
 assertEq(f.length, 0);
 assertEq('name' in f, true);
 assertEq(Function.prototype.call.call(f), 42);
 assertErrorMessage(() => new f(), TypeError, /is not a constructor/);
 
 // 'WebAssembly.Memory' data property
 const memoryDesc = Object.getOwnPropertyDescriptor(WebAssembly, 'Memory');
--- a/js/src/jit-test/tests/wasm/table-gc.js
+++ b/js/src/jit-test/tests/wasm/table-gc.js
@@ -21,89 +21,86 @@ var i = wasmEvalText(`(module (table 2 a
 var e = i.exports;
 var t = e.tbl;
 var f = t.get(0);
 assertEq(f(), e.call(0));
 assertErrorMessage(() => e.call(1), RuntimeError, /indirect call to null/);
 assertErrorMessage(() => e.call(2), RuntimeError, /index out of bounds/);
 assertEq(finalizeCount(), 0);
 i.edge = makeFinalizeObserver();
-e.edge = makeFinalizeObserver();
 t.edge = makeFinalizeObserver();
 f.edge = makeFinalizeObserver();
 gc();
 assertEq(finalizeCount(), 0);
 f = null;
 gc();
 assertEq(finalizeCount(), 1);
 f = t.get(0);
 f.edge = makeFinalizeObserver();
 gc();
 assertEq(finalizeCount(), 1);
 i.exports = null;
 e = null;
 gc();
-assertEq(finalizeCount(), 2);
+assertEq(finalizeCount(), 1);
 t = null;
 gc();
-assertEq(finalizeCount(), 2);
+assertEq(finalizeCount(), 1);
 i = null;
 gc();
-assertEq(finalizeCount(), 2);
+assertEq(finalizeCount(), 1);
 assertEq(f(), 0);
 f = null;
 gc();
-assertEq(finalizeCount(), 5);
+assertEq(finalizeCount(), 4);
 
 // A table should hold the instance of any of its elements alive.
 resetFinalizeCount();
 var i = wasmEvalText(`(module (table 1 anyfunc) (export "tbl" table) (elem (i32.const 0) $f0) ${callee(0)} ${caller})`);
 var e = i.exports;
 var t = e.tbl;
 var f = t.get(0);
 i.edge = makeFinalizeObserver();
-e.edge = makeFinalizeObserver();
 t.edge = makeFinalizeObserver();
 f.edge = makeFinalizeObserver();
 gc();
 assertEq(finalizeCount(), 0);
 i.exports = null;
 e = null;
 gc();
-assertEq(finalizeCount(), 1);
+assertEq(finalizeCount(), 0);
 f = null;
 gc();
-assertEq(finalizeCount(), 2);
+assertEq(finalizeCount(), 1);
 i = null;
 gc();
-assertEq(finalizeCount(), 2);
+assertEq(finalizeCount(), 1);
 t = null;
 gc();
-assertEq(finalizeCount(), 4);
+assertEq(finalizeCount(), 3);
 
 // Null elements shouldn't keep anything alive.
 resetFinalizeCount();
 var i = wasmEvalText(`(module (table 2 anyfunc) (export "tbl" table) ${caller})`);
 var e = i.exports;
 var t = e.tbl;
 i.edge = makeFinalizeObserver();
-e.edge = makeFinalizeObserver();
 t.edge = makeFinalizeObserver();
 gc();
 assertEq(finalizeCount(), 0);
 i.exports = null;
 e = null;
 gc();
+assertEq(finalizeCount(), 0);
+i = null;
+gc();
 assertEq(finalizeCount(), 1);
-i = null;
+t = null;
 gc();
 assertEq(finalizeCount(), 2);
-t = null;
-gc();
-assertEq(finalizeCount(), 3);
 
 // Before initialization, a table is not bound to any instance.
 resetFinalizeCount();
 var i = wasmEvalText(`(module (func $f0 (result i32) (i32.const 0)) (export "f0" $f0))`);
 var t = new Table({initial:4, element:"anyfunc"});
 i.edge = makeFinalizeObserver();
 t.edge = makeFinalizeObserver();
 gc();
--- a/js/src/wasm/WasmModule.cpp
+++ b/js/src/wasm/WasmModule.cpp
@@ -916,17 +916,20 @@ CreateExportObject(JSContext* cx,
     if (metadata.isAsmJS() && exports.length() == 1 && strlen(exports[0].fieldName()) == 0) {
         RootedValue val(cx);
         if (!GetFunctionExport(cx, instanceObj, funcImports, exports[0], &val))
             return false;
         exportObj.set(&val.toObject());
         return true;
     }
 
-    exportObj.set(JS_NewPlainObject(cx));
+    if (metadata.isAsmJS())
+        exportObj.set(NewBuiltinClassInstance<PlainObject>(cx));
+    else
+        exportObj.set(NewObjectWithGivenProto<PlainObject>(cx, nullptr));
     if (!exportObj)
         return false;
 
     for (const Export& exp : exports) {
         JSAtom* atom = AtomizeUTF8Chars(cx, exp.fieldName(), strlen(exp.fieldName()));
         if (!atom)
             return false;
 
@@ -948,16 +951,21 @@ CreateExportObject(JSContext* cx,
                 return false;
             break;
         }
 
         if (!JS_DefinePropertyById(cx, exportObj, id, val, JSPROP_ENUMERATE))
             return false;
     }
 
+    if (!metadata.isAsmJS()) {
+        if (!JS_FreezeObject(cx, exportObj))
+            return false;
+    }
+
     return true;
 }
 
 bool
 Module::instantiate(JSContext* cx,
                     Handle<FunctionVector> funcImports,
                     HandleWasmTableObject tableImport,
                     HandleWasmMemoryObject memoryImport,