mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14:10 -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.intrinsic.AddressIntrinsic;
|
||||
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.FunctionIntrinsic;
|
||||
import org.teavm.backend.c.intrinsic.GCIntrinsic;
|
||||
|
@ -293,6 +294,7 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
|
|||
intrinsics.add(new LongIntrinsic());
|
||||
intrinsics.add(new IntegerIntrinsic());
|
||||
intrinsics.add(new StringsIntrinsic());
|
||||
intrinsics.add(new ConsoleIntrinsic());
|
||||
|
||||
List<Generator> generators = new ArrayList<>();
|
||||
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")
|
||||
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) {
|
||||
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.AllocatorIntrinsic;
|
||||
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.ExceptionHandlingIntrinsic;
|
||||
import org.teavm.backend.wasm.intrinsics.FloatIntrinsic;
|
||||
|
@ -269,6 +270,12 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
|||
String[].class)).use();
|
||||
dependencyAnalyzer.linkMethod(new MethodReference(WasmRuntime.class, "lookupResource", Address.class,
|
||||
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",
|
||||
RuntimeClass.class, Address.class)).use();
|
||||
|
@ -344,6 +351,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
|||
context.addIntrinsic(new LongIntrinsic());
|
||||
context.addIntrinsic(new IntegerIntrinsic());
|
||||
context.addIntrinsic(new ObjectIntrinsic());
|
||||
context.addIntrinsic(new ConsoleIntrinsic());
|
||||
context.addGenerator(new ArrayGenerator());
|
||||
|
||||
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.List;
|
||||
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.WasmInt32Constant;
|
||||
import org.teavm.backend.wasm.model.expression.WasmInt64Constant;
|
||||
import org.teavm.backend.wasm.model.expression.WasmUnreachable;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.runtime.GC;
|
||||
|
||||
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<WasmInt64Constant> availableBytesExpressions = new ArrayList<>();
|
||||
private List<WasmInt32Constant> gcStorageAddressExpressions = new ArrayList<>();
|
||||
|
@ -89,6 +95,7 @@ public class GCIntrinsic implements WasmIntrinsic {
|
|||
case "regionsAddress":
|
||||
case "regionMaxCount":
|
||||
case "regionSize":
|
||||
case "outOfMemory":
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
@ -122,6 +129,13 @@ public class GCIntrinsic implements WasmIntrinsic {
|
|||
availableBytesExpressions.add(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:
|
||||
throw new IllegalArgumentException(invocation.getMethod().toString());
|
||||
}
|
||||
|
|
|
@ -337,6 +337,9 @@ public class WasmBinaryRenderer {
|
|||
functionsSubsection.writeLEB(functions.size());
|
||||
|
||||
for (WasmFunction function : functions) {
|
||||
if (function.getImportName() != null) {
|
||||
continue;
|
||||
}
|
||||
functionsSubsection.writeLEB(functionIndexes.get(function.getName()));
|
||||
functionsSubsection.writeAsciiString(function.getName());
|
||||
}
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
*/
|
||||
package org.teavm.runtime;
|
||||
|
||||
import org.teavm.interop.Address;
|
||||
import org.teavm.interop.Import;
|
||||
import org.teavm.interop.StaticInit;
|
||||
import org.teavm.interop.Unmanaged;
|
||||
|
@ -26,8 +25,7 @@ public final class Console {
|
|||
private Console() {
|
||||
}
|
||||
|
||||
@Import(name = "teavm_printString")
|
||||
public static native void printString(Address ptr);
|
||||
public static native void printString(String s);
|
||||
|
||||
@Import(name = "teavm_printInt")
|
||||
public static native void printInt(int n);
|
||||
|
|
|
@ -18,7 +18,6 @@ package org.teavm.runtime;
|
|||
import org.teavm.interop.Address;
|
||||
import org.teavm.interop.Export;
|
||||
import org.teavm.interop.StaticInit;
|
||||
import org.teavm.interop.Strings;
|
||||
import org.teavm.interop.Structure;
|
||||
import org.teavm.interop.Unmanaged;
|
||||
|
||||
|
@ -36,21 +35,21 @@ public final class ExceptionHandling {
|
|||
CallSite callSite = findCallSiteById(callSiteId);
|
||||
CallSiteLocation location = callSite.location;
|
||||
|
||||
Console.printString(Strings.toC(" at "));
|
||||
Console.printString(" at ");
|
||||
if (location.className == null || location.methodName == null) {
|
||||
Console.printString(Strings.toC("(Unknown method)"));
|
||||
Console.printString("(Unknown method)");
|
||||
} else {
|
||||
Console.printString(Strings.toC(location.className));
|
||||
Console.printString(Strings.toC("."));
|
||||
Console.printString(Strings.toC(location.methodName));
|
||||
Console.printString(location.className);
|
||||
Console.printString(".");
|
||||
Console.printString(location.methodName);
|
||||
}
|
||||
Console.printString(Strings.toC("("));
|
||||
Console.printString("(");
|
||||
if (location.fileName != null && location.lineNumber >= 0) {
|
||||
Console.printString(Strings.toC(location.fileName));
|
||||
Console.printString(Strings.toC(":"));
|
||||
Console.printString(location.fileName);
|
||||
Console.printString(":");
|
||||
Console.printInt(location.lineNumber);
|
||||
}
|
||||
Console.printString(Strings.toC(")\n"));
|
||||
Console.printString(")\n");
|
||||
stackFrame = ShadowStack.getNextStackFrame(stackFrame);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,6 +37,17 @@ TeaVM.wasm = function() {
|
|||
function getNativeOffset(instant) {
|
||||
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) {
|
||||
obj.teavm = {
|
||||
|
@ -48,7 +59,10 @@ TeaVM.wasm = function() {
|
|||
putwchar: putwchar,
|
||||
towlower: towlower,
|
||||
towupper: towupper,
|
||||
getNativeOffset: getNativeOffset
|
||||
getNativeOffset: getNativeOffset,
|
||||
logString: logString,
|
||||
logInt: logInt,
|
||||
logOutOfMemory: function() { console.log("Out of memory") }
|
||||
};
|
||||
|
||||
obj.teavmMath = Math;
|
||||
|
@ -79,6 +93,7 @@ TeaVM.wasm = function() {
|
|||
}
|
||||
|
||||
WebAssembly.instantiate(response, importObj).then(function(resultObject) {
|
||||
importObj.teavm.logString.memory = resultObject.instance.exports.memory;
|
||||
resultObject.instance.exports.main();
|
||||
callback(resultObject);
|
||||
}).catch(function(error) {
|
||||
|
|
Loading…
Reference in New Issue
Block a user