summaryrefslogtreecommitdiffstats
path: root/dom/promise/tests/test_webassembly_compile.html
diff options
context:
space:
mode:
Diffstat (limited to 'dom/promise/tests/test_webassembly_compile.html')
-rw-r--r--dom/promise/tests/test_webassembly_compile.html446
1 files changed, 446 insertions, 0 deletions
diff --git a/dom/promise/tests/test_webassembly_compile.html b/dom/promise/tests/test_webassembly_compile.html
new file mode 100644
index 0000000000..351f0f4ae4
--- /dev/null
+++ b/dom/promise/tests/test_webassembly_compile.html
@@ -0,0 +1,446 @@
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+ <title>WebAssembly.compile Test</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script>
+const testingFunctions = SpecialPowers.Cu.getJSTestingFunctions();
+const wasmIsSupported = SpecialPowers.unwrap(testingFunctions.wasmIsSupported);
+const wasmHasTier2CompilationCompleted = SpecialPowers.unwrap(testingFunctions.wasmHasTier2CompilationCompleted);
+const wasmLoadedFromCache = SpecialPowers.unwrap(testingFunctions.wasmLoadedFromCache);
+const isCachingEnabled = SpecialPowers.getBoolPref("javascript.options.wasm_caching");
+
+// The test_webassembly_compile_sample.wasm is a medium-sized module with 100
+// functions that call each other recursively, returning a computed sum.
+// Any other non-trivial module could be generated and used.
+var sampleCode;
+const sampleURL = "test_webassembly_compile_sample.wasm";
+const sampleFileSize = 16053;
+const sampleURLWithRandomQuery = () => sampleURL + "?id=" + String(Math.ceil(Math.random()*100000));
+const sampleExportName = "run";
+const sampleResult = 1275;
+
+function checkSampleModule(m) {
+ ok(m instanceof WebAssembly.Module, "got a module");
+ var i = new WebAssembly.Instance(m);
+ ok(i instanceof WebAssembly.Instance, "got an instance");
+ ok(i.exports[sampleExportName]() === sampleResult, "got result");
+}
+
+function checkSampleInstance(i) {
+ ok(i instanceof WebAssembly.Instance, "got a module");
+ ok(i.exports[sampleExportName]() === sampleResult, "got result");
+}
+
+function fetchSampleModuleCode() {
+ fetch(sampleURL)
+ .then(response => response.arrayBuffer())
+ .then(buffer => { sampleCode = buffer; runTest(); })
+ .catch(err => ok(false, String(err)));
+}
+
+function propertiesExist() {
+ if (!wasmIsSupported()) {
+ ok(!this.WebAssembly, "If the device doesn't support, there will be no WebAssembly object");
+ SimpleTest.finish();
+ return;
+ }
+
+ ok(WebAssembly, "WebAssembly object should exist");
+ ok(WebAssembly.compile, "WebAssembly.compile function should exist");
+ runTest();
+}
+
+function compileFail() {
+ WebAssembly.compile().then(
+ () => { ok(false, "should have failed"); runTest(); }
+ ).catch(
+ err => { ok(err instanceof TypeError, "empty compile failed"); runTest(); }
+ );
+}
+
+function compileSuccess() {
+ WebAssembly.compile(sampleCode).then(
+ m => { checkSampleModule(m); runTest(); }
+ ).catch(
+ err => { ok(false, String(err)); runTest(); }
+ );
+}
+
+function compileManySuccess() {
+ const N = 100;
+
+ var arr = [];
+ for (var i = 0; i < N; i++)
+ arr.push(WebAssembly.compile(sampleCode));
+
+ SpecialPowers.gc();
+
+ Promise.all(arr).then(ms => {
+ ok(ms.length === N, "got the right number");
+ for (var j = 0; j < N; j++)
+ checkSampleModule(ms[j]);
+ runTest();
+ }).catch(
+ err => { ok(false, String(err)); runTest(); }
+ );
+}
+
+function terminateCompileInWorker() {
+ var w = new Worker(`data:text/plain,
+ var sampleCode;
+ function spawnWork() {
+ const N = 100;
+ var arr = [];
+ for (var i = 0; i < N; i++)
+ arr.push(WebAssembly.compile(sampleCode));
+ Promise.all(arr).then(spawnWork);
+ }
+ onmessage = e => {
+ sampleCode = e.data;
+ spawnWork();
+ postMessage("ok");
+ }
+ `);
+ w.postMessage(sampleCode);
+ w.onmessage = e => {
+ ok(e.data === "ok", "worker finished first step");
+ w.terminate();
+ runTest();
+ };
+}
+
+function instantiateFail() {
+ WebAssembly.instantiate().then(
+ () => { ok(false, "should have failed"); runTest(); }
+ ).catch(
+ err => { ok(err instanceof TypeError, "empty compile failed"); runTest(); }
+ );
+}
+
+function instantiateSuccess() {
+ WebAssembly.instantiate(sampleCode).then(
+ r => { checkSampleModule(r.module); checkSampleInstance(r.instance); runTest(); }
+ ).catch(
+ err => { ok(false, String(err)); runTest(); }
+ );
+}
+
+function chainSuccess() {
+ WebAssembly.compile(sampleCode).then(
+ m => WebAssembly.instantiate(m)
+ ).then(
+ i => { checkSampleInstance(i); runTest(); }
+ ).catch(
+ err => { ok(false, String(err)); runTest(); }
+ );
+}
+
+function compileStreamingNonResponse() {
+ WebAssembly.compileStreaming({})
+ .then(() => { ok(false); })
+ .catch(err => { ok(err instanceof TypeError, "rejected {}"); runTest(); });
+}
+
+function compileStreamingNoMime() {
+ WebAssembly.compileStreaming(new Response(new ArrayBuffer()))
+ .then(() => { ok(false); })
+ .catch(err => { ok(err instanceof TypeError, "rejected no MIME type"); runTest(); });
+}
+
+function compileStreamingBadMime() {
+ var badMimes = [
+ "",
+ "application/js",
+ "application/js;application/wasm",
+ "application/wasm;application/js",
+ "application/wasm;",
+ "application/wasm1",
+ ];
+ var promises = [];
+ for (let mimeType of badMimes) {
+ var init = { headers: { "Content-Type": mimeType } };
+ promises.push(
+ WebAssembly.compileStreaming(new Response(sampleCode, init))
+ .then(() => Promise.reject(), err => {
+ is(err.message,
+ `WebAssembly: Response has unsupported MIME type '${mimeType}' expected 'application/wasm'`,
+ "correct MIME type error message");
+ return Promise.resolve();
+ })
+ );
+ }
+ Promise.all(promises)
+ .then(() => { ok(true, "all bad MIME types rejected"); runTest(); });
+}
+
+function compileStreamingGoodMime() {
+ var badMimes = [
+ "application/wasm",
+ " application/wasm ",
+ "application/wasm ",
+ ];
+ var promises = [];
+ for (let mimeType of badMimes) {
+ var init = { headers: { "Content-Type": mimeType } };
+ promises.push(
+ WebAssembly.compileStreaming(new Response(sampleCode, init))
+ );
+ }
+ Promise.all(promises)
+ .then(() => { ok(true, "all good MIME types accepted"); runTest(); });
+}
+
+function compileStreamingDoubleUseFail() {
+ fetch(sampleURL)
+ .then(response => {
+ WebAssembly.compileStreaming(response)
+ .then(m => {
+ checkSampleModule(m);
+ return WebAssembly.compileStreaming(response);
+ })
+ .then(
+ () => ok(false, "should have failed on second use"),
+ err => { ok(true, "failed on second use"); runTest(); }
+ );
+ });
+}
+
+function compileStreamingNullBody() {
+ var init = { headers: { "Content-Type": "application/wasm" } };
+ WebAssembly.compileStreaming(new Response(undefined, init))
+ .then(() => { ok(false); })
+ .catch(err => { ok(err instanceof WebAssembly.CompileError, "null body"); runTest(); });
+}
+
+function compileStreamingFetch() {
+ WebAssembly.compileStreaming(fetch(sampleURL))
+ .then(m => { checkSampleModule(m); runTest(); })
+ .catch(err => { ok(false, String(err)); });
+}
+
+function compileCachedBasic() {
+ const url = sampleURLWithRandomQuery();
+ WebAssembly.compileStreaming(fetch(url))
+ .then(module => {
+ checkSampleModule(module);
+ ok(!wasmLoadedFromCache(module), "not cached yet");
+ while(!wasmHasTier2CompilationCompleted(module));
+ return WebAssembly.compileStreaming(fetch(url));
+ })
+ .then(module => {
+ checkSampleModule(module);
+ ok(wasmLoadedFromCache(module), "loaded from cache");
+ })
+ .then(() => runTest())
+ .catch(err => { ok(false, String(err)) });
+}
+
+function compileCachedCompressed() {
+ const url = sampleURLWithRandomQuery();
+
+ // It is a rough estimate that compilation code is about
+ // 2-4 times of the wasm file size. After it compression
+ // it will be less (about 60% ?)
+ const EstimatedCompilationArtifactSize = 2 * sampleFileSize;
+ const EstimatedCompressedArtifactSize = 0.6 * EstimatedCompilationArtifactSize;
+
+ // Set limit on cache entry so it will fail if it is not
+ // compressed.
+ const cleanup = () => {
+ SpecialPowers.clearUserPref("browser.cache.disk.max_entry_size")
+ };
+ Promise.resolve(SpecialPowers.setIntPref("browser.cache.disk.max_entry_size",
+ Math.round(EstimatedCompressedArtifactSize / 1024) /* kb */))
+ .then(() => WebAssembly.compileStreaming(fetch(url)))
+ .then(module => {
+ checkSampleModule(module);
+ ok(!wasmLoadedFromCache(module), "not cached yet");
+ while(!wasmHasTier2CompilationCompleted(module));
+ return WebAssembly.compileStreaming(fetch(url));
+ })
+ .then(module => {
+ checkSampleModule(module);
+ ok(wasmLoadedFromCache(module), "loaded from cache");
+ })
+ .then(() => { cleanup(); runTest() })
+ .catch(err => { cleanup(); ok(false, String(err)) });
+}
+
+function compileCachedTooLargeForCache() {
+ const url = sampleURLWithRandomQuery();
+ // Set unreasonable limit, caching will fail.
+ // Bug 1719508 can change name of pref, this and
+ // compileCachedCompressed tests will become invalid.
+ const cleanup = () => {
+ SpecialPowers.clearUserPref("browser.cache.disk.max_entry_size")
+ };
+ Promise.resolve(SpecialPowers.setIntPref("browser.cache.disk.max_entry_size", 1 /* kb */))
+ .then(() => WebAssembly.compileStreaming(fetch(url)))
+ .then(module => {
+ console.log(module)
+ checkSampleModule(module);
+ ok(!wasmLoadedFromCache(module), "not cached yet");
+ while(!wasmHasTier2CompilationCompleted(module));
+ return WebAssembly.compileStreaming(fetch(url));
+ })
+ .then(module => {
+ checkSampleModule(module);
+ ok(!wasmLoadedFromCache(module), "not cached (size limit)");
+ })
+ .then(() => { cleanup(); runTest() })
+ .catch(err => { cleanup(); ok(false, String(err)) });
+}
+
+const Original = "original";
+const Clone = "clone";
+
+function compileCachedBothClonesHitCache(which) {
+ const url = sampleURLWithRandomQuery();
+ WebAssembly.compileStreaming(fetch(url))
+ .then(module => {
+ checkSampleModule(module);
+ ok(!wasmLoadedFromCache(module), "not cached yet");
+ while(!wasmHasTier2CompilationCompleted(module));
+ return fetch(url);
+ })
+ .then(original => {
+ let clone = original.clone();
+ if (which === Clone) [clone, original] = [original, clone];
+ return Promise.all([
+ WebAssembly.compileStreaming(original),
+ WebAssembly.compileStreaming(clone)
+ ]);
+ })
+ .then(([m1, m2]) => {
+ checkSampleModule(m1);
+ ok(wasmLoadedFromCache(m1), "clone loaded from cache");
+ checkSampleModule(m2);
+ ok(wasmLoadedFromCache(m2), "original loaded from cache");
+ })
+ .then(() => runTest())
+ .catch(err => { ok(false, String(err)) });
+}
+
+function compileCachedCacheThroughClone(which) {
+ const url = sampleURLWithRandomQuery();
+ fetch(url)
+ .then(original => {
+ ok(true, "fun time");
+ let clone = original.clone();
+ if (which === Clone) [clone, original] = [original, clone];
+ return Promise.all([
+ WebAssembly.compileStreaming(original),
+ clone.arrayBuffer()
+ ]);
+ })
+ .then(([module, buffer]) => {
+ ok(!wasmLoadedFromCache(module), "not cached yet");
+ ok(buffer instanceof ArrayBuffer);
+ while(!wasmHasTier2CompilationCompleted(module));
+ return WebAssembly.compileStreaming(fetch(url));
+ })
+ .then(m => {
+ ok(wasmLoadedFromCache(m), "cache hit of " + which);
+ })
+ .then(() => runTest())
+ .catch(err => { ok(false, String(err)) });
+}
+
+function instantiateStreamingFetch() {
+ WebAssembly.instantiateStreaming(fetch(sampleURL))
+ .then(({module, instance}) => { checkSampleModule(module); checkSampleInstance(instance); runTest(); })
+ .catch(err => { ok(false, String(err)); });
+}
+
+function compileManyStreamingFetch() {
+ const N = 20;
+
+ var arr = [];
+ for (var i = 0; i < N; i++)
+ arr.push(WebAssembly.compileStreaming(fetch(sampleURL)));
+
+ SpecialPowers.gc();
+
+ Promise.all(arr).then(ms => {
+ ok(ms.length === N, "got the right number");
+ for (var j = 0; j < N; j++)
+ checkSampleModule(ms[j]);
+ runTest();
+ }).catch(
+ err => { ok(false, String(err)); runTest(); }
+ );
+}
+
+function runWorkerTests() {
+ var w = new Worker("test_webassembly_compile_worker.js");
+ w.postMessage(sampleCode);
+ w.onmessage = e => {
+ ok(e.data === "ok", "worker test: " + e.data);
+ runTest();
+ };
+}
+
+function terminateCompileStreamingInWorker() {
+ var w = new Worker("test_webassembly_compile_worker_terminate.js");
+ w.onmessage = e => {
+ ok(e.data === "ok", "worker streaming terminate test: " + e.data);
+ w.terminate();
+ runTest();
+ };
+}
+
+var tests = [ propertiesExist,
+ compileFail,
+ compileSuccess,
+ compileManySuccess,
+ terminateCompileInWorker,
+ instantiateFail,
+ instantiateSuccess,
+ chainSuccess,
+ compileStreamingNonResponse,
+ compileStreamingNoMime,
+ compileStreamingBadMime,
+ compileStreamingGoodMime,
+ compileStreamingDoubleUseFail,
+ compileStreamingNullBody,
+ compileStreamingFetch,
+ ...(isCachingEnabled ? [
+ compileCachedBasic,
+ compileCachedCompressed,
+ compileCachedTooLargeForCache,
+ compileCachedBothClonesHitCache.bind(Original),
+ compileCachedBothClonesHitCache.bind(Clone),
+ compileCachedCacheThroughClone.bind(Original),
+ compileCachedCacheThroughClone.bind(Clone),
+ ]: []),
+ instantiateStreamingFetch,
+ compileManyStreamingFetch,
+ runWorkerTests,
+ terminateCompileStreamingInWorker,
+ ];
+
+// This initialization must always run
+tests.unshift(fetchSampleModuleCode);
+
+function runTest() {
+ if (!tests.length) {
+ SimpleTest.finish();
+ return;
+ }
+
+ var test = tests.shift();
+ test();
+}
+
+SimpleTest.waitForExplicitFinish();
+runTest();
+</script>
+</body>
+</html>