mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-23 00:24:11 -08:00
Wasm backend: fix
This commit is contained in:
parent
20866637e7
commit
da68fa0083
|
@ -49,6 +49,7 @@ import org.teavm.backend.c.generators.ArrayGenerator;
|
||||||
import org.teavm.backend.c.generators.Generator;
|
import org.teavm.backend.c.generators.Generator;
|
||||||
import org.teavm.backend.c.intrinsic.AddressIntrinsic;
|
import org.teavm.backend.c.intrinsic.AddressIntrinsic;
|
||||||
import org.teavm.backend.c.intrinsic.AllocatorIntrinsic;
|
import org.teavm.backend.c.intrinsic.AllocatorIntrinsic;
|
||||||
|
import org.teavm.backend.c.intrinsic.ConsoleIntrinsic;
|
||||||
import org.teavm.backend.c.intrinsic.ExceptionHandlingIntrinsic;
|
import org.teavm.backend.c.intrinsic.ExceptionHandlingIntrinsic;
|
||||||
import org.teavm.backend.c.intrinsic.FunctionIntrinsic;
|
import org.teavm.backend.c.intrinsic.FunctionIntrinsic;
|
||||||
import org.teavm.backend.c.intrinsic.GCIntrinsic;
|
import org.teavm.backend.c.intrinsic.GCIntrinsic;
|
||||||
|
@ -293,6 +294,7 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
|
||||||
intrinsics.add(new LongIntrinsic());
|
intrinsics.add(new LongIntrinsic());
|
||||||
intrinsics.add(new IntegerIntrinsic());
|
intrinsics.add(new IntegerIntrinsic());
|
||||||
intrinsics.add(new StringsIntrinsic());
|
intrinsics.add(new StringsIntrinsic());
|
||||||
|
intrinsics.add(new ConsoleIntrinsic());
|
||||||
|
|
||||||
List<Generator> generators = new ArrayList<>();
|
List<Generator> generators = new ArrayList<>();
|
||||||
generators.add(new ArrayGenerator());
|
generators.add(new ArrayGenerator());
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2019 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.backend.c.intrinsic;
|
||||||
|
|
||||||
|
import org.teavm.ast.ConstantExpr;
|
||||||
|
import org.teavm.ast.Expr;
|
||||||
|
import org.teavm.ast.InvocationExpr;
|
||||||
|
import org.teavm.backend.c.generate.StringPoolGenerator;
|
||||||
|
import org.teavm.model.MethodReference;
|
||||||
|
import org.teavm.runtime.Console;
|
||||||
|
|
||||||
|
public class ConsoleIntrinsic implements Intrinsic {
|
||||||
|
@Override
|
||||||
|
public boolean canHandle(MethodReference method) {
|
||||||
|
if (!method.getClassName().equals(Console.class.getName())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return method.getName().equals("printString");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void apply(IntrinsicContext context, InvocationExpr invocation) {
|
||||||
|
switch (invocation.getMethod().getName()) {
|
||||||
|
case "printString": {
|
||||||
|
context.writer().print("fprintf(stderr, \"%s\", ");
|
||||||
|
Expr arg = invocation.getArguments().get(0);
|
||||||
|
String literal = extractStringConstant(arg);
|
||||||
|
if (literal != null) {
|
||||||
|
StringPoolGenerator.generateSimpleStringLiteral(context.writer(), literal);
|
||||||
|
} else {
|
||||||
|
context.writer().print("teavm_stringToC(");
|
||||||
|
context.emit(arg);
|
||||||
|
context.writer().print(")");
|
||||||
|
}
|
||||||
|
context.writer().print(")");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String extractStringConstant(Expr expr) {
|
||||||
|
if (!(expr instanceof ConstantExpr)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object value = ((ConstantExpr) expr).getValue();
|
||||||
|
return value instanceof String ? (String) value : null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -83,6 +83,15 @@ public final class WasmRuntime {
|
||||||
@Import(name = "print", module = "spectest")
|
@Import(name = "print", module = "spectest")
|
||||||
public static native void print(int a);
|
public static native void print(int a);
|
||||||
|
|
||||||
|
@Import(name = "logString", module = "teavm")
|
||||||
|
public static native void printString(String s);
|
||||||
|
|
||||||
|
@Import(name = "logInt", module = "teavm")
|
||||||
|
public static native void printInt(int i);
|
||||||
|
|
||||||
|
@Import(name = "logOutOfMemory", module = "teavm")
|
||||||
|
public static native void printOutOfMemory();
|
||||||
|
|
||||||
public static void fillZero(Address address, int count) {
|
public static void fillZero(Address address, int count) {
|
||||||
int start = address.toInt();
|
int start = address.toInt();
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@ import org.teavm.backend.wasm.generators.WasmMethodGeneratorContext;
|
||||||
import org.teavm.backend.wasm.intrinsics.AddressIntrinsic;
|
import org.teavm.backend.wasm.intrinsics.AddressIntrinsic;
|
||||||
import org.teavm.backend.wasm.intrinsics.AllocatorIntrinsic;
|
import org.teavm.backend.wasm.intrinsics.AllocatorIntrinsic;
|
||||||
import org.teavm.backend.wasm.intrinsics.ClassIntrinsic;
|
import org.teavm.backend.wasm.intrinsics.ClassIntrinsic;
|
||||||
|
import org.teavm.backend.wasm.intrinsics.ConsoleIntrinsic;
|
||||||
import org.teavm.backend.wasm.intrinsics.DoubleIntrinsic;
|
import org.teavm.backend.wasm.intrinsics.DoubleIntrinsic;
|
||||||
import org.teavm.backend.wasm.intrinsics.ExceptionHandlingIntrinsic;
|
import org.teavm.backend.wasm.intrinsics.ExceptionHandlingIntrinsic;
|
||||||
import org.teavm.backend.wasm.intrinsics.FloatIntrinsic;
|
import org.teavm.backend.wasm.intrinsics.FloatIntrinsic;
|
||||||
|
@ -269,6 +270,12 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
||||||
String[].class)).use();
|
String[].class)).use();
|
||||||
dependencyAnalyzer.linkMethod(new MethodReference(WasmRuntime.class, "lookupResource", Address.class,
|
dependencyAnalyzer.linkMethod(new MethodReference(WasmRuntime.class, "lookupResource", Address.class,
|
||||||
String.class, Address.class)).use();
|
String.class, Address.class)).use();
|
||||||
|
dependencyAnalyzer.linkMethod(new MethodReference(WasmRuntime.class, "printString",
|
||||||
|
String.class, void.class)).use();
|
||||||
|
dependencyAnalyzer.linkMethod(new MethodReference(WasmRuntime.class, "printInt",
|
||||||
|
int.class, void.class)).use();
|
||||||
|
dependencyAnalyzer.linkMethod(new MethodReference(WasmRuntime.class, "printOutOfMemory",
|
||||||
|
void.class)).use();
|
||||||
|
|
||||||
dependencyAnalyzer.linkMethod(new MethodReference(Allocator.class, "allocate",
|
dependencyAnalyzer.linkMethod(new MethodReference(Allocator.class, "allocate",
|
||||||
RuntimeClass.class, Address.class)).use();
|
RuntimeClass.class, Address.class)).use();
|
||||||
|
@ -344,6 +351,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
||||||
context.addIntrinsic(new LongIntrinsic());
|
context.addIntrinsic(new LongIntrinsic());
|
||||||
context.addIntrinsic(new IntegerIntrinsic());
|
context.addIntrinsic(new IntegerIntrinsic());
|
||||||
context.addIntrinsic(new ObjectIntrinsic());
|
context.addIntrinsic(new ObjectIntrinsic());
|
||||||
|
context.addIntrinsic(new ConsoleIntrinsic());
|
||||||
context.addGenerator(new ArrayGenerator());
|
context.addGenerator(new ArrayGenerator());
|
||||||
|
|
||||||
IntrinsicFactoryContext intrinsicFactoryContext = new IntrinsicFactoryContext();
|
IntrinsicFactoryContext intrinsicFactoryContext = new IntrinsicFactoryContext();
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2019 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.backend.wasm.intrinsics;
|
||||||
|
|
||||||
|
import org.teavm.ast.InvocationExpr;
|
||||||
|
import org.teavm.backend.wasm.WasmRuntime;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmCall;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmUnreachable;
|
||||||
|
import org.teavm.model.MethodReference;
|
||||||
|
import org.teavm.runtime.Console;
|
||||||
|
|
||||||
|
public class ConsoleIntrinsic implements WasmIntrinsic {
|
||||||
|
private static final MethodReference PRINT_STRING = new MethodReference(WasmRuntime.class,
|
||||||
|
"printString", String.class, void.class);
|
||||||
|
private static final MethodReference PRINT_INT = new MethodReference(WasmRuntime.class,
|
||||||
|
"printInt", int.class, void.class);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isApplicable(MethodReference methodReference) {
|
||||||
|
if (!methodReference.getClassName().equals(Console.class.getName())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (methodReference.getName()) {
|
||||||
|
case "printString":
|
||||||
|
case "printInt":
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WasmExpression apply(InvocationExpr invocation, WasmIntrinsicManager manager) {
|
||||||
|
switch (invocation.getMethod().getName()) {
|
||||||
|
case "printString": {
|
||||||
|
String name = manager.getNames().forMethod(PRINT_STRING);
|
||||||
|
WasmCall call = new WasmCall(name, true);
|
||||||
|
call.getArguments().add(manager.generate(invocation.getArguments().get(0)));
|
||||||
|
return call;
|
||||||
|
}
|
||||||
|
case "printInt": {
|
||||||
|
String name = manager.getNames().forMethod(PRINT_INT);
|
||||||
|
WasmCall call = new WasmCall(name, true);
|
||||||
|
call.getArguments().add(manager.generate(invocation.getArguments().get(0)));
|
||||||
|
return call;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return new WasmUnreachable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,13 +18,19 @@ package org.teavm.backend.wasm.intrinsics;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.teavm.ast.InvocationExpr;
|
import org.teavm.ast.InvocationExpr;
|
||||||
|
import org.teavm.backend.wasm.WasmRuntime;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmBlock;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmCall;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmInt32Constant;
|
import org.teavm.backend.wasm.model.expression.WasmInt32Constant;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmInt64Constant;
|
import org.teavm.backend.wasm.model.expression.WasmInt64Constant;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmUnreachable;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
import org.teavm.runtime.GC;
|
import org.teavm.runtime.GC;
|
||||||
|
|
||||||
public class GCIntrinsic implements WasmIntrinsic {
|
public class GCIntrinsic implements WasmIntrinsic {
|
||||||
|
private static final MethodReference PRINT_OUT_OF_MEMORY = new MethodReference(
|
||||||
|
WasmRuntime.class, "printOutOfMemory", void.class);
|
||||||
private List<WasmInt32Constant> heapAddressExpressions = new ArrayList<>();
|
private List<WasmInt32Constant> heapAddressExpressions = new ArrayList<>();
|
||||||
private List<WasmInt64Constant> availableBytesExpressions = new ArrayList<>();
|
private List<WasmInt64Constant> availableBytesExpressions = new ArrayList<>();
|
||||||
private List<WasmInt32Constant> gcStorageAddressExpressions = new ArrayList<>();
|
private List<WasmInt32Constant> gcStorageAddressExpressions = new ArrayList<>();
|
||||||
|
@ -89,6 +95,7 @@ public class GCIntrinsic implements WasmIntrinsic {
|
||||||
case "regionsAddress":
|
case "regionsAddress":
|
||||||
case "regionMaxCount":
|
case "regionMaxCount":
|
||||||
case "regionSize":
|
case "regionSize":
|
||||||
|
case "outOfMemory":
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
|
@ -122,6 +129,13 @@ public class GCIntrinsic implements WasmIntrinsic {
|
||||||
availableBytesExpressions.add(constant);
|
availableBytesExpressions.add(constant);
|
||||||
return constant;
|
return constant;
|
||||||
}
|
}
|
||||||
|
case "outOfMemory": {
|
||||||
|
WasmBlock block = new WasmBlock(false);
|
||||||
|
WasmCall call = new WasmCall(manager.getNames().forMethod(PRINT_OUT_OF_MEMORY), true);
|
||||||
|
block.getBody().add(call);
|
||||||
|
block.getBody().add(new WasmUnreachable());
|
||||||
|
return block;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException(invocation.getMethod().toString());
|
throw new IllegalArgumentException(invocation.getMethod().toString());
|
||||||
}
|
}
|
||||||
|
|
|
@ -337,6 +337,9 @@ public class WasmBinaryRenderer {
|
||||||
functionsSubsection.writeLEB(functions.size());
|
functionsSubsection.writeLEB(functions.size());
|
||||||
|
|
||||||
for (WasmFunction function : functions) {
|
for (WasmFunction function : functions) {
|
||||||
|
if (function.getImportName() != null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
functionsSubsection.writeLEB(functionIndexes.get(function.getName()));
|
functionsSubsection.writeLEB(functionIndexes.get(function.getName()));
|
||||||
functionsSubsection.writeAsciiString(function.getName());
|
functionsSubsection.writeAsciiString(function.getName());
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.runtime;
|
package org.teavm.runtime;
|
||||||
|
|
||||||
import org.teavm.interop.Address;
|
|
||||||
import org.teavm.interop.Import;
|
import org.teavm.interop.Import;
|
||||||
import org.teavm.interop.StaticInit;
|
import org.teavm.interop.StaticInit;
|
||||||
import org.teavm.interop.Unmanaged;
|
import org.teavm.interop.Unmanaged;
|
||||||
|
@ -26,8 +25,7 @@ public final class Console {
|
||||||
private Console() {
|
private Console() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Import(name = "teavm_printString")
|
public static native void printString(String s);
|
||||||
public static native void printString(Address ptr);
|
|
||||||
|
|
||||||
@Import(name = "teavm_printInt")
|
@Import(name = "teavm_printInt")
|
||||||
public static native void printInt(int n);
|
public static native void printInt(int n);
|
||||||
|
|
|
@ -18,7 +18,6 @@ package org.teavm.runtime;
|
||||||
import org.teavm.interop.Address;
|
import org.teavm.interop.Address;
|
||||||
import org.teavm.interop.Export;
|
import org.teavm.interop.Export;
|
||||||
import org.teavm.interop.StaticInit;
|
import org.teavm.interop.StaticInit;
|
||||||
import org.teavm.interop.Strings;
|
|
||||||
import org.teavm.interop.Structure;
|
import org.teavm.interop.Structure;
|
||||||
import org.teavm.interop.Unmanaged;
|
import org.teavm.interop.Unmanaged;
|
||||||
|
|
||||||
|
@ -36,21 +35,21 @@ public final class ExceptionHandling {
|
||||||
CallSite callSite = findCallSiteById(callSiteId);
|
CallSite callSite = findCallSiteById(callSiteId);
|
||||||
CallSiteLocation location = callSite.location;
|
CallSiteLocation location = callSite.location;
|
||||||
|
|
||||||
Console.printString(Strings.toC(" at "));
|
Console.printString(" at ");
|
||||||
if (location.className == null || location.methodName == null) {
|
if (location.className == null || location.methodName == null) {
|
||||||
Console.printString(Strings.toC("(Unknown method)"));
|
Console.printString("(Unknown method)");
|
||||||
} else {
|
} else {
|
||||||
Console.printString(Strings.toC(location.className));
|
Console.printString(location.className);
|
||||||
Console.printString(Strings.toC("."));
|
Console.printString(".");
|
||||||
Console.printString(Strings.toC(location.methodName));
|
Console.printString(location.methodName);
|
||||||
}
|
}
|
||||||
Console.printString(Strings.toC("("));
|
Console.printString("(");
|
||||||
if (location.fileName != null && location.lineNumber >= 0) {
|
if (location.fileName != null && location.lineNumber >= 0) {
|
||||||
Console.printString(Strings.toC(location.fileName));
|
Console.printString(location.fileName);
|
||||||
Console.printString(Strings.toC(":"));
|
Console.printString(":");
|
||||||
Console.printInt(location.lineNumber);
|
Console.printInt(location.lineNumber);
|
||||||
}
|
}
|
||||||
Console.printString(Strings.toC(")\n"));
|
Console.printString(")\n");
|
||||||
stackFrame = ShadowStack.getNextStackFrame(stackFrame);
|
stackFrame = ShadowStack.getNextStackFrame(stackFrame);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,17 @@ TeaVM.wasm = function() {
|
||||||
function getNativeOffset(instant) {
|
function getNativeOffset(instant) {
|
||||||
return new Date(instant).getTimezoneOffset();
|
return new Date(instant).getTimezoneOffset();
|
||||||
}
|
}
|
||||||
|
function logString(string) {
|
||||||
|
var memory = new DataView(logString.memory.buffer);
|
||||||
|
var arrayPtr = memory.getUint32(string + 8, true);
|
||||||
|
var length = memory.getUint32(arrayPtr + 8, true);
|
||||||
|
for (var i = 0; i < length; ++i) {
|
||||||
|
putwchar(memory.getUint16(i * 2 + arrayPtr + 12, true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function logInt(i) {
|
||||||
|
lineBuffer += i.toString();
|
||||||
|
}
|
||||||
|
|
||||||
function importDefaults(obj) {
|
function importDefaults(obj) {
|
||||||
obj.teavm = {
|
obj.teavm = {
|
||||||
|
@ -48,7 +59,10 @@ TeaVM.wasm = function() {
|
||||||
putwchar: putwchar,
|
putwchar: putwchar,
|
||||||
towlower: towlower,
|
towlower: towlower,
|
||||||
towupper: towupper,
|
towupper: towupper,
|
||||||
getNativeOffset: getNativeOffset
|
getNativeOffset: getNativeOffset,
|
||||||
|
logString: logString,
|
||||||
|
logInt: logInt,
|
||||||
|
logOutOfMemory: function() { console.log("Out of memory") }
|
||||||
};
|
};
|
||||||
|
|
||||||
obj.teavmMath = Math;
|
obj.teavmMath = Math;
|
||||||
|
@ -79,6 +93,7 @@ TeaVM.wasm = function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
WebAssembly.instantiate(response, importObj).then(function(resultObject) {
|
WebAssembly.instantiate(response, importObj).then(function(resultObject) {
|
||||||
|
importObj.teavm.logString.memory = resultObject.instance.exports.memory;
|
||||||
resultObject.instance.exports.main();
|
resultObject.instance.exports.main();
|
||||||
callback(resultObject);
|
callback(resultObject);
|
||||||
}).catch(function(error) {
|
}).catch(function(error) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user