wasm gc: minor optimizations; make initializer functions Wasm start function; fix compilation; remove debugging output

This commit is contained in:
Alexey Andreev 2024-10-06 17:29:27 +02:00
parent f95250ddf7
commit 73dda91d35
5 changed files with 61 additions and 146 deletions

View File

@ -17,17 +17,6 @@ package org.teavm.backend.wasm;
import org.teavm.backend.wasm.generate.gc.WasmGCDeclarationsGenerator;
import org.teavm.backend.wasm.model.WasmFunction;
import org.teavm.backend.wasm.model.WasmGlobal;
import org.teavm.backend.wasm.model.WasmLocal;
import org.teavm.backend.wasm.model.WasmType;
import org.teavm.backend.wasm.model.expression.WasmCall;
import org.teavm.backend.wasm.model.expression.WasmCallReference;
import org.teavm.backend.wasm.model.expression.WasmDrop;
import org.teavm.backend.wasm.model.expression.WasmExpression;
import org.teavm.backend.wasm.model.expression.WasmFunctionReference;
import org.teavm.backend.wasm.model.expression.WasmGetGlobal;
import org.teavm.backend.wasm.model.expression.WasmGetLocal;
import org.teavm.backend.wasm.model.expression.WasmSetGlobal;
import org.teavm.backend.wasm.runtime.StringInternPool;
import org.teavm.backend.wasm.runtime.gc.WasmGCSupport;
import org.teavm.model.MethodReference;
@ -35,8 +24,6 @@ import org.teavm.model.ValueType;
public class WasmGCModuleGenerator {
private WasmGCDeclarationsGenerator declarationsGenerator;
private WasmFunction initializer;
private WasmGlobal initializerRef;
public WasmGCModuleGenerator(WasmGCDeclarationsGenerator declarationsGenerator) {
this.declarationsGenerator = declarationsGenerator;
@ -44,166 +31,66 @@ public class WasmGCModuleGenerator {
public void generate() {
declarationsGenerator.generate();
if (initializer != null) {
fillInitializer();
}
createInitializer();
}
private void fillInitializer() {
declarationsGenerator.contributeToInitializer(initializer);
}
public WasmFunction generateMainFunction(String entryPoint) {
var mainFunction = declarationsGenerator.functions().forStaticMethod(new MethodReference(entryPoint,
return declarationsGenerator.functions().forStaticMethod(new MethodReference(entryPoint,
"main", ValueType.parse(String[].class), ValueType.VOID));
var stringArrayType = declarationsGenerator.typeMapper()
.mapType(ValueType.parse(String[].class));
var mainFunctionCaller = new WasmFunction(declarationsGenerator.functionTypes.of(null, stringArrayType));
var argsLocal = new WasmLocal(stringArrayType, "args");
declarationsGenerator.module.functions.add(mainFunctionCaller);
mainFunctionCaller.getBody().add(callInitializer());
var callToMainFunction = new WasmCall(mainFunction, new WasmGetLocal(argsLocal));
mainFunctionCaller.getBody().add(callToMainFunction);
return mainFunctionCaller;
}
public WasmFunction generateCreateStringBuilderFunction() {
var function = declarationsGenerator.functions().forStaticMethod(new MethodReference(
return declarationsGenerator.functions().forStaticMethod(new MethodReference(
WasmGCSupport.class, "createStringBuilder", StringBuilder.class));
var caller = new WasmFunction(function.getType());
caller.getBody().add(callInitializer());
caller.getBody().add(new WasmCall(function));
declarationsGenerator.module.functions.add(caller);
return caller;
}
public WasmFunction generateCreateStringArrayFunction() {
var function = declarationsGenerator.functions().forStaticMethod(new MethodReference(
return declarationsGenerator.functions().forStaticMethod(new MethodReference(
WasmGCSupport.class, "createStringArray", int.class, String[].class));
var caller = new WasmFunction(function.getType());
var sizeLocal = new WasmLocal(WasmType.INT32, "length");
caller.add(sizeLocal);
caller.getBody().add(callInitializer());
caller.getBody().add(new WasmCall(function, new WasmGetLocal(sizeLocal)));
declarationsGenerator.module.functions.add(caller);
return caller;
}
public WasmFunction generateAppendCharFunction() {
var function = declarationsGenerator.functions().forInstanceMethod(new MethodReference(
return declarationsGenerator.functions().forInstanceMethod(new MethodReference(
StringBuilder.class, "append", char.class, StringBuilder.class));
var stringBuilderType = declarationsGenerator.typeMapper().mapType(ValueType.parse(StringBuilder.class));
var caller = new WasmFunction(declarationsGenerator.functionTypes.of(null, stringBuilderType, WasmType.INT32));
var stringBuilderLocal = new WasmLocal(stringBuilderType, "stringBuilder");
var codeLocal = new WasmLocal(WasmType.INT32, "charCode");
caller.add(stringBuilderLocal);
caller.add(codeLocal);
caller.getBody().add(callInitializer());
caller.getBody().add(new WasmDrop(new WasmCall(function, new WasmGetLocal(stringBuilderLocal),
new WasmGetLocal(codeLocal))));
declarationsGenerator.module.functions.add(caller);
return caller;
}
public WasmFunction generateBuildStringFunction() {
var function = declarationsGenerator.functions().forInstanceMethod(new MethodReference(
return declarationsGenerator.functions().forInstanceMethod(new MethodReference(
StringBuilder.class, "toString", String.class));
var stringBuilderType = declarationsGenerator.typeMapper().mapType(ValueType.parse(StringBuilder.class));
var stringType = declarationsGenerator.typeMapper().mapType(ValueType.parse(String.class));
var caller = new WasmFunction(declarationsGenerator.functionTypes.of(stringType, stringBuilderType));
var stringBuilderLocal = new WasmLocal(stringBuilderType, "stringBuilder");
caller.add(stringBuilderLocal);
caller.getBody().add(callInitializer());
caller.getBody().add(new WasmCall(function, new WasmGetLocal(stringBuilderLocal)));
declarationsGenerator.module.functions.add(caller);
return caller;
}
public WasmFunction generateSetToStringArrayFunction() {
var function = declarationsGenerator.functions().forStaticMethod(new MethodReference(
return declarationsGenerator.functions().forStaticMethod(new MethodReference(
WasmGCSupport.class, "setToStringArray", String[].class, int.class, String.class, void.class));
var stringArrayType = declarationsGenerator.typeMapper().mapType(ValueType.parse(String[].class));
var stringType = declarationsGenerator.typeMapper().mapType(ValueType.parse(String.class));
var caller = new WasmFunction(function.getType());
var arrayLocal = new WasmLocal(stringArrayType, "array");
var indexLocal = new WasmLocal(WasmType.INT32, "index");
var valueLocal = new WasmLocal(stringType, "string");
caller.add(arrayLocal);
caller.add(indexLocal);
caller.add(valueLocal);
caller.getBody().add(callInitializer());
caller.getBody().add(new WasmCall(function, new WasmGetLocal(arrayLocal),
new WasmGetLocal(indexLocal), new WasmGetLocal(valueLocal)));
declarationsGenerator.module.functions.add(caller);
return caller;
}
public WasmFunction generateStringLengthFunction() {
var function = declarationsGenerator.functions().forInstanceMethod(new MethodReference(
return declarationsGenerator.functions().forInstanceMethod(new MethodReference(
String.class, "length", int.class));
var stringType = declarationsGenerator.typeMapper().mapType(ValueType.parse(String.class));
var caller = new WasmFunction(function.getType());
var stringLocal = new WasmLocal(stringType, "string");
caller.add(stringLocal);
caller.getBody().add(callInitializer());
caller.getBody().add(new WasmCall(function, new WasmGetLocal(stringLocal)));
declarationsGenerator.module.functions.add(caller);
return caller;
}
public WasmFunction generateCharAtFunction() {
var function = declarationsGenerator.functions().forInstanceMethod(new MethodReference(
return declarationsGenerator.functions().forInstanceMethod(new MethodReference(
String.class, "charAt", int.class, char.class));
var stringType = declarationsGenerator.typeMapper().mapType(ValueType.parse(String.class));
var caller = new WasmFunction(function.getType());
var stringLocal = new WasmLocal(stringType, "string");
var indexLocal = new WasmLocal(WasmType.INT32, "index");
caller.add(stringLocal);
caller.add(indexLocal);
caller.getBody().add(callInitializer());
caller.getBody().add(new WasmCall(function, new WasmGetLocal(stringLocal),
new WasmGetLocal(indexLocal)));
declarationsGenerator.module.functions.add(caller);
return caller;
}
public WasmFunction generateReportGarbageCollectedStringFunction() {
var entryType = ValueType.object(StringInternPool.class.getName() + "$Entry");
var function = declarationsGenerator.functions().forStaticMethod(new MethodReference(
return declarationsGenerator.functions().forStaticMethod(new MethodReference(
StringInternPool.class.getName(),
"remove",
entryType,
ValueType.VOID
));
var caller = new WasmFunction(function.getType());
var entryLocal = new WasmLocal(declarationsGenerator.typeMapper().mapType(entryType));
caller.add(entryLocal);
caller.getBody().add(callInitializer());
caller.getBody().add(new WasmCall(function, new WasmGetLocal(entryLocal)));
declarationsGenerator.module.functions.add(caller);
return caller;
}
private void createInitializer() {
if (initializer != null) {
return;
}
var functionType = declarationsGenerator.functionTypes.of(null);
initializer = new WasmFunction(functionType);
initializer.setReferenced(true);
var initializer = new WasmFunction(functionType);
initializer.setName("teavm@initializer");
declarationsGenerator.module.functions.add(initializer);
initializerRef = new WasmGlobal("teavm@initializerRef", functionType.getNonNullReference(),
new WasmFunctionReference(initializer));
declarationsGenerator.module.globals.add(initializerRef);
initializer.getBody().add(new WasmSetGlobal(initializerRef,
new WasmFunctionReference(declarationsGenerator.dummyInitializer())));
}
private WasmExpression callInitializer() {
createInitializer();
return new WasmCallReference(new WasmGetGlobal(initializerRef), declarationsGenerator.functionTypes.of(null));
declarationsGenerator.module.setStartFunction(initializer);
declarationsGenerator.contributeToInitializer(initializer);
}
}

View File

@ -48,7 +48,6 @@ public class DebugLinesBuilder extends DebugSectionBuilder implements DebugLines
public void location(String file, int line) {
if (Objects.equals(file, this.file) && this.ptr != lastWrittenPtr && this.line != line) {
if (this.ptr - lastWrittenPtr < 32 && Math.abs(line - this.line) <= 3) {
System.out.println(blob.ptr() + indent.toString() + "[user] ptr: " + this.ptr + ", line: " + line);
blob.writeByte(DebugConstants.LOC_USER + (this.ptr - lastWrittenPtr) + 32 * (line - this.line + 3));
this.line = line;
lastWrittenPtr = ptr;
@ -59,12 +58,10 @@ public class DebugLinesBuilder extends DebugSectionBuilder implements DebugLines
flushPtr();
this.line = 1;
this.file = file;
System.out.println(blob.ptr() + indent.toString() + "[file] " + file);
blob.writeByte(DebugConstants.LOC_FILE).writeLEB(file != null ? files.filePtr(file) : 0);
}
if (this.line != line) {
flushPtr();
System.out.println(blob.ptr() + indent.toString() + "[line] " + line);
blob.writeByte(DebugConstants.LOC_LINE).writeSLEB(line - this.line);
this.line = line;
}
@ -77,7 +74,6 @@ public class DebugLinesBuilder extends DebugSectionBuilder implements DebugLines
private void flushPtr() {
if (ptr != lastWrittenPtr) {
System.out.println(blob.ptr() + indent.toString() + "[ptr] " + ptr);
blob.writeLEB(DebugConstants.LOC_PTR);
blob.writeLEB(ptr - lastWrittenPtr);
lastWrittenPtr = ptr;
@ -87,7 +83,6 @@ public class DebugLinesBuilder extends DebugSectionBuilder implements DebugLines
@Override
public void start(MethodReference methodReference) {
flushPtr();
System.out.println(blob.ptr() + indent.toString() + "[start] method: " + methodReference);
indent.append(".");
blob.writeLEB(DebugConstants.LOC_START);
blob.writeLEB(methods.methodPtr(methodReference));
@ -100,7 +95,6 @@ public class DebugLinesBuilder extends DebugSectionBuilder implements DebugLines
public void end() {
flushPtr();
indent.setLength(indent.length() - 1);
System.out.println(blob.ptr() + indent.toString() + "[end]");
blob.writeLEB(DebugConstants.LOC_END);
if (!states.isEmpty()) {
var state = states.pop();

View File

@ -132,6 +132,7 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
private boolean async;
protected WasmExpression result;
protected List<WasmExpression> resultConsumer;
protected int blockLevel;
public BaseWasmGenerationVisitor(BaseWasmGenerationContext context, MethodReference currentMethod,
WasmFunction function, int firstVariable, boolean async) {
@ -591,9 +592,11 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
@Override
public void visit(ConditionalStatement statement) {
accept(statement.getCondition());
++blockLevel;
var conditional = new WasmConditional(forCondition(result));
visitMany(statement.getConsequent(), conditional.getThenBlock().getBody());
visitMany(statement.getAlternative(), conditional.getElseBlock().getBody());
--blockLevel;
resultConsumer.add(conditional);
}
@ -616,6 +619,7 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
.max().orElse(0);
var defaultBlock = new WasmBlock(false);
++blockLevel;
breakTargets.put(statement, defaultBlock);
var oldBreakTarget = currentBreakTarget;
currentBreakTarget = statement;
@ -651,6 +655,7 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
breakTargets.remove(statement);
currentBreakTarget = oldBreakTarget;
--blockLevel;
resultConsumer.add(wrapper);
}
@ -738,6 +743,7 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
var wrapper = new WasmBlock(false);
var loop = new WasmBlock(true);
++blockLevel;
continueTargets.put(statement, loop);
breakTargets.put(statement, wrapper);
var oldBreakTarget = currentBreakTarget;
@ -765,6 +771,8 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
} else {
resultConsumer.add(loop);
}
--blockLevel;
}
protected WasmExpression invocation(InvocationExpr expr, List<WasmExpression> resultConsumer, boolean willDrop) {
@ -957,6 +965,7 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
@Override
public void visit(BlockStatement statement) {
var block = new WasmBlock(false);
++blockLevel;
if (statement.getId() != null) {
breakTargets.put(statement, block);
@ -969,6 +978,7 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
}
resultConsumer.add(block);
--blockLevel;
}
@ -1053,9 +1063,15 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
} else {
result = null;
}
var wasmStatement = new WasmReturn(result);
wasmStatement.setLocation(statement.getLocation());
resultConsumer.add(wasmStatement);
if (blockLevel == 0) {
if (result != null) {
resultConsumer.add(result);
}
} else {
var wasmStatement = new WasmReturn(result);
wasmStatement.setLocation(statement.getLocation());
resultConsumer.add(wasmStatement);
}
}
protected WasmExpression forceType(WasmExpression expression, ValueType type) {
@ -1181,6 +1197,7 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
protected void generateTry(List<TryCatchStatement> tryCatchStatements, List<Statement> protectedBody) {
var throwableType = mapType(ValueType.object("java.lang.Throwable"));
var innerCatchBlock = new WasmBlock(false);
++blockLevel;
var catchBlocks = new ArrayList<WasmBlock>();
for (int i = 0; i < tryCatchStatements.size(); ++i) {
@ -1247,6 +1264,7 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
resultConsumer.add(outerCatchBlock);
tempVars.release(exceptionVar);
--blockLevel;
}
protected void checkExceptionType(TryCatchStatement tryCatch, WasmLocal exceptionVar, List<WasmExpression> target,

View File

@ -24,6 +24,7 @@ import org.teavm.ast.ArrayType;
import org.teavm.ast.BinaryExpr;
import org.teavm.ast.CastExpr;
import org.teavm.ast.ConditionalExpr;
import org.teavm.ast.ConstantExpr;
import org.teavm.ast.Expr;
import org.teavm.ast.InstanceOfExpr;
import org.teavm.ast.InvocationExpr;
@ -281,20 +282,12 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
if (expr.getType() == null) {
switch (expr.getOperation()) {
case EQUALS: {
accept(expr.getFirstOperand());
var first = result;
accept(expr.getSecondOperand());
var second = result;
result = new WasmReferencesEqual(first, second);
isReferenceEq(expr);
result.setLocation(expr.getLocation());
return;
}
case NOT_EQUALS:
accept(expr.getFirstOperand());
var first = result;
accept(expr.getSecondOperand());
var second = result;
result = new WasmReferencesEqual(first, second);
isReferenceEq(expr);
result = new WasmIntUnary(WasmIntType.INT32, WasmIntUnaryOperation.EQZ, result);
result.setLocation(expr.getLocation());
return;
@ -305,6 +298,29 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
super.visit(expr);
}
private void isReferenceEq(BinaryExpr expr) {
if (isNull(expr.getFirstOperand())) {
accept(expr.getSecondOperand());
result = new WasmIsNull(result);
} else if (isNull(expr.getSecondOperand())) {
accept(expr.getFirstOperand());
result = new WasmIsNull(result);
} else {
accept(expr.getFirstOperand());
var first = result;
accept(expr.getSecondOperand());
var second = result;
result = new WasmReferencesEqual(first, second);
}
}
private boolean isNull(Expr expr) {
if (!(expr instanceof ConstantExpr)) {
return false;
}
return ((ConstantExpr) expr).getValue() == null;
}
@Override
protected WasmExpression generateVirtualCall(WasmLocal instance, MethodReference method,
List<WasmExpression> arguments) {

View File

@ -1406,7 +1406,7 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
if (debugLines != null) {
debugLines.advance(writer.getPosition() + addressOffset);
while (!methodStack.isEmpty()) {
methodStack.removeLast();
methodStack.remove(methodStack.size() - 1);
debugLines.end();
}
debugLines.end();