mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-23 00:24:11 -08:00
wasm: trying to implement coroutines
This commit is contained in:
parent
c4c1408160
commit
bd53c1a5a2
|
@ -27,9 +27,11 @@ import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import org.teavm.ast.InvocationExpr;
|
||||||
import org.teavm.ast.decompilation.Decompiler;
|
import org.teavm.ast.decompilation.Decompiler;
|
||||||
import org.teavm.backend.lowlevel.analyze.LowLevelInliningFilterFactory;
|
import org.teavm.backend.lowlevel.analyze.LowLevelInliningFilterFactory;
|
||||||
import org.teavm.backend.lowlevel.dependency.StringsDependencyListener;
|
import org.teavm.backend.lowlevel.dependency.StringsDependencyListener;
|
||||||
|
@ -69,8 +71,10 @@ import org.teavm.backend.wasm.intrinsics.RuntimeClassIntrinsic;
|
||||||
import org.teavm.backend.wasm.intrinsics.ShadowStackIntrinsic;
|
import org.teavm.backend.wasm.intrinsics.ShadowStackIntrinsic;
|
||||||
import org.teavm.backend.wasm.intrinsics.StructureIntrinsic;
|
import org.teavm.backend.wasm.intrinsics.StructureIntrinsic;
|
||||||
import org.teavm.backend.wasm.intrinsics.WasmHeapIntrinsic;
|
import org.teavm.backend.wasm.intrinsics.WasmHeapIntrinsic;
|
||||||
|
import org.teavm.backend.wasm.intrinsics.WasmIntrinsic;
|
||||||
import org.teavm.backend.wasm.intrinsics.WasmIntrinsicFactory;
|
import org.teavm.backend.wasm.intrinsics.WasmIntrinsicFactory;
|
||||||
import org.teavm.backend.wasm.intrinsics.WasmIntrinsicFactoryContext;
|
import org.teavm.backend.wasm.intrinsics.WasmIntrinsicFactoryContext;
|
||||||
|
import org.teavm.backend.wasm.intrinsics.WasmIntrinsicManager;
|
||||||
import org.teavm.backend.wasm.intrinsics.WasmRuntimeIntrinsic;
|
import org.teavm.backend.wasm.intrinsics.WasmRuntimeIntrinsic;
|
||||||
import org.teavm.backend.wasm.model.WasmFunction;
|
import org.teavm.backend.wasm.model.WasmFunction;
|
||||||
import org.teavm.backend.wasm.model.WasmLocal;
|
import org.teavm.backend.wasm.model.WasmLocal;
|
||||||
|
@ -92,6 +96,7 @@ import org.teavm.backend.wasm.model.expression.WasmLoadInt32;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmReturn;
|
import org.teavm.backend.wasm.model.expression.WasmReturn;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmSetLocal;
|
import org.teavm.backend.wasm.model.expression.WasmSetLocal;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmStoreInt32;
|
import org.teavm.backend.wasm.model.expression.WasmStoreInt32;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmUnreachable;
|
||||||
import org.teavm.backend.wasm.optimization.UnusedFunctionElimination;
|
import org.teavm.backend.wasm.optimization.UnusedFunctionElimination;
|
||||||
import org.teavm.backend.wasm.render.WasmBinaryRenderer;
|
import org.teavm.backend.wasm.render.WasmBinaryRenderer;
|
||||||
import org.teavm.backend.wasm.render.WasmBinaryVersion;
|
import org.teavm.backend.wasm.render.WasmBinaryVersion;
|
||||||
|
@ -150,7 +155,9 @@ import org.teavm.model.transformation.BoundCheckInsertion;
|
||||||
import org.teavm.model.transformation.ClassPatch;
|
import org.teavm.model.transformation.ClassPatch;
|
||||||
import org.teavm.model.transformation.NullCheckInsertion;
|
import org.teavm.model.transformation.NullCheckInsertion;
|
||||||
import org.teavm.runtime.Allocator;
|
import org.teavm.runtime.Allocator;
|
||||||
|
import org.teavm.runtime.EventQueue;
|
||||||
import org.teavm.runtime.ExceptionHandling;
|
import org.teavm.runtime.ExceptionHandling;
|
||||||
|
import org.teavm.runtime.Fiber;
|
||||||
import org.teavm.runtime.RuntimeArray;
|
import org.teavm.runtime.RuntimeArray;
|
||||||
import org.teavm.runtime.RuntimeClass;
|
import org.teavm.runtime.RuntimeClass;
|
||||||
import org.teavm.runtime.RuntimeObject;
|
import org.teavm.runtime.RuntimeObject;
|
||||||
|
@ -354,6 +361,22 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dependencyAnalyzer.linkMethod(new MethodReference(Fiber.class, "isResuming", boolean.class)).use();
|
||||||
|
dependencyAnalyzer.linkMethod(new MethodReference(Fiber.class, "isSuspending", boolean.class)).use();
|
||||||
|
dependencyAnalyzer.linkMethod(new MethodReference(Fiber.class, "current", Fiber.class)).use();
|
||||||
|
dependencyAnalyzer.linkMethod(new MethodReference(Fiber.class, "startMain", String[].class, void.class)).use();
|
||||||
|
dependencyAnalyzer.linkMethod(new MethodReference(EventQueue.class, "processSingle", void.class)).use();
|
||||||
|
dependencyAnalyzer.linkMethod(new MethodReference(EventQueue.class, "isStopped", boolean.class)).use();
|
||||||
|
dependencyAnalyzer.linkMethod(new MethodReference(Thread.class, "setCurrentThread", Thread.class,
|
||||||
|
void.class)).use();
|
||||||
|
|
||||||
|
ClassReader fiberClass = dependencyAnalyzer.getClassSource().get(Fiber.class.getName());
|
||||||
|
for (MethodReader method : fiberClass.getMethods()) {
|
||||||
|
if (method.getName().startsWith("pop") || method.getName().equals("push")) {
|
||||||
|
dependencyAnalyzer.linkMethod(method.getReference()).use();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dependencyAnalyzer.addDependencyListener(new StringsDependencyListener());
|
dependencyAnalyzer.addDependencyListener(new StringsDependencyListener());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -417,6 +440,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
||||||
context.addIntrinsic(new MemoryTraceIntrinsic());
|
context.addIntrinsic(new MemoryTraceIntrinsic());
|
||||||
}
|
}
|
||||||
context.addIntrinsic(new WasmHeapIntrinsic());
|
context.addIntrinsic(new WasmHeapIntrinsic());
|
||||||
|
context.addIntrinsic(new FiberIntrinsic());
|
||||||
|
|
||||||
IntrinsicFactoryContext intrinsicFactoryContext = new IntrinsicFactoryContext();
|
IntrinsicFactoryContext intrinsicFactoryContext = new IntrinsicFactoryContext();
|
||||||
for (WasmIntrinsicFactory additionalIntrinsicFactory : additionalIntrinsics) {
|
for (WasmIntrinsicFactory additionalIntrinsicFactory : additionalIntrinsics) {
|
||||||
|
@ -459,15 +483,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
||||||
generateInitFunction(classes, initFunction, names, binaryWriter.getAddress());
|
generateInitFunction(classes, initFunction, names, binaryWriter.getAddress());
|
||||||
module.add(initFunction);
|
module.add(initFunction);
|
||||||
module.setStartFunction(initFunction);
|
module.setStartFunction(initFunction);
|
||||||
|
module.add(createStartFunction(names));
|
||||||
|
|
||||||
for (TeaVMEntryPoint entryPoint : controller.getEntryPoints().values()) {
|
|
||||||
String mangledName = names.forMethod(entryPoint.getMethod());
|
|
||||||
WasmFunction function = module.getFunctions().get(mangledName);
|
|
||||||
if (function != null) {
|
|
||||||
function.setExportName(entryPoint.getPublicName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (String functionName : classGenerator.getFunctionTable()) {
|
for (String functionName : classGenerator.getFunctionTable()) {
|
||||||
WasmFunction function = module.getFunctions().get(functionName);
|
WasmFunction function = module.getFunctions().get(functionName);
|
||||||
|
@ -503,6 +519,22 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
||||||
emitRuntime(buildTarget, getBaseName(outputName) + ".wasm-runtime.js");
|
emitRuntime(buildTarget, getBaseName(outputName) + ".wasm-runtime.js");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private WasmFunction createStartFunction(NameProvider names) {
|
||||||
|
WasmFunction function = new WasmFunction("teavm_start");
|
||||||
|
function.setExportName("start");
|
||||||
|
function.getParameters().add(WasmType.INT32);
|
||||||
|
|
||||||
|
WasmLocal local = new WasmLocal(WasmType.INT32, "args");
|
||||||
|
function.add(local);
|
||||||
|
|
||||||
|
WasmCall call = new WasmCall(names.forMethod(new MethodReference(Fiber.class, "startMain", String[].class,
|
||||||
|
void.class)));
|
||||||
|
call.getArguments().add(new WasmGetLocal(local));
|
||||||
|
function.getBody().add(call);
|
||||||
|
|
||||||
|
return function;
|
||||||
|
}
|
||||||
|
|
||||||
private class IntrinsicFactoryContext implements WasmIntrinsicFactoryContext {
|
private class IntrinsicFactoryContext implements WasmIntrinsicFactoryContext {
|
||||||
@Override
|
@Override
|
||||||
public ClassReaderSource getClassSource() {
|
public ClassReaderSource getClassSource() {
|
||||||
|
@ -967,4 +999,53 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
||||||
return classSource;
|
return classSource;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class FiberIntrinsic implements WasmIntrinsic {
|
||||||
|
@Override
|
||||||
|
public boolean isApplicable(MethodReference methodReference) {
|
||||||
|
if (!methodReference.getClassName().equals(Fiber.class.getName())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
switch (methodReference.getName()) {
|
||||||
|
case "runMain":
|
||||||
|
case "setCurrentThread":
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WasmExpression apply(InvocationExpr invocation, WasmIntrinsicManager manager) {
|
||||||
|
switch (invocation.getMethod().getName()) {
|
||||||
|
case "runMain": {
|
||||||
|
Iterator<? extends TeaVMEntryPoint> entryPointIter = controller.getEntryPoints().values()
|
||||||
|
.iterator();
|
||||||
|
if (entryPointIter.hasNext()) {
|
||||||
|
TeaVMEntryPoint entryPoint = entryPointIter.next();
|
||||||
|
String name = manager.getNames().forMethod(entryPoint.getMethod());
|
||||||
|
WasmCall call = new WasmCall(name);
|
||||||
|
call.getArguments().add(manager.generate(invocation.getArguments().get(0)));
|
||||||
|
call.setLocation(invocation.getLocation());
|
||||||
|
return call;
|
||||||
|
} else {
|
||||||
|
WasmUnreachable unreachable = new WasmUnreachable();
|
||||||
|
unreachable.setLocation(invocation.getLocation());
|
||||||
|
return unreachable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case "setCurrentThread": {
|
||||||
|
String name = manager.getNames().forMethod(new MethodReference(Thread.class,
|
||||||
|
"setCurrentThread", Thread.class, void.class));
|
||||||
|
WasmCall call = new WasmCall(name);
|
||||||
|
call.getArguments().add(manager.generate(invocation.getArguments().get(0)));
|
||||||
|
call.setLocation(invocation.getLocation());
|
||||||
|
return call;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -701,7 +701,7 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor {
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
if (expression.isImported()) {
|
if (expression.isImported()) {
|
||||||
sb.append(!function.getImportModule().isEmpty()
|
sb.append(function.getImportModule() != null && !function.getImportModule().isEmpty()
|
||||||
? function.getImportModule() + "_" + function.getImportName()
|
? function.getImportModule() + "_" + function.getImportName()
|
||||||
: function.getImportName());
|
: function.getImportName());
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -17,10 +17,9 @@ package org.teavm.runtime;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import org.teavm.backend.c.intrinsic.RuntimeInclude;
|
import org.teavm.backend.c.intrinsic.RuntimeInclude;
|
||||||
|
import org.teavm.interop.Export;
|
||||||
import org.teavm.interop.Import;
|
import org.teavm.interop.Import;
|
||||||
import org.teavm.interop.Platforms;
|
|
||||||
import org.teavm.interop.StaticInit;
|
import org.teavm.interop.StaticInit;
|
||||||
import org.teavm.interop.UnsupportedOn;
|
|
||||||
|
|
||||||
@StaticInit
|
@StaticInit
|
||||||
public final class EventQueue {
|
public final class EventQueue {
|
||||||
|
@ -72,6 +71,31 @@ public final class EventQueue {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Export(name = "teavm_processQueue")
|
||||||
|
public static long processSingle() {
|
||||||
|
if (size == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Node node = data[0];
|
||||||
|
long currentTime = System.currentTimeMillis();
|
||||||
|
if (node.time <= System.currentTimeMillis()) {
|
||||||
|
remove(0);
|
||||||
|
node.event.run();
|
||||||
|
if (size == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return Math.max(0, node.time - currentTime);
|
||||||
|
} else {
|
||||||
|
return node.time - currentTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Export(name = "teavm_stopped")
|
||||||
|
public static boolean isStopped() {
|
||||||
|
return finished;
|
||||||
|
}
|
||||||
|
|
||||||
public static void stop() {
|
public static void stop() {
|
||||||
finished = true;
|
finished = true;
|
||||||
}
|
}
|
||||||
|
@ -129,12 +153,10 @@ public final class EventQueue {
|
||||||
|
|
||||||
@Import(name = "teavm_waitFor")
|
@Import(name = "teavm_waitFor")
|
||||||
@RuntimeInclude("fiber.h")
|
@RuntimeInclude("fiber.h")
|
||||||
@UnsupportedOn(Platforms.WEBASSEMBLY)
|
|
||||||
private static native void waitFor(long time);
|
private static native void waitFor(long time);
|
||||||
|
|
||||||
@Import(name = "teavm_interrupt")
|
@Import(name = "teavm_interrupt", module = "teavm")
|
||||||
@RuntimeInclude("fiber.h")
|
@RuntimeInclude("fiber.h")
|
||||||
@UnsupportedOn(Platforms.WEBASSEMBLY)
|
|
||||||
private static native void interrupt();
|
private static native void interrupt();
|
||||||
|
|
||||||
private static void ensureCapacity(int capacity) {
|
private static void ensureCapacity(int capacity) {
|
||||||
|
|
|
@ -43,19 +43,46 @@ TeaVM.wasm = function() {
|
||||||
function getNativeOffset(instant) {
|
function getNativeOffset(instant) {
|
||||||
return new Date(instant).getTimezoneOffset();
|
return new Date(instant).getTimezoneOffset();
|
||||||
}
|
}
|
||||||
function logString(string) {
|
function logString(string, controller) {
|
||||||
var memory = new DataView(logString.memory.buffer);
|
let instance = controller.instance;
|
||||||
var arrayPtr = memory.getUint32(string + 8, true);
|
let memory = instance.exports.memory.buffer;
|
||||||
var length = memory.getUint32(arrayPtr + 8, true);
|
let arrayPtr = instance.exports.teavm_stringData(string);
|
||||||
for (var i = 0; i < length; ++i) {
|
let length = instance.exports.teavm_arrayLength(arrayPtr);
|
||||||
putwchar(memory.getUint16(i * 2 + arrayPtr + 12, true));
|
let arrayData = new DataView(memory, instance.exports.teavm_charArrayData(arrayPtr), length * 2);
|
||||||
|
for (let i = 0; i < length; ++i) {
|
||||||
|
putwchar(arrayData.memory.getUint16(i * 2, true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function logInt(i) {
|
function logInt(i) {
|
||||||
lineBuffer += i.toString();
|
lineBuffer += i.toString();
|
||||||
}
|
}
|
||||||
|
function interrupt(controller) {
|
||||||
|
if (controller.timer !== null) {
|
||||||
|
clearTimeout(controller.timer);
|
||||||
|
controller.timer = null;
|
||||||
|
}
|
||||||
|
controller.timer = setTimeout(() => process(controller), 0);
|
||||||
|
}
|
||||||
|
function process(controller) {
|
||||||
|
let result = controller.instance.exports.teavm_processQueue();
|
||||||
|
if (!controller.complete) {
|
||||||
|
if (controller.instance.exports.teavm_stopped()) {
|
||||||
|
controller.complete = true;
|
||||||
|
controller.resolve();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (result >= 0) {
|
||||||
|
controller.timer = setTimeout(() => process(controller), result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function importDefaults(obj) {
|
function defaults(obj) {
|
||||||
|
let controller = {};
|
||||||
|
controller.instance = null;
|
||||||
|
controller.timer = null;
|
||||||
|
controller.resolve = null;
|
||||||
|
controller.reject = null;
|
||||||
|
controller.complete = false;
|
||||||
obj.teavm = {
|
obj.teavm = {
|
||||||
currentTimeMillis: currentTimeMillis,
|
currentTimeMillis: currentTimeMillis,
|
||||||
nanoTime: function() { return performance.now(); },
|
nanoTime: function() { return performance.now(); },
|
||||||
|
@ -67,9 +94,10 @@ TeaVM.wasm = function() {
|
||||||
towlower: towlower,
|
towlower: towlower,
|
||||||
towupper: towupper,
|
towupper: towupper,
|
||||||
getNativeOffset: getNativeOffset,
|
getNativeOffset: getNativeOffset,
|
||||||
logString: logString,
|
logString: string => logString(string, controller),
|
||||||
logInt: logInt,
|
logInt: logInt,
|
||||||
logOutOfMemory: function() { console.log("Out of memory") }
|
logOutOfMemory: () => console.log("Out of memory"),
|
||||||
|
teavm_interrupt: () => interrupt(controller)
|
||||||
};
|
};
|
||||||
|
|
||||||
obj.teavmMath = Math;
|
obj.teavmMath = Math;
|
||||||
|
@ -91,6 +119,8 @@ TeaVM.wasm = function() {
|
||||||
gcCompleted: function() {},
|
gcCompleted: function() {},
|
||||||
init: function(maxHeap) {}
|
init: function(maxHeap) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
return controller;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createTeaVM(instance) {
|
function createTeaVM(instance) {
|
||||||
|
@ -109,35 +139,29 @@ TeaVM.wasm = function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
teavm.main = createMain(teavm, instance.exports.main);
|
teavm.main = createMain(teavm, instance.exports.main);
|
||||||
|
|
||||||
return teavm;
|
return teavm;
|
||||||
}
|
}
|
||||||
|
|
||||||
function wrapExport(fn, instance) {
|
function wrapExport(fn, instance) {
|
||||||
return function() {
|
return function() {
|
||||||
let result = fn.apply(this, arguments);
|
let result = fn.apply(this, arguments);
|
||||||
let ex = instance.exports.teavm_catchException();
|
let ex = catchException(instance);
|
||||||
if (ex !== 0) {
|
if (ex !== null) {
|
||||||
throw new JavaError("Uncaught exception occurred in java");
|
throw ex;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function catchException(instance) {
|
||||||
|
let ex = instance.exports.teavm_catchException();
|
||||||
|
if (ex !== 0) {
|
||||||
|
return new JavaError("Uncaught exception occurred in Java");
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
function load(path, options) {
|
function load(path, options) {
|
||||||
if (!options) {
|
|
||||||
options = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
let callback = typeof options.callback !== "undefined" ? options.callback : function() {};
|
|
||||||
let errorCallback = typeof options.errorCallback !== "undefined" ? options.errorCallback : function() {};
|
|
||||||
|
|
||||||
let importObj = {};
|
|
||||||
importDefaults(importObj);
|
|
||||||
if (typeof options.installImports !== "undefined") {
|
|
||||||
options.installImports(importObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
let xhr = new XMLHttpRequest();
|
let xhr = new XMLHttpRequest();
|
||||||
xhr.responseType = "arraybuffer";
|
xhr.responseType = "arraybuffer";
|
||||||
xhr.open("GET", path);
|
xhr.open("GET", path);
|
||||||
|
@ -146,45 +170,61 @@ TeaVM.wasm = function() {
|
||||||
xhr.onload = () => {
|
xhr.onload = () => {
|
||||||
let response = xhr.response;
|
let response = xhr.response;
|
||||||
if (!response) {
|
if (!response) {
|
||||||
|
reject("Error loading Wasm data")
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
WebAssembly.instantiate(response, importObj).then(resultObject => {
|
resolve(response);
|
||||||
importObj.teavm.logString.memory = resultObject.instance.exports.memory;
|
|
||||||
let teavm = createTeaVM(resultObject.instance);
|
|
||||||
teavm.main = createMain(teavm, wrapExport, resultObject.instance.exports.main);
|
|
||||||
resolve(teavm);
|
|
||||||
}).catch(error => {
|
|
||||||
reject(error);
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
xhr.send();
|
xhr.send();
|
||||||
|
}).then(data => create(data, options));
|
||||||
|
}
|
||||||
|
|
||||||
|
function create(data, options) {
|
||||||
|
if (!options) {
|
||||||
|
options = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const importObj = {};
|
||||||
|
const controller = defaults(importObj);
|
||||||
|
if (typeof options.installImports !== "undefined") {
|
||||||
|
options.installImports(importObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
return WebAssembly.instantiate(data, importObj).then(resultObject => {
|
||||||
|
controller.instance = resultObject.instance;
|
||||||
|
let teavm = createTeaVM(resultObject.instance);
|
||||||
|
teavm.main = createMain(teavm, controller);
|
||||||
|
return teavm;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function createMain(teavm, mainFunction) {
|
function createMain(teavm, controller) {
|
||||||
return function(args) {
|
return function(args) {
|
||||||
if (typeof args === "undefined") {
|
if (typeof args === "undefined") {
|
||||||
args = [];
|
args = [];
|
||||||
}
|
}
|
||||||
return new Promise(resolve => {
|
return new Promise((resolve, reject) => {
|
||||||
let javaArgs = teavm.allocateStringArray(mainArgs.length);
|
let javaArgs = teavm.allocateStringArray(args.length);
|
||||||
let javaArgsData = new Uint32Array(teavm.memory, teavm.objectArrayData(javaArgs), args.length);
|
let javaArgsData = new DataView(teavm.memory.buffer, teavm.objectArrayData(javaArgs), args.length * 4);
|
||||||
for (let i = 0; i < mainArgs.length; ++i) {
|
for (let i = 0; i < args.length; ++i) {
|
||||||
let arg = args[i];
|
let arg = args[i];
|
||||||
let javaArg = teavm.allocateString(arg.length);
|
let javaArg = teavm.allocateString(arg.length);
|
||||||
let javaArgAddress = teavm.objectArrayData(teavm.stringData(javaArg));
|
let javaArgAddress = teavm.objectArrayData(teavm.stringData(javaArg));
|
||||||
let javaArgData = new Uint16Array(teavm.memory, javaArgAddress, arg.length);
|
let javaArgData = new DataView(teavm.memory.buffer, javaArgAddress, arg.length * 2);
|
||||||
for (let j = 0; j < arg.length; ++j) {
|
for (let j = 0; j < arg.length; ++j) {
|
||||||
javaArgData[j] = arg.charCodeAt(j);
|
javaArgData.setUint16(j * 2, arg.charCodeAt(j), true);
|
||||||
}
|
}
|
||||||
javaArgsData[i] = javaArg;
|
javaArgsData.setInt32(i * 4, javaArg, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
resolve(wrapExport(mainFunction, teavm.instance)(javaArgs));
|
controller.resolve = resolve;
|
||||||
|
controller.reject = reject;
|
||||||
|
wrapExport(teavm.instance.exports.start, teavm.instance)(javaArgs);
|
||||||
|
process(controller);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return { JavaError, importDefaults, load, wrapExport, createTeaVM, createMain };
|
return { JavaError, load, create };
|
||||||
}();
|
}();
|
||||||
|
|
|
@ -500,7 +500,7 @@ public class TeaVMTestRunner extends Runner implements Filterable {
|
||||||
runs.add(createTestRun(configuration, testPath, child, RunKind.WASM, reference.toString(),
|
runs.add(createTestRun(configuration, testPath, child, RunKind.WASM, reference.toString(),
|
||||||
notifier, onSuccess));
|
notifier, onSuccess));
|
||||||
File htmlPath = getOutputFile(outputPathForMethod, "test-wasm", configuration.getSuffix(), false, ".html");
|
File htmlPath = getOutputFile(outputPathForMethod, "test-wasm", configuration.getSuffix(), false, ".html");
|
||||||
properties.put("SCRIPT", "../" + testPath.getName() + "-runtime.js");
|
properties.put("SCRIPT", "../" + testPath.getName());
|
||||||
properties.put("IDENTIFIER", reference.toString());
|
properties.put("IDENTIFIER", reference.toString());
|
||||||
try {
|
try {
|
||||||
resourceToFile("teavm-run-test-wasm.html", htmlPath, properties);
|
resourceToFile("teavm-run-test-wasm.html", htmlPath, properties);
|
||||||
|
@ -555,8 +555,7 @@ public class TeaVMTestRunner extends Runner implements Filterable {
|
||||||
if (run != null) {
|
if (run != null) {
|
||||||
runs.add(run);
|
runs.add(run);
|
||||||
|
|
||||||
File testPath = getOutputFile(outputPath, "test", configuration.getSuffix(), false,
|
File testPath = getOutputFile(outputPath, "test", configuration.getSuffix(), false, ".wasm");
|
||||||
".wasm-runtime.js");
|
|
||||||
File htmlPath = getOutputFile(outputPath, "test", configuration.getSuffix(), false, ".html");
|
File htmlPath = getOutputFile(outputPath, "test", configuration.getSuffix(), false, ".html");
|
||||||
properties.put("SCRIPT", testPath.getName());
|
properties.put("SCRIPT", testPath.getName());
|
||||||
properties.put("IDENTIFIER", "");
|
properties.put("IDENTIFIER", "");
|
||||||
|
|
|
@ -21,9 +21,9 @@
|
||||||
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
|
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<script type="text/javascript" src="${SCRIPT}"></script>
|
<script type="text/javascript" src="${SCRIPT}-runtime.js"></script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
TeaVM.wasm.load("test.wasm").then(teavm => teavm.main(["${IDENTIFIER}"]));
|
TeaVM.wasm.load("${SCRIPT}").then(teavm => teavm.main(["${IDENTIFIER}"]));
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
Loading…
Reference in New Issue
Block a user