diff --git a/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java b/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java index ed9ca0bd9..ce728edeb 100644 --- a/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java +++ b/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java @@ -15,10 +15,13 @@ */ package org.teavm.backend.wasm; +import java.io.BufferedReader; import java.io.IOException; +import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Writer; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -419,6 +422,8 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost { if (cEmitted) { emitC(module, buildTarget, getBaseName(outputName) + ".wasm.c"); } + + emitRuntime(buildTarget, getBaseName(outputName) + ".wasm-runtime.js"); } private class IntrinsicFactoryContext implements WasmIntrinsicFactoryContext { @@ -469,6 +474,22 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost { } } + private void emitRuntime(BuildTarget buildTarget, String outputName) throws IOException { + ClassLoader loader = controller.getClassLoader(); + try (BufferedReader reader = new BufferedReader(new InputStreamReader( + loader.getResourceAsStream("org/teavm/backend/wasm/wasm-runtime.js"), StandardCharsets.UTF_8)); + Writer writer = new OutputStreamWriter(buildTarget.createResource(outputName), + StandardCharsets.UTF_8)) { + while (true) { + String line = reader.readLine(); + if (line == null) { + break; + } + writer.append(line).append('\n'); + } + } + } + private void generateMethods(ListableClassHolderSource classes, WasmGenerationContext context, WasmGenerator generator, WasmClassGenerator classGenerator, BinaryWriter binaryWriter, WasmModule module) { List methods = new ArrayList<>(); diff --git a/samples/benchmark/src/main/webapp/teavm-wasm.html b/samples/benchmark/src/main/webapp/teavm-wasm.html index e516d9e00..9f56c46ec 100644 --- a/samples/benchmark/src/main/webapp/teavm-wasm.html +++ b/samples/benchmark/src/main/webapp/teavm-wasm.html @@ -18,6 +18,7 @@ TeaVM WebAssembly jbox2d benchmark + @@ -39,7 +40,7 @@ var canvas = document.getElementById("benchmark-canvas"); document.body.onload = function() { var benchmark = new Benchmark(canvas.getContext("2d")); - benchmark.runAll(); + benchmark.load(); } diff --git a/samples/benchmark/src/main/webapp/teavm-wasm.js b/samples/benchmark/src/main/webapp/teavm-wasm.js index 0c0a64dbc..039fce4b7 100644 --- a/samples/benchmark/src/main/webapp/teavm-wasm.js +++ b/samples/benchmark/src/main/webapp/teavm-wasm.js @@ -18,131 +18,86 @@ var Benchmark = function() { function Benchmark(canvas) { this.canvas = canvas; this.instance = null; - this.line = ""; this.resultTableBody = document.getElementById("result-table-body"); } - Benchmark.prototype.runAll = function() { - load(this, function() { this.instance.exports.main(); }.bind(this)); + Benchmark.prototype.load = function() { + TeaVM.wasm.run("teavm-wasm/classes.wasm", { + installImports: installImports.bind(this), + callback: function(result) { + this.instance = result.instance; + }.bind(this) + }); }; - function tick(benchmark) { - var exports = benchmark.instance.exports; + function installImports(o) { + var canvas = this.canvas; + o.benchmark = { + performanceTime: function() { return window.performance.now() || 0; }, + reportPerformance: function(second, timeSpentComputing) { + var row = document.createElement("tr"); + this.resultTableBody.appendChild(row); + var secondCell = document.createElement("td"); + row.appendChild(secondCell); + secondCell.appendChild(document.createTextNode(second.toString())); + var timeCell = document.createElement("td"); + row.appendChild(timeCell); + timeCell.appendChild(document.createTextNode(timeSpentComputing.toString())); + }.bind(this), + repeatAfter: function(time) { + setTimeout(tick.bind(this), time); + }.bind(this), + setupCanvas: function() { + canvas.fillStyle = "white"; + canvas.strokeStyle = "grey"; + canvas.fillRect(0, 0, 600, 600); + canvas.translate(0, 600); + canvas.scale(1, -1); + canvas.scale(100, 100); + canvas.lineWidth = 0.01; + } + }; + o.canvas = { + save: function() { + canvas.save(); + }, + restore: function() { + canvas.restore(); + }, + beginPath: function() { + canvas.beginPath(); + }, + closePath: function() { + canvas.closePath(); + }, + stroke: function() { + canvas.stroke(); + }, + moveTo: function(x, y) { + canvas.moveTo(x, y); + }, + lineTo: function(x, y) { + canvas.lineTo(x, y); + }, + translate: function(x, y) { + canvas.translate(x, y); + }, + rotate: function(angle) { + canvas.rotate(angle); + }, + arc: function(cx, cy, radius, startAngle, endAngle, counterClockwise) { + canvas.arc(cx, cy, radius, startAngle, endAngle, counterClockwise); + } + }; + } + + function tick() { + var exports = this.instance.exports; exports.tick(); - var exception = exports.sys$catchException(); + var exception = exports.sys_catchException(); if (exception !== 0) { console.log("Exception: " + exception); } } - function currentTimeMillis() { - return new Date().getTime(); - } - - function putchar(benchmark, charCode) { - if (charCode == 10) { - console.log(benchmark.line); - benchmark.line = ""; - } else { - benchmark.line += String.fromCharCode(charCode); - } - } - - function load(benchmark, callback) { - var xhr = new XMLHttpRequest(); - xhr.responseType = "arraybuffer"; - xhr.open("GET", "teavm-wasm/classes.wasm"); - xhr.onload = function() { - var response = xhr.response; - if (!response) { - return; - } - var canvas = benchmark.canvas; - var importObj = { - runtime: { - currentTimeMillis: currentTimeMillis, - isNaN: isNaN, - isFinite: isFinite, - getNaN: function() { return NaN; }, - putchar: function(code) { putchar(benchmark, code); } - }, - benchmark: { - performanceTime: function() { return window.performance.now() || 0; }, - reportPerformance: function(second, timeSpentComputing) { - var row = document.createElement("tr"); - benchmark.resultTableBody.appendChild(row); - var secondCell = document.createElement("td"); - row.appendChild(secondCell); - secondCell.appendChild(document.createTextNode(second.toString())); - var timeCell = document.createElement("td"); - row.appendChild(timeCell); - timeCell.appendChild(document.createTextNode(timeSpentComputing.toString())); - }, - repeatAfter: function(time) { - setTimeout(tick.bind(null, benchmark), time); - }, - setupCanvas: function() { - canvas.fillStyle = "white"; - canvas.strokeStyle = "grey"; - canvas.fillRect(0, 0, 600, 600); - canvas.translate(0, 600); - canvas.scale(1, -1); - canvas.scale(100, 100); - canvas.lineWidth = 0.01; - } - }, - canvas: { - save: function() { - canvas.save(); - }, - restore: function() { - canvas.restore(); - }, - beginPath: function() { - canvas.beginPath(); - }, - closePath: function() { - canvas.closePath(); - }, - stroke: function() { - canvas.stroke(); - }, - moveTo: function(x, y) { - canvas.moveTo(x, y); - }, - lineTo: function(x, y) { - canvas.lineTo(x, y); - }, - translate: function(x, y) { - canvas.translate(x, y); - }, - rotate: function(angle) { - canvas.rotate(angle); - }, - arc: function(cx, cy, radius, startAngle, endAngle, counterClockwise) { - canvas.arc(cx, cy, radius, startAngle, endAngle, counterClockwise); - } - }, - math: Math, - debug: { - traceMemoryAccess: function(callSite, address) { - if (address >= 63 * 65536) { - console.log("Memory access #" + callSite + " at " + address); - } - return address; - } - } - }; - - WebAssembly.instantiate(response, importObj).then(function(resultObject) { - benchmark.instance = resultObject.instance; - console.log("Initialized") - callback(); - }).catch(function(error) { - console.log("Error : " + error); - }); - }; - xhr.send(); - } - return Benchmark; }(); \ No newline at end of file