mirror of
https://github.com/konsoletyper/teavm.git
synced 2024-11-21 01:00:54 +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;
|
||||
|
||||
import org.teavm.interop.Import;
|
||||
import org.teavm.jso.JSBody;
|
||||
|
||||
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);")
|
||||
@Import(module = "runtime", name = "isNaN")
|
||||
public static native boolean isNaN(float v);
|
||||
|
||||
@JSBody(params = "v", script = "return !isFinite(v);")
|
||||
public static native boolean isInfinite(float v);
|
||||
public static 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;")
|
||||
@Import(module = "runtime", name = "getNaN")
|
||||
private static native float getNaN();
|
||||
|
||||
public static float parseFloat(TString string) throws TNumberFormatException {
|
||||
|
@ -16,11 +16,8 @@
|
||||
package org.teavm.classlib.java.lang;
|
||||
|
||||
import org.teavm.backend.javascript.spi.GeneratedBy;
|
||||
import org.teavm.interop.Import;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public final class TMath extends TObject {
|
||||
public static final double E = 2.71828182845904523536;
|
||||
public static final double PI = 3.14159265358979323846;
|
||||
@ -29,21 +26,27 @@ public final class TMath extends TObject {
|
||||
}
|
||||
|
||||
@GeneratedBy(MathNativeGenerator.class)
|
||||
@Import(module = "math", name = "sin")
|
||||
public static native double sin(double a);
|
||||
|
||||
@GeneratedBy(MathNativeGenerator.class)
|
||||
@Import(module = "math", name = "cos")
|
||||
public static native double cos(double a);
|
||||
|
||||
@GeneratedBy(MathNativeGenerator.class)
|
||||
@Import(module = "math", name = "tan")
|
||||
public static native double tan(double a);
|
||||
|
||||
@GeneratedBy(MathNativeGenerator.class)
|
||||
@Import(module = "math", name = "asin")
|
||||
public static native double asin(double a);
|
||||
|
||||
@GeneratedBy(MathNativeGenerator.class)
|
||||
@Import(module = "math", name = "acos")
|
||||
public static native double acos(double a);
|
||||
|
||||
@GeneratedBy(MathNativeGenerator.class)
|
||||
@Import(module = "math", name = "atan")
|
||||
public static native double atan(double a);
|
||||
|
||||
public static double toRadians(double angdeg) {
|
||||
@ -55,9 +58,11 @@ public final class TMath extends TObject {
|
||||
}
|
||||
|
||||
@GeneratedBy(MathNativeGenerator.class)
|
||||
@Import(module = "math", name = "exp")
|
||||
public static native double exp(double a);
|
||||
|
||||
@GeneratedBy(MathNativeGenerator.class)
|
||||
@Import(module = "math", name = "log")
|
||||
public static native double log(double a);
|
||||
|
||||
public static double log10(double a) {
|
||||
@ -65,6 +70,7 @@ public final class TMath extends TObject {
|
||||
}
|
||||
|
||||
@GeneratedBy(MathNativeGenerator.class)
|
||||
@Import(module = "math", name = "sqrt")
|
||||
public static native double sqrt(double a);
|
||||
|
||||
public static double cbrt(double a) {
|
||||
@ -77,12 +83,15 @@ public final class TMath extends TObject {
|
||||
}
|
||||
|
||||
@GeneratedBy(MathNativeGenerator.class)
|
||||
@Import(module = "math", name = "ceil")
|
||||
public static native double ceil(double a);
|
||||
|
||||
@GeneratedBy(MathNativeGenerator.class)
|
||||
@Import(module = "math", name = "floor")
|
||||
public static native double floor(double a);
|
||||
|
||||
@GeneratedBy(MathNativeGenerator.class)
|
||||
@Import(module = "math", name = "pow")
|
||||
public static native double pow(double x, double y);
|
||||
|
||||
public static double rint(double a) {
|
||||
@ -90,6 +99,7 @@ public final class TMath extends TObject {
|
||||
}
|
||||
|
||||
@GeneratedBy(MathNativeGenerator.class)
|
||||
@Import(module = "math", name = "atan2")
|
||||
public static native double atan2(double y, double x);
|
||||
|
||||
public static int round(float a) {
|
||||
@ -101,6 +111,7 @@ public final class TMath extends TObject {
|
||||
}
|
||||
|
||||
@GeneratedBy(MathNativeGenerator.class)
|
||||
@Import(module = "math", name = "random")
|
||||
public static native double random();
|
||||
|
||||
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.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Deque;
|
||||
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.WasmUnreachable;
|
||||
import org.teavm.interop.Address;
|
||||
import org.teavm.model.CallLocation;
|
||||
import org.teavm.model.FieldReference;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.TextLocation;
|
||||
@ -123,7 +121,6 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||
private WasmGenerationContext context;
|
||||
private WasmClassGenerator classGenerator;
|
||||
private WasmFunction function;
|
||||
private MethodReference method;
|
||||
private int firstVariable;
|
||||
private IdentifiedStatement currentContinueTarget;
|
||||
private IdentifiedStatement currentBreakTarget;
|
||||
@ -135,11 +132,10 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||
WasmExpression result;
|
||||
|
||||
WasmGenerationVisitor(WasmGenerationContext context, WasmClassGenerator classGenerator,
|
||||
WasmFunction function, MethodReference method, int firstVariable) {
|
||||
WasmFunction function, int firstVariable) {
|
||||
this.context = context;
|
||||
this.classGenerator = classGenerator;
|
||||
this.function = function;
|
||||
this.method = method;
|
||||
this.firstVariable = firstVariable;
|
||||
int typeCount = WasmType.values().length;
|
||||
for (int i = 0; i < typeCount; ++i) {
|
||||
@ -862,15 +858,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||
int vtableOffset = classGenerator.getClassSize(RuntimeClass.class.getName());
|
||||
VirtualTableEntry vtableEntry = context.getVirtualTableProvider().lookup(expr.getMethod());
|
||||
if (vtableEntry == null) {
|
||||
result = new WasmInt32Constant(0);
|
||||
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());
|
||||
result = new WasmUnreachable();
|
||||
return;
|
||||
}
|
||||
WasmExpression methodIndex = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD,
|
||||
@ -1160,7 +1148,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||
if (expr.getType() instanceof ValueType.Object) {
|
||||
ValueType.Object cls = (ValueType.Object) expr.getType();
|
||||
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);
|
||||
block.setLocation(expr.getLocation());
|
||||
@ -1187,11 +1175,11 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||
WasmIntBinaryOperation.GT_SIGNED, new WasmGetLocal(tagVar),
|
||||
new WasmInt32Constant(ranges.get(i - 1).upper));
|
||||
WasmConditional conditional = new WasmConditional(upperThanExcluded);
|
||||
WasmExpression lowerThanExluded = new WasmIntBinary(WasmIntType.INT32,
|
||||
WasmExpression lowerThanExcluded = new WasmIntBinary(WasmIntType.INT32,
|
||||
WasmIntBinaryOperation.LT_SIGNED, new WasmGetLocal(tagVar),
|
||||
new WasmInt32Constant(ranges.get(i).lower));
|
||||
|
||||
WasmBranch branch = new WasmBranch(lowerThanExluded, block);
|
||||
WasmBranch branch = new WasmBranch(lowerThanExcluded, block);
|
||||
branch.setResult(new WasmInt32Constant(0));
|
||||
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.WasmLocal;
|
||||
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.ClassHolderSource;
|
||||
import org.teavm.model.ElementModifier;
|
||||
@ -64,11 +66,16 @@ public class WasmGenerator {
|
||||
function.setResult(WasmGeneratorUtil.mapType(methodReference.getReturnType()));
|
||||
}
|
||||
|
||||
WasmGenerationVisitor visitor = new WasmGenerationVisitor(context, classGenerator, function, methodReference,
|
||||
WasmGenerationVisitor visitor = new WasmGenerationVisitor(context, classGenerator, function,
|
||||
firstVariable);
|
||||
methodAst.getBody().acceptVisitor(visitor);
|
||||
function.getBody().add(visitor.result);
|
||||
|
||||
AnnotationReader exportAnnot = method.getAnnotations().get(Export.class.getName());
|
||||
if (exportAnnot != null) {
|
||||
function.setExportName(exportAnnot.getValue("name").getString());
|
||||
}
|
||||
|
||||
return function;
|
||||
}
|
||||
|
||||
|
@ -155,7 +155,7 @@ public class WasmBinaryRenderer {
|
||||
|
||||
section.writeLEB(module.getMemorySize());
|
||||
section.writeLEB(module.getMemorySize());
|
||||
section.writeByte(0);
|
||||
section.writeByte(1);
|
||||
|
||||
writeSection("memory", section.getData());
|
||||
}
|
||||
|
@ -398,10 +398,10 @@ class WasmRenderingVisitor implements WasmExpressionVisitor {
|
||||
append("i32.load");
|
||||
break;
|
||||
}
|
||||
append(" align=" + expression.getAlignment());
|
||||
if (expression.getOffset() > 0) {
|
||||
append(" offset=" + expression.getOffset());
|
||||
}
|
||||
append(" align=" + expression.getAlignment());
|
||||
line(expression.getIndex());
|
||||
close();
|
||||
}
|
||||
@ -432,30 +432,32 @@ class WasmRenderingVisitor implements WasmExpressionVisitor {
|
||||
append("i64.load");
|
||||
break;
|
||||
}
|
||||
append(" align=" + expression.getAlignment());
|
||||
if (expression.getOffset() > 0) {
|
||||
append(" offset=" + expression.getOffset());
|
||||
}
|
||||
append(" align=" + expression.getAlignment());
|
||||
line(expression.getIndex());
|
||||
close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmLoadFloat32 expression) {
|
||||
open().append("f32.load align=" + expression.getAlignment());
|
||||
open().append("f32.load");
|
||||
if (expression.getOffset() > 0) {
|
||||
append(" offset=" + expression.getOffset());
|
||||
}
|
||||
append(" align=" + expression.getAlignment());
|
||||
line(expression.getIndex());
|
||||
close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmLoadFloat64 expression) {
|
||||
open().append("f64.load align=" + expression.getAlignment());
|
||||
open().append("f64.load");
|
||||
if (expression.getOffset() > 0) {
|
||||
append(" offset=" + expression.getOffset());
|
||||
}
|
||||
append(" align=" + expression.getAlignment());
|
||||
line(expression.getIndex());
|
||||
close();
|
||||
}
|
||||
@ -476,10 +478,10 @@ class WasmRenderingVisitor implements WasmExpressionVisitor {
|
||||
append("i32.store");
|
||||
break;
|
||||
}
|
||||
append(" align=" + expression.getAlignment());
|
||||
if (expression.getOffset() > 0) {
|
||||
append(" offset=" + expression.getOffset());
|
||||
}
|
||||
append(" align=" + expression.getAlignment());
|
||||
line(expression.getIndex());
|
||||
line(expression.getValue());
|
||||
close();
|
||||
@ -505,10 +507,10 @@ class WasmRenderingVisitor implements WasmExpressionVisitor {
|
||||
append("i64.store");
|
||||
break;
|
||||
}
|
||||
append(" align=" + expression.getAlignment());
|
||||
if (expression.getOffset() > 0) {
|
||||
append(" offset=" + expression.getOffset());
|
||||
}
|
||||
append(" align=" + expression.getAlignment());
|
||||
line(expression.getIndex());
|
||||
line(expression.getValue());
|
||||
close();
|
||||
@ -516,10 +518,11 @@ class WasmRenderingVisitor implements WasmExpressionVisitor {
|
||||
|
||||
@Override
|
||||
public void visit(WasmStoreFloat32 expression) {
|
||||
open().append("f32.store align=" + expression.getAlignment());
|
||||
open().append("f32.store");
|
||||
if (expression.getOffset() > 0) {
|
||||
append(" offset=" + expression.getOffset());
|
||||
}
|
||||
append(" align=" + expression.getAlignment());
|
||||
line(expression.getIndex());
|
||||
line(expression.getValue());
|
||||
close();
|
||||
@ -527,10 +530,11 @@ class WasmRenderingVisitor implements WasmExpressionVisitor {
|
||||
|
||||
@Override
|
||||
public void visit(WasmStoreFloat64 expression) {
|
||||
open().append("f64.store align=" + expression.getAlignment());
|
||||
open().append("f64.store");
|
||||
if (expression.getOffset() > 0) {
|
||||
append(" offset=" + expression.getOffset());
|
||||
}
|
||||
append(" align=" + expression.getAlignment());
|
||||
line(expression.getIndex());
|
||||
line(expression.getValue());
|
||||
close();
|
||||
|
@ -38,12 +38,17 @@ public class VirtualTableProvider {
|
||||
this.classSource = classSource;
|
||||
interfaceMapping = new InterfaceToClassMapping(classSource);
|
||||
|
||||
Set<String> classNames = new HashSet<>(classSource.getClassNames());
|
||||
for (MethodReference virtualMethod : virtualMethods) {
|
||||
String cls = interfaceMapping.mapClass(virtualMethod.getClassName());
|
||||
if (cls == null) {
|
||||
cls = virtualMethod.getClassName();
|
||||
}
|
||||
classNames.add(cls);
|
||||
virtualMethodMap.computeIfAbsent(cls, c -> new HashSet<>()).add(virtualMethod.getDescriptor());
|
||||
}
|
||||
|
||||
for (String className : classSource.getClassNames()) {
|
||||
for (String className : classNames) {
|
||||
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) {
|
||||
switch (type) {
|
||||
case INT:
|
||||
@ -396,7 +373,15 @@ public class TypeInferer {
|
||||
@Override
|
||||
public void binary(BinaryOperation op, VariableReader receiver, VariableReader first, VariableReader second,
|
||||
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
|
||||
|
@ -16,6 +16,7 @@
|
||||
package org.teavm.runtime;
|
||||
|
||||
import org.teavm.interop.Address;
|
||||
import org.teavm.interop.Export;
|
||||
import org.teavm.interop.StaticInit;
|
||||
import org.teavm.interop.Structure;
|
||||
import org.teavm.interop.Unmanaged;
|
||||
@ -30,6 +31,7 @@ public final class ExceptionHandling {
|
||||
|
||||
private static Throwable thrownException;
|
||||
|
||||
@Export(name = "sys$catchException")
|
||||
public static Throwable catchException() {
|
||||
Throwable exception = thrownException;
|
||||
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>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.teavm</groupId>
|
||||
<artifactId>teavm-interop</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jbox2d</groupId>
|
||||
<artifactId>jbox2d-library</artifactId>
|
||||
@ -144,6 +150,19 @@
|
||||
<optimizationLevel>FULL</optimizationLevel>
|
||||
</configuration>
|
||||
</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>
|
||||
</plugin>
|
||||
<plugin>
|
||||
|
@ -30,10 +30,6 @@ import org.teavm.jso.dom.html.HTMLDocument;
|
||||
import org.teavm.jso.dom.html.HTMLElement;
|
||||
import org.teavm.samples.benchmark.shared.Scene;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public final class BenchmarkStarter {
|
||||
private static HTMLDocument document = Window.current().getDocument();
|
||||
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