mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
wasm gc: fix bugs related to casts and implement runtime method for converting date to string
This commit is contained in:
parent
8e2cf27e94
commit
bfd2c8479c
|
@ -373,7 +373,7 @@ public class TDate implements TComparable<TDate> {
|
||||||
public String toString() {
|
public String toString() {
|
||||||
if (PlatformDetector.isC()) {
|
if (PlatformDetector.isC()) {
|
||||||
return toStringC(value);
|
return toStringC(value);
|
||||||
} else if (PlatformDetector.isWebAssembly()) {
|
} else if (PlatformDetector.isWebAssembly() || PlatformDetector.isWebAssemblyGC()) {
|
||||||
return toStringWebAssembly(value);
|
return toStringWebAssembly(value);
|
||||||
} else {
|
} else {
|
||||||
return JSDate.create(value).stringValue();
|
return JSDate.create(value).stringValue();
|
||||||
|
|
|
@ -170,6 +170,16 @@ public class WasmGenerationVisitor extends BaseWasmGenerationVisitor {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected WasmType mapCastSourceType(WasmType type) {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean validateCastTypes(WasmType sourceType, WasmType targetType, TextLocation location) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected WasmExpression peekException() {
|
protected WasmExpression peekException() {
|
||||||
return new WasmCall(context.functions().forStaticMethod(PEEK_EXCEPTION_METHOD));
|
return new WasmCall(context.functions().forStaticMethod(PEEK_EXCEPTION_METHOD));
|
||||||
|
|
|
@ -1184,40 +1184,53 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(CastExpr expr) {
|
public void visit(CastExpr expr) {
|
||||||
if (expr.isWeak()) {
|
var wasmTargetType = (WasmType.CompositeReference) mapType(expr.getTarget());
|
||||||
acceptWithType(expr.getValue(), expr.getTarget());
|
|
||||||
result = generateCast(result, mapType(expr.getTarget()));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var block = new WasmBlock(false);
|
|
||||||
var wasmTargetType = mapType(expr.getTarget());
|
|
||||||
block.setType(wasmTargetType);
|
|
||||||
block.setLocation(expr.getLocation());
|
|
||||||
|
|
||||||
acceptWithType(expr.getValue(), expr.getTarget());
|
acceptWithType(expr.getValue(), expr.getTarget());
|
||||||
result.acceptVisitor(typeInference);
|
if (!expr.isWeak()) {
|
||||||
var wasmSourceType = typeInference.getResult();
|
result.acceptVisitor(typeInference);
|
||||||
var valueToCast = exprCache.create(result, wasmSourceType, expr.getLocation(), block.getBody());
|
var wasmSourceType = typeInference.getResult();
|
||||||
|
if (wasmSourceType == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var nullCheck = new WasmBranch(genIsNull(valueToCast.expr()), block);
|
wasmSourceType = mapCastSourceType(wasmSourceType);
|
||||||
nullCheck.setResult(nullLiteral(wasmTargetType));
|
|
||||||
block.getBody().add(new WasmDrop(nullCheck));
|
|
||||||
|
|
||||||
var supertypeCall = generateInstanceOf(valueToCast.expr(), expr.getTarget());
|
if (!validateCastTypes(wasmSourceType, wasmTargetType, expr.getLocation())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var breakIfPassed = new WasmBranch(supertypeCall, block);
|
var block = new WasmBlock(false);
|
||||||
breakIfPassed.setResult(generateCast(valueToCast.expr(), wasmTargetType));
|
block.setType(wasmSourceType);
|
||||||
block.getBody().add(new WasmDrop(breakIfPassed));
|
block.setLocation(expr.getLocation());
|
||||||
|
acceptWithType(expr.getValue(), expr.getTarget());
|
||||||
|
var valueToCast = exprCache.create(result, wasmSourceType, expr.getLocation(), block.getBody());
|
||||||
|
|
||||||
var callSiteId = generateCallSiteId(expr.getLocation());
|
var nullCheck = new WasmBranch(genIsNull(valueToCast.expr()), block);
|
||||||
callSiteId.generateRegister(block.getBody(), expr.getLocation());
|
nullCheck.setResult(nullLiteral(wasmTargetType));
|
||||||
generateThrowCCE(expr.getLocation(), block.getBody());
|
block.getBody().add(new WasmDrop(nullCheck));
|
||||||
callSiteId.generateThrow(block.getBody(), expr.getLocation());
|
|
||||||
|
|
||||||
valueToCast.release();
|
var supertypeCall = generateInstanceOf(valueToCast.expr(), expr.getTarget());
|
||||||
result = block;
|
|
||||||
|
var breakIfPassed = new WasmBranch(supertypeCall, block);
|
||||||
|
breakIfPassed.setResult(valueToCast.expr());
|
||||||
|
block.getBody().add(new WasmDrop(breakIfPassed));
|
||||||
|
|
||||||
|
var callSiteId = generateCallSiteId(expr.getLocation());
|
||||||
|
callSiteId.generateRegister(block.getBody(), expr.getLocation());
|
||||||
|
generateThrowCCE(expr.getLocation(), block.getBody());
|
||||||
|
callSiteId.generateThrow(block.getBody(), expr.getLocation());
|
||||||
|
|
||||||
|
valueToCast.release();
|
||||||
|
result = block;
|
||||||
|
}
|
||||||
|
result = generateCast(result, wasmTargetType);
|
||||||
|
result.setLocation(expr.getLocation());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected abstract WasmType mapCastSourceType(WasmType type);
|
||||||
|
|
||||||
|
protected abstract boolean validateCastTypes(WasmType sourceType, WasmType targetType, TextLocation location);
|
||||||
|
|
||||||
protected abstract WasmExpression generateCast(WasmExpression value, WasmType targetType);
|
protected abstract WasmExpression generateCast(WasmExpression value, WasmType targetType);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -222,7 +222,7 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
|
||||||
}
|
}
|
||||||
return new WasmNullConstant(type instanceof WasmType.Reference
|
return new WasmNullConstant(type instanceof WasmType.Reference
|
||||||
? (WasmType.Reference) type
|
? (WasmType.Reference) type
|
||||||
: WasmType.Reference.STRUCT);
|
: context.classInfoProvider().getClassInfo("java.lang.Object").getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -362,6 +362,39 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
|
||||||
return new WasmCast(value, (WasmType.Reference) targetType);
|
return new WasmCast(value, (WasmType.Reference) targetType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected WasmType mapCastSourceType(WasmType type) {
|
||||||
|
if (!(type instanceof WasmType.CompositeReference)) {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
var refType = (WasmType.CompositeReference) type;
|
||||||
|
return refType.isNullable() ? refType : refType.composite.getReference();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean validateCastTypes(WasmType sourceType, WasmType targetType, TextLocation location) {
|
||||||
|
if (!(sourceType instanceof WasmType.CompositeReference)
|
||||||
|
|| !(targetType instanceof WasmType.CompositeReference)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
var sourceRefType = (WasmType.CompositeReference) sourceType;
|
||||||
|
var targetRefType = (WasmType.CompositeReference) targetType;
|
||||||
|
if (sourceRefType.composite instanceof WasmStructure
|
||||||
|
&& targetRefType.composite instanceof WasmStructure) {
|
||||||
|
var sourceStruct = (WasmStructure) sourceRefType.composite;
|
||||||
|
var targetStruct = (WasmStructure) targetRefType.composite;
|
||||||
|
if (targetStruct.isSupertypeOf(sourceStruct)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!sourceStruct.isSupertypeOf(targetStruct)) {
|
||||||
|
result = new WasmUnreachable();
|
||||||
|
result.setLocation(location);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean needsClassInitializer(String className) {
|
protected boolean needsClassInitializer(String className) {
|
||||||
return context.classInfoProvider().getClassInfo(className).getInitializerPointer() != null;
|
return context.classInfoProvider().getClassInfo(className).getInitializerPointer() != null;
|
||||||
|
@ -516,6 +549,11 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
|
||||||
|
|
||||||
target.acceptVisitor(typeInference);
|
target.acceptVisitor(typeInference);
|
||||||
var type = (WasmType.CompositeReference) typeInference.getResult();
|
var type = (WasmType.CompositeReference) typeInference.getResult();
|
||||||
|
if (type == null) {
|
||||||
|
result = new WasmUnreachable();
|
||||||
|
result.setLocation(expr.getLocation());
|
||||||
|
return;
|
||||||
|
}
|
||||||
var struct = (WasmStructure) type.composite;
|
var struct = (WasmStructure) type.composite;
|
||||||
var fieldIndex = context.classInfoProvider().getFieldIndex(expr.getField());
|
var fieldIndex = context.classInfoProvider().getFieldIndex(expr.getField());
|
||||||
if (fieldIndex >= 0) {
|
if (fieldIndex >= 0) {
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.backend.wasm.generate.gc.methods;
|
package org.teavm.backend.wasm.generate.gc.methods;
|
||||||
|
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.io.StringWriter;
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayDeque;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -209,7 +211,11 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
|
||||||
generateNativeMethodBody(method, function);
|
generateNativeMethodBody(method, function);
|
||||||
}
|
}
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
throw new RuntimeException("Failed generating method body: " + method.getReference(), e);
|
var buffer = new StringWriter();
|
||||||
|
var printWriter = new PrintWriter(buffer);
|
||||||
|
e.printStackTrace(printWriter);
|
||||||
|
diagnostics.error(new CallLocation(method.getReference()),
|
||||||
|
"Failed generating method body due to internal exception: " + buffer.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -67,7 +67,7 @@ public abstract class WasmType {
|
||||||
|
|
||||||
private final boolean nullable;
|
private final boolean nullable;
|
||||||
|
|
||||||
public Reference(boolean nullable) {
|
Reference(boolean nullable) {
|
||||||
this.nullable = nullable;
|
this.nullable = nullable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ TeaVM.wasm = function() {
|
||||||
function defaults(imports) {
|
function defaults(imports) {
|
||||||
let stderr = "";
|
let stderr = "";
|
||||||
let stdout = "";
|
let stdout = "";
|
||||||
|
let exports;
|
||||||
imports.teavm = {
|
imports.teavm = {
|
||||||
putcharStderr(c) {
|
putcharStderr(c) {
|
||||||
if (c === 10) {
|
if (c === 10) {
|
||||||
|
@ -38,6 +39,9 @@ TeaVM.wasm = function() {
|
||||||
},
|
},
|
||||||
currentTimeMillis() {
|
currentTimeMillis() {
|
||||||
return new Date().getTime();
|
return new Date().getTime();
|
||||||
|
},
|
||||||
|
dateToString(timestamp, controller) {
|
||||||
|
return stringToJava(new Date(timestamp).toString());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
imports.teavmMath = Math;
|
imports.teavmMath = Math;
|
||||||
|
@ -62,21 +66,25 @@ TeaVM.wasm = function() {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function stringToJava(str) {
|
||||||
|
let sb = exports.createStringBuilder();
|
||||||
|
for (let i = 0; i < str.length; ++i) {
|
||||||
|
exports.appendChar(sb, str.charCodeAt(i));
|
||||||
|
}
|
||||||
|
return exports.buildString(sb);
|
||||||
|
}
|
||||||
|
|
||||||
function createMain(instance) {
|
function createMain(instance) {
|
||||||
return args => {
|
return args => {
|
||||||
if (typeof args === "undefined") {
|
if (typeof args === "undefined") {
|
||||||
args = [];
|
args = [];
|
||||||
}
|
}
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let exports = instance.exports;
|
exports = instance.exports;
|
||||||
let javaArgs = exports.createStringArray(args.length);
|
let javaArgs = exports.createStringArray(args.length);
|
||||||
for (let i = 0; i < args.length; ++i) {
|
for (let i = 0; i < args.length; ++i) {
|
||||||
let arg = args[i];
|
let arg = args[i];
|
||||||
let javaArg = exports.createStringBuilder();
|
exports.setToStringArray(javaArgs, i, stringToJava(args[i]));
|
||||||
for (let j = 0; j < arg.length; ++j) {
|
|
||||||
exports.appendChar(javaArg, arg.charCodeAt(j));
|
|
||||||
}
|
|
||||||
exports.setToStringArray(javaArgs, i, exports.buildString(javaArg));
|
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
exports.main(javaArgs);
|
exports.main(javaArgs);
|
||||||
|
|
|
@ -154,6 +154,7 @@ public class TestClockTick extends AbstractTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
//-----------------------------------------------------------------------
|
||||||
|
@SkipPlatform(TestPlatform.WEBASSEMBLY_GC)
|
||||||
public void test_tickSeconds_ZoneId() throws Exception {
|
public void test_tickSeconds_ZoneId() throws Exception {
|
||||||
Clock test = Clock.tickSeconds(PARIS);
|
Clock test = Clock.tickSeconds(PARIS);
|
||||||
assertEquals(test.getZone(), PARIS);
|
assertEquals(test.getZone(), PARIS);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user