mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
WASM: porting jbox2d benchmark to WebAssembly
This commit is contained in:
parent
f890680e90
commit
cc0c68e809
|
@ -15,6 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.classlib.java.lang;
|
package org.teavm.classlib.java.lang;
|
||||||
|
|
||||||
|
import org.teavm.interop.Import;
|
||||||
import org.teavm.jso.JSBody;
|
import org.teavm.jso.JSBody;
|
||||||
|
|
||||||
public class TFloat extends TNumber implements TComparable<TFloat> {
|
public class TFloat extends TNumber implements TComparable<TFloat> {
|
||||||
|
@ -89,12 +90,19 @@ public class TFloat extends TNumber implements TComparable<TFloat> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@JSBody(params = "v", script = "return isNaN(v);")
|
@JSBody(params = "v", script = "return isNaN(v);")
|
||||||
|
@Import(module = "runtime", name = "isNaN")
|
||||||
public static native boolean isNaN(float v);
|
public static native boolean isNaN(float v);
|
||||||
|
|
||||||
@JSBody(params = "v", script = "return !isFinite(v);")
|
public static boolean isInfinite(float v) {
|
||||||
public static native boolean isInfinite(float v);
|
return !isFinite(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
@JSBody(params = "v", script = "return isFinite(v);")
|
||||||
|
@Import(module = "runtime", name = "isFinite")
|
||||||
|
private static native boolean isFinite(float v);
|
||||||
|
|
||||||
@JSBody(params = {}, script = "return NaN;")
|
@JSBody(params = {}, script = "return NaN;")
|
||||||
|
@Import(module = "runtime", name = "getNaN")
|
||||||
private static native float getNaN();
|
private static native float getNaN();
|
||||||
|
|
||||||
public static float parseFloat(TString string) throws TNumberFormatException {
|
public static float parseFloat(TString string) throws TNumberFormatException {
|
||||||
|
|
|
@ -16,11 +16,8 @@
|
||||||
package org.teavm.classlib.java.lang;
|
package org.teavm.classlib.java.lang;
|
||||||
|
|
||||||
import org.teavm.backend.javascript.spi.GeneratedBy;
|
import org.teavm.backend.javascript.spi.GeneratedBy;
|
||||||
|
import org.teavm.interop.Import;
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Alexey Andreev
|
|
||||||
*/
|
|
||||||
public final class TMath extends TObject {
|
public final class TMath extends TObject {
|
||||||
public static final double E = 2.71828182845904523536;
|
public static final double E = 2.71828182845904523536;
|
||||||
public static final double PI = 3.14159265358979323846;
|
public static final double PI = 3.14159265358979323846;
|
||||||
|
@ -29,21 +26,27 @@ public final class TMath extends TObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
@GeneratedBy(MathNativeGenerator.class)
|
@GeneratedBy(MathNativeGenerator.class)
|
||||||
|
@Import(module = "math", name = "sin")
|
||||||
public static native double sin(double a);
|
public static native double sin(double a);
|
||||||
|
|
||||||
@GeneratedBy(MathNativeGenerator.class)
|
@GeneratedBy(MathNativeGenerator.class)
|
||||||
|
@Import(module = "math", name = "cos")
|
||||||
public static native double cos(double a);
|
public static native double cos(double a);
|
||||||
|
|
||||||
@GeneratedBy(MathNativeGenerator.class)
|
@GeneratedBy(MathNativeGenerator.class)
|
||||||
|
@Import(module = "math", name = "tan")
|
||||||
public static native double tan(double a);
|
public static native double tan(double a);
|
||||||
|
|
||||||
@GeneratedBy(MathNativeGenerator.class)
|
@GeneratedBy(MathNativeGenerator.class)
|
||||||
|
@Import(module = "math", name = "asin")
|
||||||
public static native double asin(double a);
|
public static native double asin(double a);
|
||||||
|
|
||||||
@GeneratedBy(MathNativeGenerator.class)
|
@GeneratedBy(MathNativeGenerator.class)
|
||||||
|
@Import(module = "math", name = "acos")
|
||||||
public static native double acos(double a);
|
public static native double acos(double a);
|
||||||
|
|
||||||
@GeneratedBy(MathNativeGenerator.class)
|
@GeneratedBy(MathNativeGenerator.class)
|
||||||
|
@Import(module = "math", name = "atan")
|
||||||
public static native double atan(double a);
|
public static native double atan(double a);
|
||||||
|
|
||||||
public static double toRadians(double angdeg) {
|
public static double toRadians(double angdeg) {
|
||||||
|
@ -55,9 +58,11 @@ public final class TMath extends TObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
@GeneratedBy(MathNativeGenerator.class)
|
@GeneratedBy(MathNativeGenerator.class)
|
||||||
|
@Import(module = "math", name = "exp")
|
||||||
public static native double exp(double a);
|
public static native double exp(double a);
|
||||||
|
|
||||||
@GeneratedBy(MathNativeGenerator.class)
|
@GeneratedBy(MathNativeGenerator.class)
|
||||||
|
@Import(module = "math", name = "log")
|
||||||
public static native double log(double a);
|
public static native double log(double a);
|
||||||
|
|
||||||
public static double log10(double a) {
|
public static double log10(double a) {
|
||||||
|
@ -65,6 +70,7 @@ public final class TMath extends TObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
@GeneratedBy(MathNativeGenerator.class)
|
@GeneratedBy(MathNativeGenerator.class)
|
||||||
|
@Import(module = "math", name = "sqrt")
|
||||||
public static native double sqrt(double a);
|
public static native double sqrt(double a);
|
||||||
|
|
||||||
public static double cbrt(double a) {
|
public static double cbrt(double a) {
|
||||||
|
@ -77,12 +83,15 @@ public final class TMath extends TObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
@GeneratedBy(MathNativeGenerator.class)
|
@GeneratedBy(MathNativeGenerator.class)
|
||||||
|
@Import(module = "math", name = "ceil")
|
||||||
public static native double ceil(double a);
|
public static native double ceil(double a);
|
||||||
|
|
||||||
@GeneratedBy(MathNativeGenerator.class)
|
@GeneratedBy(MathNativeGenerator.class)
|
||||||
|
@Import(module = "math", name = "floor")
|
||||||
public static native double floor(double a);
|
public static native double floor(double a);
|
||||||
|
|
||||||
@GeneratedBy(MathNativeGenerator.class)
|
@GeneratedBy(MathNativeGenerator.class)
|
||||||
|
@Import(module = "math", name = "pow")
|
||||||
public static native double pow(double x, double y);
|
public static native double pow(double x, double y);
|
||||||
|
|
||||||
public static double rint(double a) {
|
public static double rint(double a) {
|
||||||
|
@ -90,6 +99,7 @@ public final class TMath extends TObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
@GeneratedBy(MathNativeGenerator.class)
|
@GeneratedBy(MathNativeGenerator.class)
|
||||||
|
@Import(module = "math", name = "atan2")
|
||||||
public static native double atan2(double y, double x);
|
public static native double atan2(double y, double x);
|
||||||
|
|
||||||
public static int round(float a) {
|
public static int round(float a) {
|
||||||
|
@ -101,6 +111,7 @@ public final class TMath extends TObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
@GeneratedBy(MathNativeGenerator.class)
|
@GeneratedBy(MathNativeGenerator.class)
|
||||||
|
@Import(module = "math", name = "random")
|
||||||
public static native double random();
|
public static native double random();
|
||||||
|
|
||||||
public static int min(int a, int b) {
|
public static int min(int a, int b) {
|
||||||
|
|
|
@ -18,7 +18,6 @@ package org.teavm.backend.wasm.generate;
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayDeque;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.Deque;
|
import java.util.Deque;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -106,7 +105,6 @@ import org.teavm.backend.wasm.model.expression.WasmStoreInt64;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmSwitch;
|
import org.teavm.backend.wasm.model.expression.WasmSwitch;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmUnreachable;
|
import org.teavm.backend.wasm.model.expression.WasmUnreachable;
|
||||||
import org.teavm.interop.Address;
|
import org.teavm.interop.Address;
|
||||||
import org.teavm.model.CallLocation;
|
|
||||||
import org.teavm.model.FieldReference;
|
import org.teavm.model.FieldReference;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
import org.teavm.model.TextLocation;
|
import org.teavm.model.TextLocation;
|
||||||
|
@ -123,7 +121,6 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
private WasmGenerationContext context;
|
private WasmGenerationContext context;
|
||||||
private WasmClassGenerator classGenerator;
|
private WasmClassGenerator classGenerator;
|
||||||
private WasmFunction function;
|
private WasmFunction function;
|
||||||
private MethodReference method;
|
|
||||||
private int firstVariable;
|
private int firstVariable;
|
||||||
private IdentifiedStatement currentContinueTarget;
|
private IdentifiedStatement currentContinueTarget;
|
||||||
private IdentifiedStatement currentBreakTarget;
|
private IdentifiedStatement currentBreakTarget;
|
||||||
|
@ -135,11 +132,10 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
WasmExpression result;
|
WasmExpression result;
|
||||||
|
|
||||||
WasmGenerationVisitor(WasmGenerationContext context, WasmClassGenerator classGenerator,
|
WasmGenerationVisitor(WasmGenerationContext context, WasmClassGenerator classGenerator,
|
||||||
WasmFunction function, MethodReference method, int firstVariable) {
|
WasmFunction function, int firstVariable) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.classGenerator = classGenerator;
|
this.classGenerator = classGenerator;
|
||||||
this.function = function;
|
this.function = function;
|
||||||
this.method = method;
|
|
||||||
this.firstVariable = firstVariable;
|
this.firstVariable = firstVariable;
|
||||||
int typeCount = WasmType.values().length;
|
int typeCount = WasmType.values().length;
|
||||||
for (int i = 0; i < typeCount; ++i) {
|
for (int i = 0; i < typeCount; ++i) {
|
||||||
|
@ -862,15 +858,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
int vtableOffset = classGenerator.getClassSize(RuntimeClass.class.getName());
|
int vtableOffset = classGenerator.getClassSize(RuntimeClass.class.getName());
|
||||||
VirtualTableEntry vtableEntry = context.getVirtualTableProvider().lookup(expr.getMethod());
|
VirtualTableEntry vtableEntry = context.getVirtualTableProvider().lookup(expr.getMethod());
|
||||||
if (vtableEntry == null) {
|
if (vtableEntry == null) {
|
||||||
result = new WasmInt32Constant(0);
|
result = new WasmUnreachable();
|
||||||
TextLocation insnLocation = null;
|
|
||||||
if (expr.getLocation() != null) {
|
|
||||||
insnLocation = new TextLocation(expr.getLocation().getFileName(),
|
|
||||||
expr.getLocation().getLine());
|
|
||||||
}
|
|
||||||
CallLocation location = new CallLocation(method, insnLocation);
|
|
||||||
context.getDiagnostics().error(location, "Can't generate WebAssembly to call {{m0}} method",
|
|
||||||
expr.getMethod());
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
WasmExpression methodIndex = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD,
|
WasmExpression methodIndex = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD,
|
||||||
|
@ -1160,7 +1148,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
if (expr.getType() instanceof ValueType.Object) {
|
if (expr.getType() instanceof ValueType.Object) {
|
||||||
ValueType.Object cls = (ValueType.Object) expr.getType();
|
ValueType.Object cls = (ValueType.Object) expr.getType();
|
||||||
List<TagRegistry.Range> ranges = context.getTagRegistry().getRanges(cls.getClassName());
|
List<TagRegistry.Range> ranges = context.getTagRegistry().getRanges(cls.getClassName());
|
||||||
Collections.sort(ranges, Comparator.comparingInt(range -> range.lower));
|
ranges.sort(Comparator.comparingInt(range -> range.lower));
|
||||||
|
|
||||||
WasmBlock block = new WasmBlock(false);
|
WasmBlock block = new WasmBlock(false);
|
||||||
block.setLocation(expr.getLocation());
|
block.setLocation(expr.getLocation());
|
||||||
|
@ -1187,11 +1175,11 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
WasmIntBinaryOperation.GT_SIGNED, new WasmGetLocal(tagVar),
|
WasmIntBinaryOperation.GT_SIGNED, new WasmGetLocal(tagVar),
|
||||||
new WasmInt32Constant(ranges.get(i - 1).upper));
|
new WasmInt32Constant(ranges.get(i - 1).upper));
|
||||||
WasmConditional conditional = new WasmConditional(upperThanExcluded);
|
WasmConditional conditional = new WasmConditional(upperThanExcluded);
|
||||||
WasmExpression lowerThanExluded = new WasmIntBinary(WasmIntType.INT32,
|
WasmExpression lowerThanExcluded = new WasmIntBinary(WasmIntType.INT32,
|
||||||
WasmIntBinaryOperation.LT_SIGNED, new WasmGetLocal(tagVar),
|
WasmIntBinaryOperation.LT_SIGNED, new WasmGetLocal(tagVar),
|
||||||
new WasmInt32Constant(ranges.get(i).lower));
|
new WasmInt32Constant(ranges.get(i).lower));
|
||||||
|
|
||||||
WasmBranch branch = new WasmBranch(lowerThanExluded, block);
|
WasmBranch branch = new WasmBranch(lowerThanExcluded, block);
|
||||||
branch.setResult(new WasmInt32Constant(0));
|
branch.setResult(new WasmInt32Constant(0));
|
||||||
conditional.getThenBlock().getBody().add(branch);
|
conditional.getThenBlock().getBody().add(branch);
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,8 @@ import org.teavm.ast.decompilation.Decompiler;
|
||||||
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;
|
||||||
import org.teavm.backend.wasm.model.WasmType;
|
import org.teavm.backend.wasm.model.WasmType;
|
||||||
|
import org.teavm.interop.Export;
|
||||||
|
import org.teavm.model.AnnotationReader;
|
||||||
import org.teavm.model.ClassHolder;
|
import org.teavm.model.ClassHolder;
|
||||||
import org.teavm.model.ClassHolderSource;
|
import org.teavm.model.ClassHolderSource;
|
||||||
import org.teavm.model.ElementModifier;
|
import org.teavm.model.ElementModifier;
|
||||||
|
@ -64,11 +66,16 @@ public class WasmGenerator {
|
||||||
function.setResult(WasmGeneratorUtil.mapType(methodReference.getReturnType()));
|
function.setResult(WasmGeneratorUtil.mapType(methodReference.getReturnType()));
|
||||||
}
|
}
|
||||||
|
|
||||||
WasmGenerationVisitor visitor = new WasmGenerationVisitor(context, classGenerator, function, methodReference,
|
WasmGenerationVisitor visitor = new WasmGenerationVisitor(context, classGenerator, function,
|
||||||
firstVariable);
|
firstVariable);
|
||||||
methodAst.getBody().acceptVisitor(visitor);
|
methodAst.getBody().acceptVisitor(visitor);
|
||||||
function.getBody().add(visitor.result);
|
function.getBody().add(visitor.result);
|
||||||
|
|
||||||
|
AnnotationReader exportAnnot = method.getAnnotations().get(Export.class.getName());
|
||||||
|
if (exportAnnot != null) {
|
||||||
|
function.setExportName(exportAnnot.getValue("name").getString());
|
||||||
|
}
|
||||||
|
|
||||||
return function;
|
return function;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -155,7 +155,7 @@ public class WasmBinaryRenderer {
|
||||||
|
|
||||||
section.writeLEB(module.getMemorySize());
|
section.writeLEB(module.getMemorySize());
|
||||||
section.writeLEB(module.getMemorySize());
|
section.writeLEB(module.getMemorySize());
|
||||||
section.writeByte(0);
|
section.writeByte(1);
|
||||||
|
|
||||||
writeSection("memory", section.getData());
|
writeSection("memory", section.getData());
|
||||||
}
|
}
|
||||||
|
|
|
@ -398,10 +398,10 @@ class WasmRenderingVisitor implements WasmExpressionVisitor {
|
||||||
append("i32.load");
|
append("i32.load");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
append(" align=" + expression.getAlignment());
|
|
||||||
if (expression.getOffset() > 0) {
|
if (expression.getOffset() > 0) {
|
||||||
append(" offset=" + expression.getOffset());
|
append(" offset=" + expression.getOffset());
|
||||||
}
|
}
|
||||||
|
append(" align=" + expression.getAlignment());
|
||||||
line(expression.getIndex());
|
line(expression.getIndex());
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
@ -432,30 +432,32 @@ class WasmRenderingVisitor implements WasmExpressionVisitor {
|
||||||
append("i64.load");
|
append("i64.load");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
append(" align=" + expression.getAlignment());
|
|
||||||
if (expression.getOffset() > 0) {
|
if (expression.getOffset() > 0) {
|
||||||
append(" offset=" + expression.getOffset());
|
append(" offset=" + expression.getOffset());
|
||||||
}
|
}
|
||||||
|
append(" align=" + expression.getAlignment());
|
||||||
line(expression.getIndex());
|
line(expression.getIndex());
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(WasmLoadFloat32 expression) {
|
public void visit(WasmLoadFloat32 expression) {
|
||||||
open().append("f32.load align=" + expression.getAlignment());
|
open().append("f32.load");
|
||||||
if (expression.getOffset() > 0) {
|
if (expression.getOffset() > 0) {
|
||||||
append(" offset=" + expression.getOffset());
|
append(" offset=" + expression.getOffset());
|
||||||
}
|
}
|
||||||
|
append(" align=" + expression.getAlignment());
|
||||||
line(expression.getIndex());
|
line(expression.getIndex());
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(WasmLoadFloat64 expression) {
|
public void visit(WasmLoadFloat64 expression) {
|
||||||
open().append("f64.load align=" + expression.getAlignment());
|
open().append("f64.load");
|
||||||
if (expression.getOffset() > 0) {
|
if (expression.getOffset() > 0) {
|
||||||
append(" offset=" + expression.getOffset());
|
append(" offset=" + expression.getOffset());
|
||||||
}
|
}
|
||||||
|
append(" align=" + expression.getAlignment());
|
||||||
line(expression.getIndex());
|
line(expression.getIndex());
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
@ -476,10 +478,10 @@ class WasmRenderingVisitor implements WasmExpressionVisitor {
|
||||||
append("i32.store");
|
append("i32.store");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
append(" align=" + expression.getAlignment());
|
|
||||||
if (expression.getOffset() > 0) {
|
if (expression.getOffset() > 0) {
|
||||||
append(" offset=" + expression.getOffset());
|
append(" offset=" + expression.getOffset());
|
||||||
}
|
}
|
||||||
|
append(" align=" + expression.getAlignment());
|
||||||
line(expression.getIndex());
|
line(expression.getIndex());
|
||||||
line(expression.getValue());
|
line(expression.getValue());
|
||||||
close();
|
close();
|
||||||
|
@ -505,10 +507,10 @@ class WasmRenderingVisitor implements WasmExpressionVisitor {
|
||||||
append("i64.store");
|
append("i64.store");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
append(" align=" + expression.getAlignment());
|
|
||||||
if (expression.getOffset() > 0) {
|
if (expression.getOffset() > 0) {
|
||||||
append(" offset=" + expression.getOffset());
|
append(" offset=" + expression.getOffset());
|
||||||
}
|
}
|
||||||
|
append(" align=" + expression.getAlignment());
|
||||||
line(expression.getIndex());
|
line(expression.getIndex());
|
||||||
line(expression.getValue());
|
line(expression.getValue());
|
||||||
close();
|
close();
|
||||||
|
@ -516,10 +518,11 @@ class WasmRenderingVisitor implements WasmExpressionVisitor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(WasmStoreFloat32 expression) {
|
public void visit(WasmStoreFloat32 expression) {
|
||||||
open().append("f32.store align=" + expression.getAlignment());
|
open().append("f32.store");
|
||||||
if (expression.getOffset() > 0) {
|
if (expression.getOffset() > 0) {
|
||||||
append(" offset=" + expression.getOffset());
|
append(" offset=" + expression.getOffset());
|
||||||
}
|
}
|
||||||
|
append(" align=" + expression.getAlignment());
|
||||||
line(expression.getIndex());
|
line(expression.getIndex());
|
||||||
line(expression.getValue());
|
line(expression.getValue());
|
||||||
close();
|
close();
|
||||||
|
@ -527,10 +530,11 @@ class WasmRenderingVisitor implements WasmExpressionVisitor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(WasmStoreFloat64 expression) {
|
public void visit(WasmStoreFloat64 expression) {
|
||||||
open().append("f64.store align=" + expression.getAlignment());
|
open().append("f64.store");
|
||||||
if (expression.getOffset() > 0) {
|
if (expression.getOffset() > 0) {
|
||||||
append(" offset=" + expression.getOffset());
|
append(" offset=" + expression.getOffset());
|
||||||
}
|
}
|
||||||
|
append(" align=" + expression.getAlignment());
|
||||||
line(expression.getIndex());
|
line(expression.getIndex());
|
||||||
line(expression.getValue());
|
line(expression.getValue());
|
||||||
close();
|
close();
|
||||||
|
|
|
@ -38,12 +38,17 @@ public class VirtualTableProvider {
|
||||||
this.classSource = classSource;
|
this.classSource = classSource;
|
||||||
interfaceMapping = new InterfaceToClassMapping(classSource);
|
interfaceMapping = new InterfaceToClassMapping(classSource);
|
||||||
|
|
||||||
|
Set<String> classNames = new HashSet<>(classSource.getClassNames());
|
||||||
for (MethodReference virtualMethod : virtualMethods) {
|
for (MethodReference virtualMethod : virtualMethods) {
|
||||||
String cls = interfaceMapping.mapClass(virtualMethod.getClassName());
|
String cls = interfaceMapping.mapClass(virtualMethod.getClassName());
|
||||||
|
if (cls == null) {
|
||||||
|
cls = virtualMethod.getClassName();
|
||||||
|
}
|
||||||
|
classNames.add(cls);
|
||||||
virtualMethodMap.computeIfAbsent(cls, c -> new HashSet<>()).add(virtualMethod.getDescriptor());
|
virtualMethodMap.computeIfAbsent(cls, c -> new HashSet<>()).add(virtualMethod.getDescriptor());
|
||||||
}
|
}
|
||||||
|
|
||||||
for (String className : classSource.getClassNames()) {
|
for (String className : classNames) {
|
||||||
fillClass(className);
|
fillClass(className);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -153,29 +153,6 @@ public class TypeInferer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VariableType convert(ArrayElementType type) {
|
|
||||||
switch (type) {
|
|
||||||
case BYTE:
|
|
||||||
return VariableType.BYTE_ARRAY;
|
|
||||||
case CHAR:
|
|
||||||
return VariableType.CHAR_ARRAY;
|
|
||||||
case SHORT:
|
|
||||||
return VariableType.SHORT_ARRAY;
|
|
||||||
case INT:
|
|
||||||
return VariableType.INT_ARRAY;
|
|
||||||
case LONG:
|
|
||||||
return VariableType.LONG_ARRAY;
|
|
||||||
case FLOAT:
|
|
||||||
return VariableType.FLOAT_ARRAY;
|
|
||||||
case DOUBLE:
|
|
||||||
return VariableType.DOUBLE_ARRAY;
|
|
||||||
case OBJECT:
|
|
||||||
return VariableType.OBJECT_ARRAY;
|
|
||||||
default:
|
|
||||||
throw new AssertionError();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VariableType convert(NumericOperandType type) {
|
VariableType convert(NumericOperandType type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case INT:
|
case INT:
|
||||||
|
@ -396,7 +373,15 @@ public class TypeInferer {
|
||||||
@Override
|
@Override
|
||||||
public void binary(BinaryOperation op, VariableReader receiver, VariableReader first, VariableReader second,
|
public void binary(BinaryOperation op, VariableReader receiver, VariableReader first, VariableReader second,
|
||||||
NumericOperandType type) {
|
NumericOperandType type) {
|
||||||
types[receiver.getIndex()] = convert(type);
|
switch (op) {
|
||||||
|
case COMPARE:
|
||||||
|
types[receiver.getIndex()] = VariableType.INT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
types[receiver.getIndex()] = convert(type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
package org.teavm.runtime;
|
package org.teavm.runtime;
|
||||||
|
|
||||||
import org.teavm.interop.Address;
|
import org.teavm.interop.Address;
|
||||||
|
import org.teavm.interop.Export;
|
||||||
import org.teavm.interop.StaticInit;
|
import org.teavm.interop.StaticInit;
|
||||||
import org.teavm.interop.Structure;
|
import org.teavm.interop.Structure;
|
||||||
import org.teavm.interop.Unmanaged;
|
import org.teavm.interop.Unmanaged;
|
||||||
|
@ -30,6 +31,7 @@ public final class ExceptionHandling {
|
||||||
|
|
||||||
private static Throwable thrownException;
|
private static Throwable thrownException;
|
||||||
|
|
||||||
|
@Export(name = "sys$catchException")
|
||||||
public static Throwable catchException() {
|
public static Throwable catchException() {
|
||||||
Throwable exception = thrownException;
|
Throwable exception = thrownException;
|
||||||
thrownException = null;
|
thrownException = null;
|
||||||
|
|
27
interop/core/src/main/java/org/teavm/interop/Export.java
Normal file
27
interop/core/src/main/java/org/teavm/interop/Export.java
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2016 Alexey Andreev.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.teavm.interop;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target(ElementType.METHOD)
|
||||||
|
public @interface Export {
|
||||||
|
String name();
|
||||||
|
}
|
|
@ -45,6 +45,12 @@
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.teavm</groupId>
|
||||||
|
<artifactId>teavm-interop</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jbox2d</groupId>
|
<groupId>org.jbox2d</groupId>
|
||||||
<artifactId>jbox2d-library</artifactId>
|
<artifactId>jbox2d-library</artifactId>
|
||||||
|
@ -144,6 +150,19 @@
|
||||||
<optimizationLevel>FULL</optimizationLevel>
|
<optimizationLevel>FULL</optimizationLevel>
|
||||||
</configuration>
|
</configuration>
|
||||||
</execution>
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<id>wasm-client</id>
|
||||||
|
<goals>
|
||||||
|
<goal>compile</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<targetDirectory>${project.build.directory}/generated/wasm/teavm-wasm</targetDirectory>
|
||||||
|
<mainClass>org.teavm.samples.benchmark.teavm.WasmBenchmarkStarter</mainClass>
|
||||||
|
<debugInformationGenerated>true</debugInformationGenerated>
|
||||||
|
<targetType>WEBASSEMBLY</targetType>
|
||||||
|
<optimizationLevel>FULL</optimizationLevel>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
|
|
|
@ -30,10 +30,6 @@ import org.teavm.jso.dom.html.HTMLDocument;
|
||||||
import org.teavm.jso.dom.html.HTMLElement;
|
import org.teavm.jso.dom.html.HTMLElement;
|
||||||
import org.teavm.samples.benchmark.shared.Scene;
|
import org.teavm.samples.benchmark.shared.Scene;
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Alexey Andreev
|
|
||||||
*/
|
|
||||||
public final class BenchmarkStarter {
|
public final class BenchmarkStarter {
|
||||||
private static HTMLDocument document = Window.current().getDocument();
|
private static HTMLDocument document = Window.current().getDocument();
|
||||||
private static HTMLCanvasElement canvas = (HTMLCanvasElement) document.getElementById("benchmark-canvas");
|
private static HTMLCanvasElement canvas = (HTMLCanvasElement) document.getElementById("benchmark-canvas");
|
||||||
|
|
|
@ -0,0 +1,105 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2016 Alexey Andreev.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.teavm.samples.benchmark.teavm;
|
||||||
|
|
||||||
|
import org.jbox2d.collision.shapes.CircleShape;
|
||||||
|
import org.jbox2d.collision.shapes.PolygonShape;
|
||||||
|
import org.jbox2d.collision.shapes.Shape;
|
||||||
|
import org.jbox2d.collision.shapes.ShapeType;
|
||||||
|
import org.jbox2d.common.Vec2;
|
||||||
|
import org.jbox2d.dynamics.Body;
|
||||||
|
import org.jbox2d.dynamics.Fixture;
|
||||||
|
import org.teavm.interop.Export;
|
||||||
|
import org.teavm.interop.Import;
|
||||||
|
import org.teavm.samples.benchmark.shared.Scene;
|
||||||
|
|
||||||
|
public final class WasmBenchmarkStarter {
|
||||||
|
private static Scene scene = new Scene();
|
||||||
|
private static int currentSecond;
|
||||||
|
private static long startMillisecond;
|
||||||
|
private static int timeSpentCalculating;
|
||||||
|
|
||||||
|
private WasmBenchmarkStarter() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
startMillisecond = System.currentTimeMillis();
|
||||||
|
tick();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Export(name = "tick")
|
||||||
|
public static void tick() {
|
||||||
|
double start = performanceTime();
|
||||||
|
System.out.println("About to calculate frame");
|
||||||
|
scene.calculate();
|
||||||
|
System.out.println("Frame calculated successfully");
|
||||||
|
double end = performanceTime();
|
||||||
|
int second = (int) ((System.currentTimeMillis() - startMillisecond) / 1000);
|
||||||
|
if (second > currentSecond) {
|
||||||
|
reportPerformance(second, timeSpentCalculating);
|
||||||
|
timeSpentCalculating = 0;
|
||||||
|
currentSecond = second;
|
||||||
|
}
|
||||||
|
timeSpentCalculating += (int) (end - start);
|
||||||
|
render();
|
||||||
|
repeatAfter(scene.timeUntilNextStep());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void render() {
|
||||||
|
WasmCanvas.save();
|
||||||
|
setupCanvas();
|
||||||
|
for (Body body = scene.getWorld().getBodyList(); body != null; body = body.getNext()) {
|
||||||
|
Vec2 center = body.getPosition();
|
||||||
|
WasmCanvas.save();
|
||||||
|
WasmCanvas.translate(center.x, center.y);
|
||||||
|
WasmCanvas.rotate(body.getAngle());
|
||||||
|
for (Fixture fixture = body.getFixtureList(); fixture != null; fixture = fixture.getNext()) {
|
||||||
|
Shape shape = fixture.getShape();
|
||||||
|
if (shape.getType() == ShapeType.CIRCLE) {
|
||||||
|
CircleShape circle = (CircleShape) shape;
|
||||||
|
WasmCanvas.beginPath();
|
||||||
|
WasmCanvas.arc(circle.m_p.x, circle.m_p.y, circle.getRadius(), 0, Math.PI * 2, true);
|
||||||
|
WasmCanvas.closePath();
|
||||||
|
WasmCanvas.stroke();
|
||||||
|
} else if (shape.getType() == ShapeType.POLYGON) {
|
||||||
|
PolygonShape poly = (PolygonShape) shape;
|
||||||
|
Vec2[] vertices = poly.getVertices();
|
||||||
|
WasmCanvas.beginPath();
|
||||||
|
WasmCanvas.moveTo(vertices[0].x, vertices[0].y);
|
||||||
|
for (int i = 1; i < poly.getVertexCount(); ++i) {
|
||||||
|
WasmCanvas.lineTo(vertices[i].x, vertices[i].y);
|
||||||
|
}
|
||||||
|
WasmCanvas.closePath();
|
||||||
|
WasmCanvas.stroke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WasmCanvas.restore();
|
||||||
|
}
|
||||||
|
WasmCanvas.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Import(module = "benchmark", name = "setupCanvas")
|
||||||
|
private static native void setupCanvas();
|
||||||
|
|
||||||
|
@Import(module = "benchmark", name = "performanceTime")
|
||||||
|
private static native double performanceTime();
|
||||||
|
|
||||||
|
@Import(module = "benchmark", name = "reportPerformance")
|
||||||
|
private static native void reportPerformance(int second, int timeSpentCalculating);
|
||||||
|
|
||||||
|
@Import(module = "benchmark", name = "repeatAfter")
|
||||||
|
private static native void repeatAfter(int seconds);
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2016 Alexey Andreev.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.teavm.samples.benchmark.teavm;
|
||||||
|
|
||||||
|
import org.teavm.interop.Import;
|
||||||
|
import org.teavm.interop.StaticInit;
|
||||||
|
|
||||||
|
@StaticInit
|
||||||
|
public final class WasmCanvas {
|
||||||
|
private WasmCanvas() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Import(module = "canvas", name = "save")
|
||||||
|
public static native void save();
|
||||||
|
|
||||||
|
@Import(module = "canvas", name = "restore")
|
||||||
|
public static native void restore();
|
||||||
|
|
||||||
|
@Import(module = "canvas", name = "translate")
|
||||||
|
public static native void translate(double x, double y);
|
||||||
|
|
||||||
|
@Import(module = "canvas", name = "rotate")
|
||||||
|
public static native void rotate(double angle);
|
||||||
|
|
||||||
|
@Import(module = "canvas", name = "beginPath")
|
||||||
|
public static native void beginPath();
|
||||||
|
|
||||||
|
@Import(module = "canvas", name = "closePath")
|
||||||
|
public static native void closePath();
|
||||||
|
|
||||||
|
@Import(module = "canvas", name = "stroke")
|
||||||
|
public static native void stroke();
|
||||||
|
|
||||||
|
@Import(module = "canvas", name = "arc")
|
||||||
|
public static native void arc(double cx, double cy, double radius, double startAngle, double endAngle,
|
||||||
|
boolean counterClockwise);
|
||||||
|
|
||||||
|
@Import(module = "canvas", name = "moveTo")
|
||||||
|
public static native void moveTo(double x, double y);
|
||||||
|
|
||||||
|
@Import(module = "canvas", name = "lineTo")
|
||||||
|
public static native void lineTo(double x, double y);
|
||||||
|
}
|
46
samples/benchmark/src/main/webapp/teavm-wasm.html
Normal file
46
samples/benchmark/src/main/webapp/teavm-wasm.html
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<!--
|
||||||
|
~ Copyright 2016 Alexey Andreev.
|
||||||
|
~
|
||||||
|
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
~ you may not use this file except in compliance with the License.
|
||||||
|
~ You may obtain a copy of the License at
|
||||||
|
~
|
||||||
|
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
~
|
||||||
|
~ Unless required by applicable law or agreed to in writing, software
|
||||||
|
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
~ See the License for the specific language governing permissions and
|
||||||
|
~ limitations under the License.
|
||||||
|
-->
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
|
||||||
|
<title>TeaVM WebAssembly jbox2d benchmark</title>
|
||||||
|
<script src="teavm-wasm.js" type="text/javascript"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>TeaVM performance</h1>
|
||||||
|
<div>
|
||||||
|
<canvas id="benchmark-canvas" width="600" height="600"></canvas>
|
||||||
|
</div>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Second</th>
|
||||||
|
<th>Time spent computing, ms</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="result-table-body">
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<script>
|
||||||
|
var canvas = document.getElementById("benchmark-canvas");
|
||||||
|
document.body.onload = function() {
|
||||||
|
var benchmark = new Benchmark(canvas.getContext("2d"));
|
||||||
|
benchmark.runAll();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
104
samples/benchmark/src/main/webapp/teavm-wasm.js
Normal file
104
samples/benchmark/src/main/webapp/teavm-wasm.js
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2016 Alexey Andreev.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var Benchmark = function() {
|
||||||
|
function Benchmark(canvas) {
|
||||||
|
this.canvas = canvas;
|
||||||
|
this.module = null;
|
||||||
|
this.line = "";
|
||||||
|
}
|
||||||
|
Benchmark.prototype.runAll = function() {
|
||||||
|
load(this, function() { this.module.exports.main(); }.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
function tick(benchmark) {
|
||||||
|
var exports = benchmark.module.exports;
|
||||||
|
exports.tick();
|
||||||
|
console.log("tick");
|
||||||
|
var exception = exports.sys$catchException();
|
||||||
|
if (exception != null) {
|
||||||
|
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.open("GET", "teavm-wasm/classes.wasm");
|
||||||
|
xhr.onreadystatechange = function() {
|
||||||
|
var response = xhr.response;
|
||||||
|
if (!response) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var importObj = {
|
||||||
|
runtime: {
|
||||||
|
currentTimeMillis: currentTimeMillis,
|
||||||
|
isNaN: isNaN,
|
||||||
|
isFinite: isFinite,
|
||||||
|
getNaN: function() { return NaN; },
|
||||||
|
putchar: function() { putchar(benchmark); }
|
||||||
|
},
|
||||||
|
benchmark: {
|
||||||
|
performanceTime: function() { return window.performance.now() || 0; },
|
||||||
|
reportPerformance: function(second, timeSpentComputing) {
|
||||||
|
console.log("Second: " + second + ", time: " + timeSpentComputing);
|
||||||
|
},
|
||||||
|
repeatAfter: function(time) {
|
||||||
|
console.log("repeatAfter");
|
||||||
|
setTimeout(tick.bind(benchmark), time);
|
||||||
|
},
|
||||||
|
setupCanvas: function() {
|
||||||
|
var canvas = benchmark.canvas;
|
||||||
|
canvas.setFillStyle("white");
|
||||||
|
context.setStrokeStyle("grey");
|
||||||
|
canvas.fillRect(0, 0, 600, 600);
|
||||||
|
canvas.translate(0, 600);
|
||||||
|
canvas.scale(1, -1);
|
||||||
|
canvas.scale(100, 100);
|
||||||
|
canvas.setLineWidth(0.01);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
canvas: benchmark.canvas,
|
||||||
|
math: Math,
|
||||||
|
debug: {
|
||||||
|
traceMemoryAccess: function(callSite, address) {
|
||||||
|
if (address >= 63 * 65536) {
|
||||||
|
console.log("Memory access #" + callSite + " at " + address);
|
||||||
|
}
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
benchmark.module = Wasm.instantiateModule(new Uint8Array(response), importObj)
|
||||||
|
callback();
|
||||||
|
};
|
||||||
|
xhr.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Benchmark;
|
||||||
|
}();
|
Loading…
Reference in New Issue
Block a user