mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
wasm: implement transformation from TeaVM tree IR to Wasm GC
This commit is contained in:
parent
172de8e737
commit
f48c24283c
|
@ -127,6 +127,8 @@ import org.teavm.model.transformation.BoundCheckInsertion;
|
||||||
import org.teavm.model.transformation.ClassPatch;
|
import org.teavm.model.transformation.ClassPatch;
|
||||||
import org.teavm.model.transformation.NullCheckInsertion;
|
import org.teavm.model.transformation.NullCheckInsertion;
|
||||||
import org.teavm.model.util.AsyncMethodFinder;
|
import org.teavm.model.util.AsyncMethodFinder;
|
||||||
|
import org.teavm.model.util.DefaultVariableCategoryProvider;
|
||||||
|
import org.teavm.model.util.VariableCategoryProvider;
|
||||||
import org.teavm.runtime.Allocator;
|
import org.teavm.runtime.Allocator;
|
||||||
import org.teavm.runtime.CallSite;
|
import org.teavm.runtime.CallSite;
|
||||||
import org.teavm.runtime.CallSiteLocation;
|
import org.teavm.runtime.CallSiteLocation;
|
||||||
|
@ -259,8 +261,8 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean requiresRegisterAllocation() {
|
public VariableCategoryProvider variableCategoryProvider() {
|
||||||
return true;
|
return new DefaultVariableCategoryProvider();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -98,6 +98,8 @@ import org.teavm.model.instructions.StringConstantInstruction;
|
||||||
import org.teavm.model.transformation.BoundCheckInsertion;
|
import org.teavm.model.transformation.BoundCheckInsertion;
|
||||||
import org.teavm.model.transformation.NullCheckFilter;
|
import org.teavm.model.transformation.NullCheckFilter;
|
||||||
import org.teavm.model.transformation.NullCheckInsertion;
|
import org.teavm.model.transformation.NullCheckInsertion;
|
||||||
|
import org.teavm.model.util.DefaultVariableCategoryProvider;
|
||||||
|
import org.teavm.model.util.VariableCategoryProvider;
|
||||||
import org.teavm.vm.BuildTarget;
|
import org.teavm.vm.BuildTarget;
|
||||||
import org.teavm.vm.RenderingException;
|
import org.teavm.vm.RenderingException;
|
||||||
import org.teavm.vm.TeaVMTarget;
|
import org.teavm.vm.TeaVMTarget;
|
||||||
|
@ -223,8 +225,8 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean requiresRegisterAllocation() {
|
public VariableCategoryProvider variableCategoryProvider() {
|
||||||
return true;
|
return new DefaultVariableCategoryProvider();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setStackTraceIncluded(boolean stackTraceIncluded) {
|
public void setStackTraceIncluded(boolean stackTraceIncluded) {
|
||||||
|
|
|
@ -166,6 +166,8 @@ import org.teavm.model.transformation.BoundCheckInsertion;
|
||||||
import org.teavm.model.transformation.ClassPatch;
|
import org.teavm.model.transformation.ClassPatch;
|
||||||
import org.teavm.model.transformation.NullCheckInsertion;
|
import org.teavm.model.transformation.NullCheckInsertion;
|
||||||
import org.teavm.model.util.AsyncMethodFinder;
|
import org.teavm.model.util.AsyncMethodFinder;
|
||||||
|
import org.teavm.model.util.DefaultVariableCategoryProvider;
|
||||||
|
import org.teavm.model.util.VariableCategoryProvider;
|
||||||
import org.teavm.runtime.Allocator;
|
import org.teavm.runtime.Allocator;
|
||||||
import org.teavm.runtime.EventQueue;
|
import org.teavm.runtime.EventQueue;
|
||||||
import org.teavm.runtime.ExceptionHandling;
|
import org.teavm.runtime.ExceptionHandling;
|
||||||
|
@ -236,8 +238,8 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean requiresRegisterAllocation() {
|
public VariableCategoryProvider variableCategoryProvider() {
|
||||||
return true;
|
return new DefaultVariableCategoryProvider();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -146,8 +146,10 @@ public class WasmGenerationVisitor extends BaseWasmGenerationVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected WasmExpression generateThrowNPE() {
|
protected void generateThrowNPE(TextLocation location, List<WasmExpression> target) {
|
||||||
return new WasmCall(context.functions().forStaticMethod(THROW_NPE_METHOD));
|
var call = new WasmCall(context.functions().forStaticMethod(THROW_NPE_METHOD));
|
||||||
|
call.setLocation(location);
|
||||||
|
target.add(call);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -174,8 +176,17 @@ public class WasmGenerationVisitor extends BaseWasmGenerationVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected WasmExpression catchException() {
|
protected void catchException(TextLocation location, List<WasmExpression> target, WasmLocal local) {
|
||||||
return new WasmCall(context.functions().forStaticMethod(CATCH_METHOD));
|
var call = new WasmCall(context.functions().forStaticMethod(CATCH_METHOD));
|
||||||
|
if (local != null) {
|
||||||
|
var save = new WasmSetLocal(local, call);
|
||||||
|
save.setLocation(location);
|
||||||
|
target.add(save);
|
||||||
|
} else {
|
||||||
|
var drop = new WasmDrop(call);
|
||||||
|
drop.setLocation(location);
|
||||||
|
target.add(drop);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -494,8 +505,10 @@ public class WasmGenerationVisitor extends BaseWasmGenerationVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected WasmExpression generateThrow(WasmExpression expression) {
|
protected void generateThrow(WasmExpression expression, TextLocation location, List<WasmExpression> target) {
|
||||||
return new WasmCall(context.functions().forStaticMethod(THROW_METHOD), result);
|
var call = new WasmCall(context.functions().forStaticMethod(THROW_METHOD), result);
|
||||||
|
call.setLocation(location);
|
||||||
|
target.add(call);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class CallSiteIdentifierImpl extends CallSiteIdentifier
|
private class CallSiteIdentifierImpl extends CallSiteIdentifier
|
||||||
|
@ -745,18 +758,24 @@ public class WasmGenerationVisitor extends BaseWasmGenerationVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected WasmExpression allocateObject(String className, TextLocation location) {
|
protected void allocateObject(String className, TextLocation location, WasmLocal local,
|
||||||
|
List<WasmExpression> target) {
|
||||||
int tag = classGenerator.getClassPointer(ValueType.object(className));
|
int tag = classGenerator.getClassPointer(ValueType.object(className));
|
||||||
var allocFunction = context.functions().forStaticMethod(new MethodReference(Allocator.class, "allocate",
|
var allocFunction = context.functions().forStaticMethod(new MethodReference(Allocator.class, "allocate",
|
||||||
RuntimeClass.class, Address.class));
|
RuntimeClass.class, Address.class));
|
||||||
WasmCall call = new WasmCall(allocFunction);
|
WasmCall call = new WasmCall(allocFunction);
|
||||||
call.getArguments().add(new WasmInt32Constant(tag));
|
call.getArguments().add(new WasmInt32Constant(tag));
|
||||||
call.setLocation(location);
|
call.setLocation(location);
|
||||||
return call;
|
if (local != null) {
|
||||||
|
target.add(new WasmSetLocal(local, call));
|
||||||
|
} else {
|
||||||
|
target.add(call);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected WasmExpression allocateArray(ValueType itemType, WasmExpression length, TextLocation location) {
|
protected void allocateArray(ValueType itemType, WasmExpression length, TextLocation location, WasmLocal local,
|
||||||
|
List<WasmExpression> target) {
|
||||||
int classPointer = classGenerator.getClassPointer(ValueType.arrayOf(itemType));
|
int classPointer = classGenerator.getClassPointer(ValueType.arrayOf(itemType));
|
||||||
var allocFunction = context.functions().forStaticMethod(new MethodReference(Allocator.class, "allocateArray",
|
var allocFunction = context.functions().forStaticMethod(new MethodReference(Allocator.class, "allocateArray",
|
||||||
RuntimeClass.class, int.class, Address.class));
|
RuntimeClass.class, int.class, Address.class));
|
||||||
|
@ -764,7 +783,11 @@ public class WasmGenerationVisitor extends BaseWasmGenerationVisitor {
|
||||||
call.getArguments().add(new WasmInt32Constant(classPointer));
|
call.getArguments().add(new WasmInt32Constant(classPointer));
|
||||||
call.getArguments().add(length);
|
call.getArguments().add(length);
|
||||||
call.setLocation(location);
|
call.setLocation(location);
|
||||||
return call;
|
if (local != null) {
|
||||||
|
target.add(new WasmSetLocal(local, call));
|
||||||
|
} else {
|
||||||
|
target.add(call);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -822,8 +845,10 @@ public class WasmGenerationVisitor extends BaseWasmGenerationVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected WasmExpression generateThrowCCE() {
|
protected void generateThrowCCE(TextLocation location, List<WasmExpression> target) {
|
||||||
return new WasmCall(context.functions().forStaticMethod(THROW_CCE_METHOD));
|
var call = new WasmCall(context.functions().forStaticMethod(THROW_CCE_METHOD));
|
||||||
|
call.setLocation(location);
|
||||||
|
target.add(call);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -834,8 +859,8 @@ public class WasmGenerationVisitor extends BaseWasmGenerationVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean needsClassInitializer(String clasName) {
|
protected boolean needsClassInitializer(String className) {
|
||||||
return classGenerator.hasClinit(clasName);
|
return classGenerator.hasClinit(className);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -928,8 +953,10 @@ public class WasmGenerationVisitor extends BaseWasmGenerationVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected WasmExpression generateThrowAIOOBE() {
|
protected void generateThrowAIOOBE(TextLocation location, List<WasmExpression> target) {
|
||||||
return new WasmCall(context.functions().forStaticMethod(THROW_AIOOBE_METHOD));
|
var call = new WasmCall(context.functions().forStaticMethod(THROW_AIOOBE_METHOD));
|
||||||
|
call.setLocation(location);
|
||||||
|
target.add(call);
|
||||||
}
|
}
|
||||||
|
|
||||||
private WasmIntrinsicManager intrinsicManager = new WasmIntrinsicManager() {
|
private WasmIntrinsicManager intrinsicManager = new WasmIntrinsicManager() {
|
||||||
|
|
|
@ -125,7 +125,7 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
|
||||||
private Map<IdentifiedStatement, WasmBlock> continueTargets = new HashMap<>();
|
private Map<IdentifiedStatement, WasmBlock> continueTargets = new HashMap<>();
|
||||||
private Set<WasmBlock> usedBlocks = new HashSet<>();
|
private Set<WasmBlock> usedBlocks = new HashSet<>();
|
||||||
protected final TemporaryVariablePool tempVars;
|
protected final TemporaryVariablePool tempVars;
|
||||||
private ExpressionCache exprCache;
|
protected final ExpressionCache exprCache;
|
||||||
|
|
||||||
private boolean async;
|
private boolean async;
|
||||||
protected WasmExpression result;
|
protected WasmExpression result;
|
||||||
|
@ -459,14 +459,14 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
|
||||||
|
|
||||||
var callSiteId = generateCallSiteId(location);
|
var callSiteId = generateCallSiteId(location);
|
||||||
callSiteId.generateRegister(block.getBody(), location);
|
callSiteId.generateRegister(block.getBody(), location);
|
||||||
block.getBody().add(generateThrowNPE());
|
generateThrowNPE(location, block.getBody());
|
||||||
callSiteId.generateThrow(block.getBody(), location);
|
callSiteId.generateThrow(block.getBody(), location);
|
||||||
|
|
||||||
cachedValue.release();
|
cachedValue.release();
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract WasmExpression generateThrowNPE();
|
protected abstract void generateThrowNPE(TextLocation location, List<WasmExpression> target);
|
||||||
|
|
||||||
protected abstract WasmExpression generateArrayLength(WasmExpression array);
|
protected abstract WasmExpression generateArrayLength(WasmExpression array);
|
||||||
|
|
||||||
|
@ -852,8 +852,7 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
|
||||||
block.setType(resultType);
|
block.setType(resultType);
|
||||||
|
|
||||||
var tmp = tempVars.acquire(resultType);
|
var tmp = tempVars.acquire(resultType);
|
||||||
block.getBody().add(new WasmSetLocal(tmp, allocateObject(expr.getMethod().getClassName(),
|
allocateObject(expr.getMethod().getClassName(), expr.getLocation(), tmp, block.getBody());
|
||||||
expr.getLocation())));
|
|
||||||
|
|
||||||
var function = context.functions().forInstanceMethod(expr.getMethod());
|
var function = context.functions().forInstanceMethod(expr.getMethod());
|
||||||
var call = new WasmCall(function);
|
var call = new WasmCall(function);
|
||||||
|
@ -876,7 +875,7 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
|
||||||
accept(expr.getArguments().get(0));
|
accept(expr.getArguments().get(0));
|
||||||
var instance = result;
|
var instance = result;
|
||||||
var block = new WasmBlock(false);
|
var block = new WasmBlock(false);
|
||||||
block.setType(WasmGeneratorUtil.mapType(reference.getReturnType()));
|
block.setType(mapType(reference.getReturnType()));
|
||||||
|
|
||||||
var instanceVar = tempVars.acquire(WasmType.INT32);
|
var instanceVar = tempVars.acquire(WasmType.INT32);
|
||||||
block.getBody().add(new WasmSetLocal(instanceVar, instance));
|
block.getBody().add(new WasmSetLocal(instanceVar, instance));
|
||||||
|
@ -961,7 +960,7 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
|
||||||
block.setType(mapType(ValueType.object(expr.getConstructedClass())));
|
block.setType(mapType(ValueType.object(expr.getConstructedClass())));
|
||||||
var callSiteId = generateCallSiteId(expr.getLocation());
|
var callSiteId = generateCallSiteId(expr.getLocation());
|
||||||
callSiteId.generateRegister(block.getBody(), expr.getLocation());
|
callSiteId.generateRegister(block.getBody(), expr.getLocation());
|
||||||
block.getBody().add(allocateObject(expr.getConstructedClass(), expr.getLocation()));
|
allocateObject(expr.getConstructedClass(), expr.getLocation(), null, block.getBody());
|
||||||
if (block.getBody().size() == 1) {
|
if (block.getBody().size() == 1) {
|
||||||
result = block.getBody().get(0);
|
result = block.getBody().get(0);
|
||||||
} else {
|
} else {
|
||||||
|
@ -969,7 +968,8 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract WasmExpression allocateObject(String className, TextLocation location);
|
protected abstract void allocateObject(String className, TextLocation location, WasmLocal local,
|
||||||
|
List<WasmExpression> target);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(NewArrayExpr expr) {
|
public void visit(NewArrayExpr expr) {
|
||||||
|
@ -981,8 +981,7 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
|
||||||
|
|
||||||
accept(expr.getLength());
|
accept(expr.getLength());
|
||||||
var length = result;
|
var length = result;
|
||||||
var call = allocateArray(expr.getType(), length, expr.getLocation());
|
allocateArray(expr.getType(), length, expr.getLocation(), null, block.getBody());
|
||||||
block.getBody().add(call);
|
|
||||||
|
|
||||||
if (block.getBody().size() == 1) {
|
if (block.getBody().size() == 1) {
|
||||||
result = block.getBody().get(0);
|
result = block.getBody().get(0);
|
||||||
|
@ -991,7 +990,8 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract WasmExpression allocateArray(ValueType itemType, WasmExpression length, TextLocation location);
|
protected abstract void allocateArray(ValueType itemType, WasmExpression length, TextLocation location,
|
||||||
|
WasmLocal local, List<WasmExpression> target);
|
||||||
|
|
||||||
protected abstract WasmExpression allocateMultiArray(List<WasmExpression> target, ValueType itemType,
|
protected abstract WasmExpression allocateMultiArray(List<WasmExpression> target, ValueType itemType,
|
||||||
List<WasmExpression> dimensions, TextLocation location);
|
List<WasmExpression> dimensions, TextLocation location);
|
||||||
|
@ -1035,9 +1035,8 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
|
||||||
callSiteId.generateRegister(block.getBody(), expr.getLocation());
|
callSiteId.generateRegister(block.getBody(), expr.getLocation());
|
||||||
|
|
||||||
var array = tempVars.acquire(wasmArrayType);
|
var array = tempVars.acquire(wasmArrayType);
|
||||||
var allocation = allocateArray(expr.getType(), new WasmInt32Constant(expr.getData().size()),
|
allocateArray(expr.getType(), new WasmInt32Constant(expr.getData().size()), expr.getLocation(), array,
|
||||||
expr.getLocation());
|
block.getBody());
|
||||||
block.getBody().add(new WasmSetLocal(array, allocation));
|
|
||||||
|
|
||||||
for (int i = 0; i < expr.getData().size(); ++i) {
|
for (int i = 0; i < expr.getData().size(); ++i) {
|
||||||
expr.getData().get(i).acceptVisitor(this);
|
expr.getData().get(i).acceptVisitor(this);
|
||||||
|
@ -1117,13 +1116,12 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
|
||||||
callSiteId.generateRegister(resultConsumer, statement.getLocation());
|
callSiteId.generateRegister(resultConsumer, statement.getLocation());
|
||||||
|
|
||||||
accept(statement.getException());
|
accept(statement.getException());
|
||||||
var call = generateThrow(result);
|
generateThrow(result, statement.getLocation(), resultConsumer);
|
||||||
call.setLocation(statement.getLocation());
|
|
||||||
resultConsumer.add(call);
|
|
||||||
callSiteId.generateThrow(resultConsumer, statement.getLocation());
|
callSiteId.generateThrow(resultConsumer, statement.getLocation());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract WasmExpression generateThrow(WasmExpression expression);
|
protected abstract void generateThrow(WasmExpression expression, TextLocation location,
|
||||||
|
List<WasmExpression> target);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(CastExpr expr) {
|
public void visit(CastExpr expr) {
|
||||||
|
@ -1149,7 +1147,7 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
|
||||||
|
|
||||||
var callSiteId = generateCallSiteId(expr.getLocation());
|
var callSiteId = generateCallSiteId(expr.getLocation());
|
||||||
callSiteId.generateRegister(block.getBody(), expr.getLocation());
|
callSiteId.generateRegister(block.getBody(), expr.getLocation());
|
||||||
block.getBody().add(generateThrowCCE());
|
generateThrowCCE(expr.getLocation(), block.getBody());
|
||||||
callSiteId.generateThrow(block.getBody(), expr.getLocation());
|
callSiteId.generateThrow(block.getBody(), expr.getLocation());
|
||||||
|
|
||||||
valueToCast.release();
|
valueToCast.release();
|
||||||
|
@ -1168,7 +1166,7 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract boolean needsClassInitializer(String clasName);
|
protected abstract boolean needsClassInitializer(String className);
|
||||||
|
|
||||||
protected abstract WasmExpression generateClassInitializer(String className, TextLocation location);
|
protected abstract WasmExpression generateClassInitializer(String className, TextLocation location);
|
||||||
|
|
||||||
|
@ -1245,11 +1243,10 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
|
||||||
var catchBlock = catchBlocks.get(i);
|
var catchBlock = catchBlocks.get(i);
|
||||||
catchBlock.getBody().add(currentBlock);
|
catchBlock.getBody().add(currentBlock);
|
||||||
|
|
||||||
var catchCall = catchException();
|
var catchLocal = tryCatch.getExceptionVariable() != null
|
||||||
var catchWrapper = tryCatch.getExceptionVariable() != null
|
? localVar(tryCatch.getExceptionVariable())
|
||||||
? new WasmSetLocal(localVar(tryCatch.getExceptionVariable()), catchCall)
|
: null;
|
||||||
: new WasmDrop(catchCall);
|
catchException(null, catchBlock.getBody(), catchLocal);
|
||||||
catchBlock.getBody().add(catchWrapper);
|
|
||||||
visitMany(tryCatch.getHandler(), catchBlock.getBody());
|
visitMany(tryCatch.getHandler(), catchBlock.getBody());
|
||||||
if (!catchBlock.isTerminating() && catchBlock != outerCatchBlock) {
|
if (!catchBlock.isTerminating() && catchBlock != outerCatchBlock) {
|
||||||
catchBlock.getBody().add(new WasmBreak(outerCatchBlock));
|
catchBlock.getBody().add(new WasmBreak(outerCatchBlock));
|
||||||
|
@ -1262,7 +1259,7 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
|
||||||
|
|
||||||
protected abstract WasmExpression peekException();
|
protected abstract WasmExpression peekException();
|
||||||
|
|
||||||
protected abstract WasmExpression catchException();
|
protected abstract void catchException(TextLocation location, List<WasmExpression> target, WasmLocal local);
|
||||||
|
|
||||||
private void visitMany(List<Statement> statements, List<WasmExpression> target) {
|
private void visitMany(List<Statement> statements, List<WasmExpression> target) {
|
||||||
var oldTarget = resultConsumer;
|
var oldTarget = resultConsumer;
|
||||||
|
@ -1346,15 +1343,15 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
|
||||||
|
|
||||||
var callSiteId = generateCallSiteId(expr.getLocation());
|
var callSiteId = generateCallSiteId(expr.getLocation());
|
||||||
callSiteId.generateRegister(block.getBody(), expr.getLocation());
|
callSiteId.generateRegister(block.getBody(), expr.getLocation());
|
||||||
block.getBody().add(generateThrowAIOOBE());
|
generateThrowAIOOBE(expr.getLocation(), block.getBody());
|
||||||
callSiteId.generateThrow(block.getBody(), expr.getLocation());
|
callSiteId.generateThrow(block.getBody(), expr.getLocation());
|
||||||
|
|
||||||
result = block;
|
result = block;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract WasmExpression generateThrowAIOOBE();
|
protected abstract void generateThrowAIOOBE(TextLocation location, List<WasmExpression> target);
|
||||||
|
|
||||||
protected abstract WasmExpression generateThrowCCE();
|
protected abstract void generateThrowCCE(TextLocation location, List<WasmExpression> target);
|
||||||
|
|
||||||
private static WasmExpression negate(WasmExpression expr) {
|
private static WasmExpression negate(WasmExpression expr) {
|
||||||
if (expr instanceof WasmIntBinary) {
|
if (expr instanceof WasmIntBinary) {
|
||||||
|
|
|
@ -0,0 +1,130 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 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.generate.gc;
|
||||||
|
|
||||||
|
import org.teavm.backend.wasm.WasmFunctionRepository;
|
||||||
|
import org.teavm.backend.wasm.WasmFunctionTypes;
|
||||||
|
import org.teavm.backend.wasm.generate.common.methods.BaseWasmGenerationContext;
|
||||||
|
import org.teavm.backend.wasm.generate.gc.classes.WasmGCClassInfoProvider;
|
||||||
|
import org.teavm.backend.wasm.generate.gc.classes.WasmGCStandardClasses;
|
||||||
|
import org.teavm.backend.wasm.generate.gc.classes.WasmGCTypeMapper;
|
||||||
|
import org.teavm.backend.wasm.generate.gc.strings.WasmGCStringProvider;
|
||||||
|
import org.teavm.backend.wasm.model.WasmFunction;
|
||||||
|
import org.teavm.backend.wasm.model.WasmGlobal;
|
||||||
|
import org.teavm.backend.wasm.model.WasmModule;
|
||||||
|
import org.teavm.backend.wasm.model.WasmTag;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmNullConstant;
|
||||||
|
import org.teavm.backend.wasm.runtime.WasmGCSupport;
|
||||||
|
import org.teavm.model.ClassReaderSource;
|
||||||
|
import org.teavm.model.MethodReference;
|
||||||
|
import org.teavm.model.classes.VirtualTableProvider;
|
||||||
|
|
||||||
|
public class WasmGCGenerationContext implements BaseWasmGenerationContext {
|
||||||
|
private WasmModule module;
|
||||||
|
private WasmGCClassInfoProvider classInfoProvider;
|
||||||
|
private WasmGCStandardClasses standardClasses;
|
||||||
|
private WasmGCStringProvider strings;
|
||||||
|
private VirtualTableProvider virtualTables;
|
||||||
|
private WasmGCTypeMapper typeMapper;
|
||||||
|
private WasmFunction npeMethod;
|
||||||
|
private WasmFunction aaiobeMethod;
|
||||||
|
private WasmFunction cceMethod;
|
||||||
|
private WasmGlobal exceptionGlobal;
|
||||||
|
|
||||||
|
public WasmGCGenerationContext(WasmModule module, WasmGCClassInfoProvider classInfoProvider,
|
||||||
|
WasmGCStandardClasses standardClasses, WasmGCStringProvider strings, VirtualTableProvider virtualTables,
|
||||||
|
WasmGCTypeMapper typeMapper) {
|
||||||
|
this.module = module;
|
||||||
|
this.classInfoProvider = classInfoProvider;
|
||||||
|
this.standardClasses = standardClasses;
|
||||||
|
this.strings = strings;
|
||||||
|
this.virtualTables = virtualTables;
|
||||||
|
this.typeMapper = typeMapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public WasmGCClassInfoProvider classInfoProvider() {
|
||||||
|
return classInfoProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public WasmGCStandardClasses standardClasses() {
|
||||||
|
return standardClasses;
|
||||||
|
}
|
||||||
|
|
||||||
|
public WasmGCStringProvider strings() {
|
||||||
|
return strings;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VirtualTableProvider virtualTables() {
|
||||||
|
return virtualTables;
|
||||||
|
}
|
||||||
|
|
||||||
|
public WasmGCTypeMapper typeMapper() {
|
||||||
|
return typeMapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WasmFunctionRepository functions() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WasmFunctionTypes functionTypes() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WasmTag getExceptionTag() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClassReaderSource classSource() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public WasmFunction npeMethod() {
|
||||||
|
if (npeMethod == null) {
|
||||||
|
npeMethod = functions().forStaticMethod(new MethodReference(WasmGCSupport.class, "npe",
|
||||||
|
NullPointerException.class));
|
||||||
|
}
|
||||||
|
return npeMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public WasmFunction aaiobeMethod() {
|
||||||
|
if (aaiobeMethod == null) {
|
||||||
|
aaiobeMethod = functions().forStaticMethod(new MethodReference(WasmGCSupport.class, "aaiobe",
|
||||||
|
ArrayIndexOutOfBoundsException.class));
|
||||||
|
}
|
||||||
|
return aaiobeMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public WasmFunction cceMethod() {
|
||||||
|
if (cceMethod == null) {
|
||||||
|
cceMethod = functions().forStaticMethod(new MethodReference(WasmGCSupport.class, "cce",
|
||||||
|
ClassCastException.class));
|
||||||
|
}
|
||||||
|
return cceMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public WasmGlobal exceptionGlobal() {
|
||||||
|
if (exceptionGlobal == null) {
|
||||||
|
var type = classInfoProvider.getClassInfo("java.lang.Throwable").getType();
|
||||||
|
exceptionGlobal = new WasmGlobal("teavm_thrown_exception", type, new WasmNullConstant(type));
|
||||||
|
module.globals.add(exceptionGlobal);
|
||||||
|
}
|
||||||
|
return exceptionGlobal;
|
||||||
|
}
|
||||||
|
}
|
|
@ -54,6 +54,7 @@ import org.teavm.model.FieldReference;
|
||||||
import org.teavm.model.MethodDescriptor;
|
import org.teavm.model.MethodDescriptor;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
import org.teavm.model.ValueType;
|
import org.teavm.model.ValueType;
|
||||||
|
import org.teavm.model.analysis.ClassInitializerInfo;
|
||||||
import org.teavm.model.analysis.ClassMetadataRequirements;
|
import org.teavm.model.analysis.ClassMetadataRequirements;
|
||||||
import org.teavm.model.classes.TagRegistry;
|
import org.teavm.model.classes.TagRegistry;
|
||||||
import org.teavm.model.classes.VirtualTable;
|
import org.teavm.model.classes.VirtualTable;
|
||||||
|
@ -61,7 +62,7 @@ import org.teavm.model.classes.VirtualTableProvider;
|
||||||
import org.teavm.model.util.ReflectionUtil;
|
import org.teavm.model.util.ReflectionUtil;
|
||||||
|
|
||||||
public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInitializerContributor {
|
public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInitializerContributor {
|
||||||
public static final int CLASS_FIELD_OFFSET = 0;
|
private static final MethodDescriptor CLINIT_METHOD_DESC = new MethodDescriptor("<clinit>", ValueType.VOID);
|
||||||
|
|
||||||
private final WasmModule module;
|
private final WasmModule module;
|
||||||
private ClassReaderSource classSource;
|
private ClassReaderSource classSource;
|
||||||
|
@ -73,6 +74,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
private Map<ValueType, WasmGCClassInfo> classInfoMap = new LinkedHashMap<>();
|
private Map<ValueType, WasmGCClassInfo> classInfoMap = new LinkedHashMap<>();
|
||||||
private ObjectIntMap<FieldReference> fieldIndexes = new ObjectIntHashMap<>();
|
private ObjectIntMap<FieldReference> fieldIndexes = new ObjectIntHashMap<>();
|
||||||
private ObjectIntMap<MethodReference> methodIndexes = new ObjectIntHashMap<>();
|
private ObjectIntMap<MethodReference> methodIndexes = new ObjectIntHashMap<>();
|
||||||
|
private ClassInitializerInfo classInitializerInfo;
|
||||||
|
|
||||||
public final WasmGCStringPool strings;
|
public final WasmGCStringPool strings;
|
||||||
public final WasmGCStandardClasses standardClasses;
|
public final WasmGCStandardClasses standardClasses;
|
||||||
|
@ -95,7 +97,8 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
public WasmGCClassGenerator(WasmModule module, ClassReaderSource classSource,
|
public WasmGCClassGenerator(WasmModule module, ClassReaderSource classSource,
|
||||||
WasmFunctionTypes functionTypes, TagRegistry tagRegistry,
|
WasmFunctionTypes functionTypes, TagRegistry tagRegistry,
|
||||||
ClassMetadataRequirements metadataRequirements, VirtualTableProvider virtualTables,
|
ClassMetadataRequirements metadataRequirements, VirtualTableProvider virtualTables,
|
||||||
WasmGCFunctionProvider functionProvider, NameProvider names) {
|
WasmGCFunctionProvider functionProvider, NameProvider names,
|
||||||
|
ClassInitializerInfo classInitializerInfo) {
|
||||||
this.module = module;
|
this.module = module;
|
||||||
this.classSource = classSource;
|
this.classSource = classSource;
|
||||||
this.functionTypes = functionTypes;
|
this.functionTypes = functionTypes;
|
||||||
|
@ -104,6 +107,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
this.virtualTables = virtualTables;
|
this.virtualTables = virtualTables;
|
||||||
this.functionProvider = functionProvider;
|
this.functionProvider = functionProvider;
|
||||||
this.names = names;
|
this.names = names;
|
||||||
|
this.classInitializerInfo = classInitializerInfo;
|
||||||
standardClasses = new WasmGCStandardClasses(this);
|
standardClasses = new WasmGCStandardClasses(this);
|
||||||
strings = new WasmGCStringPool(standardClasses, module, functionProvider);
|
strings = new WasmGCStringPool(standardClasses, module, functionProvider);
|
||||||
supertypeGenerator = new WasmGCSupertypeFunctionGenerator(module, this, names, tagRegistry, functionTypes);
|
supertypeGenerator = new WasmGCSupertypeFunctionGenerator(module, this, names, tagRegistry, functionTypes);
|
||||||
|
@ -128,6 +132,13 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
new WasmFunctionReference(supertypeFunction)));
|
new WasmFunctionReference(supertypeFunction)));
|
||||||
function.getBody().add(setClassField(classInfo, CLASS_FIELD_OFFSET,
|
function.getBody().add(setClassField(classInfo, CLASS_FIELD_OFFSET,
|
||||||
new WasmGetGlobal(classClass.pointer)));
|
new WasmGetGlobal(classClass.pointer)));
|
||||||
|
if (classInfo.initializerPointer != null) {
|
||||||
|
var className = ((ValueType.Object) classInfo.getValueType()).getClassName();
|
||||||
|
var initFunction = functionProvider.getStaticFunction(new MethodReference(className,
|
||||||
|
CLINIT_METHOD_DESC));
|
||||||
|
function.getBody().add(new WasmSetGlobal(classInfo.initializerPointer,
|
||||||
|
new WasmFunctionReference(initFunction)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,6 +235,14 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initRegularClass(WasmGCClassInfo classInfo, WasmStructure classStructure, String name) {
|
private void initRegularClass(WasmGCClassInfo classInfo, WasmStructure classStructure, String name) {
|
||||||
|
var cls = classSource.get(name);
|
||||||
|
if (classInitializerInfo.isDynamicInitializer(name)) {
|
||||||
|
if (cls != null && cls.getMethod(CLINIT_METHOD_DESC) != null) {
|
||||||
|
var clinitType = functionTypes.of(null);
|
||||||
|
classInfo.initializerPointer = new WasmGlobal(null, clinitType.getReference(),
|
||||||
|
new WasmNullConstant(clinitType.getReference()));
|
||||||
|
}
|
||||||
|
}
|
||||||
classInfo.initializer = target -> {
|
classInfo.initializer = target -> {
|
||||||
var ranges = tagRegistry.getRanges(name);
|
var ranges = tagRegistry.getRanges(name);
|
||||||
int tag = ranges.stream().mapToInt(range -> range.lower).min().orElse(0);
|
int tag = ranges.stream().mapToInt(range -> range.lower).min().orElse(0);
|
||||||
|
@ -233,7 +252,6 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
var namePtr = strings.getStringConstant(name).global;
|
var namePtr = strings.getStringConstant(name).global;
|
||||||
target.add(setClassField(classInfo, classNameOffset, new WasmGetGlobal(namePtr)));
|
target.add(setClassField(classInfo, classNameOffset, new WasmGetGlobal(namePtr)));
|
||||||
}
|
}
|
||||||
var cls = classSource.get(name);
|
|
||||||
if (cls != null) {
|
if (cls != null) {
|
||||||
if (metadataReg.simpleName() && cls.getSimpleName() != null) {
|
if (metadataReg.simpleName() && cls.getSimpleName() != null) {
|
||||||
var namePtr = strings.getStringConstant(cls.getSimpleName()).global;
|
var namePtr = strings.getStringConstant(cls.getSimpleName()).global;
|
||||||
|
@ -334,6 +352,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getFieldIndex(FieldReference fieldRef) {
|
public int getFieldIndex(FieldReference fieldRef) {
|
||||||
var result = fieldIndexes.getOrDefault(fieldRef, -1);
|
var result = fieldIndexes.getOrDefault(fieldRef, -1);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
|
@ -342,6 +361,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getVirtualMethodIndex(MethodReference methodRef) {
|
public int getVirtualMethodIndex(MethodReference methodRef) {
|
||||||
var result = methodIndexes.getOrDefault(methodRef, -1);
|
var result = methodIndexes.getOrDefault(methodRef, -1);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
|
|
|
@ -28,6 +28,7 @@ public class WasmGCClassInfo {
|
||||||
WasmStructure structure;
|
WasmStructure structure;
|
||||||
WasmStructure virtualTableStructure;
|
WasmStructure virtualTableStructure;
|
||||||
WasmGlobal pointer;
|
WasmGlobal pointer;
|
||||||
|
WasmGlobal initializerPointer;
|
||||||
Consumer<List<WasmExpression>> initializer;
|
Consumer<List<WasmExpression>> initializer;
|
||||||
|
|
||||||
WasmGCClassInfo(ValueType valueType) {
|
WasmGCClassInfo(ValueType valueType) {
|
||||||
|
@ -53,4 +54,8 @@ public class WasmGCClassInfo {
|
||||||
public WasmGlobal getPointer() {
|
public WasmGlobal getPointer() {
|
||||||
return pointer;
|
return pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public WasmGlobal getInitializerPointer() {
|
||||||
|
return initializerPointer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,11 +15,21 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.backend.wasm.generate.gc.classes;
|
package org.teavm.backend.wasm.generate.gc.classes;
|
||||||
|
|
||||||
|
import org.teavm.model.FieldReference;
|
||||||
|
import org.teavm.model.MethodReference;
|
||||||
import org.teavm.model.ValueType;
|
import org.teavm.model.ValueType;
|
||||||
|
|
||||||
public interface WasmGCClassInfoProvider {
|
public interface WasmGCClassInfoProvider {
|
||||||
|
int CLASS_FIELD_OFFSET = 0;
|
||||||
|
int MONITOR_FIELD_OFFSET = 1;
|
||||||
|
int ARRAY_DATA_FIELD_OFFSET = 2;
|
||||||
|
|
||||||
WasmGCClassInfo getClassInfo(ValueType type);
|
WasmGCClassInfo getClassInfo(ValueType type);
|
||||||
|
|
||||||
|
int getFieldIndex(FieldReference fieldRef);
|
||||||
|
|
||||||
|
int getVirtualMethodIndex(MethodReference methodRef);
|
||||||
|
|
||||||
default WasmGCClassInfo getClassInfo(String name) {
|
default WasmGCClassInfo getClassInfo(String name) {
|
||||||
return getClassInfo(ValueType.object(name));
|
return getClassInfo(ValueType.object(name));
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,381 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 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.generate.gc.methods;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import org.teavm.ast.ArrayType;
|
||||||
|
import org.teavm.ast.Expr;
|
||||||
|
import org.teavm.ast.InvocationExpr;
|
||||||
|
import org.teavm.ast.QualificationExpr;
|
||||||
|
import org.teavm.ast.SubscriptExpr;
|
||||||
|
import org.teavm.ast.UnwrapArrayExpr;
|
||||||
|
import org.teavm.backend.wasm.generate.common.methods.BaseWasmGenerationVisitor;
|
||||||
|
import org.teavm.backend.wasm.generate.gc.WasmGCGenerationContext;
|
||||||
|
import org.teavm.backend.wasm.generate.gc.classes.WasmGCClassInfoProvider;
|
||||||
|
import org.teavm.backend.wasm.model.WasmArray;
|
||||||
|
import org.teavm.backend.wasm.model.WasmFunction;
|
||||||
|
import org.teavm.backend.wasm.model.WasmFunctionType;
|
||||||
|
import org.teavm.backend.wasm.model.WasmLocal;
|
||||||
|
import org.teavm.backend.wasm.model.WasmStructure;
|
||||||
|
import org.teavm.backend.wasm.model.WasmType;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmArrayGet;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmArrayLength;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmArrayNewDefault;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmArraySet;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmBlock;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmCall;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmCallReference;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmCast;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmGetGlobal;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmGetLocal;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmNullConstant;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmSetGlobal;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmSetLocal;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmStructGet;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmStructNewDefault;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmStructSet;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmThrow;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmUnreachable;
|
||||||
|
import org.teavm.model.FieldReference;
|
||||||
|
import org.teavm.model.MethodReference;
|
||||||
|
import org.teavm.model.TextLocation;
|
||||||
|
import org.teavm.model.ValueType;
|
||||||
|
|
||||||
|
public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
|
||||||
|
private WasmGCGenerationContext context;
|
||||||
|
|
||||||
|
public WasmGCGenerationVisitor(WasmGCGenerationContext context, WasmFunction function,
|
||||||
|
int firstVariable, boolean async) {
|
||||||
|
super(context, function, firstVariable, async);
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isManaged() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isManagedCall(MethodReference method) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void generateThrowNPE(TextLocation location, List<WasmExpression> target) {
|
||||||
|
generateThrow(new WasmCall(context.npeMethod()), location, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void generateThrowAIOOBE(TextLocation location, List<WasmExpression> target) {
|
||||||
|
generateThrow(new WasmCall(context.aaiobeMethod()), location, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void generateThrowCCE(TextLocation location, List<WasmExpression> target) {
|
||||||
|
generateThrow(new WasmCall(context.cceMethod()), location, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void generateThrow(WasmExpression expression, TextLocation location, List<WasmExpression> target) {
|
||||||
|
var setThrowable = new WasmSetGlobal(context.exceptionGlobal(), expression);
|
||||||
|
setThrowable.setLocation(location);
|
||||||
|
target.add(setThrowable);
|
||||||
|
|
||||||
|
var result = new WasmThrow(context.getExceptionTag());
|
||||||
|
result.setLocation(location);
|
||||||
|
target.add(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(UnwrapArrayExpr expr) {
|
||||||
|
accept(expr.getArray());
|
||||||
|
result = unwrapArray(result);
|
||||||
|
result.setLocation(expr.getLocation());
|
||||||
|
}
|
||||||
|
|
||||||
|
private WasmExpression unwrapArray(WasmExpression array) {
|
||||||
|
array.acceptVisitor(typeInference);
|
||||||
|
var arrayType = (WasmType.CompositeReference) typeInference.getResult();
|
||||||
|
var arrayStruct = (WasmStructure) arrayType.composite;
|
||||||
|
return new WasmStructGet(arrayStruct, array, WasmGCClassInfoProvider.ARRAY_DATA_FIELD_OFFSET);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected WasmExpression generateArrayLength(WasmExpression array) {
|
||||||
|
return new WasmArrayLength(array);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected WasmExpression storeArrayItem(WasmExpression array, WasmExpression index, WasmExpression value,
|
||||||
|
ArrayType type) {
|
||||||
|
array.acceptVisitor(typeInference);
|
||||||
|
var arrayRefType = (WasmType.CompositeReference) typeInference.getResult();
|
||||||
|
var arrayType = (WasmArray) arrayRefType.composite;
|
||||||
|
return new WasmArraySet(arrayType, array, index, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void storeField(Expr qualified, FieldReference field, Expr value, TextLocation location) {
|
||||||
|
accept(qualified);
|
||||||
|
var target = result;
|
||||||
|
accept(value);
|
||||||
|
var wasmValue = result;
|
||||||
|
|
||||||
|
target.acceptVisitor(typeInference);
|
||||||
|
var type = (WasmType.CompositeReference) typeInference.getResult();
|
||||||
|
var struct = (WasmStructure) type.composite;
|
||||||
|
|
||||||
|
var fieldIndex = context.classInfoProvider().getFieldIndex(field);
|
||||||
|
|
||||||
|
var expr = new WasmStructSet(struct, target, fieldIndex, wasmValue);
|
||||||
|
expr.setLocation(location);
|
||||||
|
resultConsumer.add(expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected WasmExpression stringLiteral(String s) {
|
||||||
|
var stringConstant = context.strings().getStringConstant(s);
|
||||||
|
return new WasmGetGlobal(stringConstant.global);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected WasmExpression classLiteral(ValueType type) {
|
||||||
|
var classConstant = context.classInfoProvider().getClassInfo(type);
|
||||||
|
return new WasmGetGlobal(classConstant.getPointer());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected CallSiteIdentifier generateCallSiteId(TextLocation location) {
|
||||||
|
return new SimpleCallSite();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected WasmExpression generateVirtualCall(WasmLocal instance, MethodReference method,
|
||||||
|
List<WasmExpression> arguments) {
|
||||||
|
var vtable = context.virtualTables().lookup(method.getClassName());
|
||||||
|
if (vtable != null) {
|
||||||
|
vtable = vtable.findMethodContainer(method.getDescriptor());
|
||||||
|
}
|
||||||
|
if (vtable == null) {
|
||||||
|
return new WasmUnreachable();
|
||||||
|
}
|
||||||
|
method = new MethodReference(vtable.getClassName(), method.getDescriptor());
|
||||||
|
|
||||||
|
arguments.get(0).acceptVisitor(typeInference);
|
||||||
|
var instanceType = (WasmType.CompositeReference) typeInference.getResult();
|
||||||
|
var instanceStruct = (WasmStructure) instanceType.composite;
|
||||||
|
|
||||||
|
WasmExpression classRef = new WasmStructGet(instanceStruct, new WasmGetLocal(instance),
|
||||||
|
WasmGCClassInfoProvider.CLASS_FIELD_OFFSET);
|
||||||
|
var index = context.classInfoProvider().getVirtualMethodIndex(method);
|
||||||
|
var vtableType = (WasmType.CompositeReference) instanceStruct.getFields()
|
||||||
|
.get(WasmGCClassInfoProvider.CLASS_FIELD_OFFSET).asUnpackedType();
|
||||||
|
var vtableStruct = (WasmStructure) vtableType.composite;
|
||||||
|
var expectedVtableStruct = context.classInfoProvider().getClassInfo(vtable.getClassName())
|
||||||
|
.getVirtualTableStructure();
|
||||||
|
if (expectedVtableStruct != vtableStruct) {
|
||||||
|
classRef = new WasmCast(classRef, expectedVtableStruct.getReference());
|
||||||
|
}
|
||||||
|
|
||||||
|
var functionRef = new WasmStructGet(expectedVtableStruct, classRef, index);
|
||||||
|
var functionTypeRef = (WasmType.CompositeReference) expectedVtableStruct.getFields()
|
||||||
|
.get(index).asUnpackedType();
|
||||||
|
var invoke = new WasmCallReference(functionRef, (WasmFunctionType) functionTypeRef.composite);
|
||||||
|
invoke.getArguments().addAll(arguments);
|
||||||
|
return invoke;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void allocateObject(String className, TextLocation location, WasmLocal local,
|
||||||
|
List<WasmExpression> target) {
|
||||||
|
var classInfo = context.classInfoProvider().getClassInfo(className);
|
||||||
|
var block = new WasmBlock(false);
|
||||||
|
block.setType(classInfo.getType());
|
||||||
|
var targetVar = local;
|
||||||
|
if (targetVar == null) {
|
||||||
|
targetVar = tempVars.acquire(classInfo.getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
var structNew = new WasmSetLocal(targetVar, new WasmStructNewDefault(classInfo.getStructure()));
|
||||||
|
structNew.setLocation(location);
|
||||||
|
target.add(structNew);
|
||||||
|
|
||||||
|
var initClassField = new WasmStructSet(classInfo.getStructure(), new WasmGetLocal(targetVar),
|
||||||
|
WasmGCClassInfoProvider.CLASS_FIELD_OFFSET, new WasmGetGlobal(classInfo.getPointer()));
|
||||||
|
initClassField.setLocation(location);
|
||||||
|
target.add(initClassField);
|
||||||
|
|
||||||
|
if (local == null) {
|
||||||
|
var getLocal = new WasmGetLocal(targetVar);
|
||||||
|
getLocal.setLocation(location);
|
||||||
|
target.add(getLocal);
|
||||||
|
tempVars.release(targetVar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void allocateArray(ValueType itemType, WasmExpression length, TextLocation location, WasmLocal local,
|
||||||
|
List<WasmExpression> target) {
|
||||||
|
var classInfo = context.classInfoProvider().getClassInfo(ValueType.arrayOf(itemType));
|
||||||
|
var block = new WasmBlock(false);
|
||||||
|
block.setType(classInfo.getType());
|
||||||
|
var targetVar = local;
|
||||||
|
if (targetVar == null) {
|
||||||
|
targetVar = tempVars.acquire(classInfo.getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
var structNew = new WasmSetLocal(targetVar, new WasmStructNewDefault(classInfo.getStructure()));
|
||||||
|
structNew.setLocation(location);
|
||||||
|
target.add(structNew);
|
||||||
|
|
||||||
|
var initClassField = new WasmStructSet(classInfo.getStructure(), new WasmGetLocal(targetVar),
|
||||||
|
WasmGCClassInfoProvider.CLASS_FIELD_OFFSET, new WasmGetGlobal(classInfo.getPointer()));
|
||||||
|
initClassField.setLocation(location);
|
||||||
|
target.add(initClassField);
|
||||||
|
|
||||||
|
var wasmArrayType = (WasmType.CompositeReference) classInfo.getStructure().getFields()
|
||||||
|
.get(WasmGCClassInfoProvider.ARRAY_DATA_FIELD_OFFSET)
|
||||||
|
.asUnpackedType();
|
||||||
|
var wasmArray = (WasmArray) wasmArrayType.composite;
|
||||||
|
var initArrayField = new WasmStructSet(
|
||||||
|
classInfo.getStructure(),
|
||||||
|
new WasmGetLocal(targetVar),
|
||||||
|
WasmGCClassInfoProvider.ARRAY_DATA_FIELD_OFFSET,
|
||||||
|
new WasmArrayNewDefault(wasmArray, length)
|
||||||
|
);
|
||||||
|
initArrayField.setLocation(location);
|
||||||
|
target.add(initArrayField);
|
||||||
|
|
||||||
|
if (local == null) {
|
||||||
|
var getLocal = new WasmGetLocal(targetVar);
|
||||||
|
getLocal.setLocation(location);
|
||||||
|
target.add(getLocal);
|
||||||
|
tempVars.release(targetVar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected WasmExpression allocateMultiArray(List<WasmExpression> target, ValueType itemType,
|
||||||
|
List<WasmExpression> dimensions, TextLocation location) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected WasmExpression generateInstanceOf(WasmExpression expression, ValueType type) {
|
||||||
|
context.classInfoProvider().getClassInfo(type);
|
||||||
|
var supertypeCall = new WasmCall(context.functions().forSupertype(type));
|
||||||
|
var classRef = new WasmStructGet(
|
||||||
|
context.standardClasses().objectClass().getStructure(),
|
||||||
|
expression,
|
||||||
|
WasmGCClassInfoProvider.CLASS_FIELD_OFFSET
|
||||||
|
);
|
||||||
|
supertypeCall.getArguments().add(classRef);
|
||||||
|
return supertypeCall;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected WasmExpression generateCast(WasmExpression value, WasmType targetType) {
|
||||||
|
return new WasmCast(value, (WasmType.Reference) targetType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean needsClassInitializer(String className) {
|
||||||
|
return context.classInfoProvider().getClassInfo(className).getInitializerPointer() != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected WasmExpression generateClassInitializer(String className, TextLocation location) {
|
||||||
|
var pointer = context.classInfoProvider().getClassInfo(className).getInitializerPointer();
|
||||||
|
var result = new WasmCallReference(new WasmGetGlobal(pointer),
|
||||||
|
context.functionTypes().of(null));
|
||||||
|
result.setLocation(location);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected WasmExpression peekException() {
|
||||||
|
return new WasmGetGlobal(context.exceptionGlobal());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void catchException(TextLocation location, List<WasmExpression> target, WasmLocal local) {
|
||||||
|
var type = context.classInfoProvider().getClassInfo("java.lang.Throwable").getType();
|
||||||
|
if (local != null) {
|
||||||
|
var save = new WasmSetLocal(local, new WasmGetGlobal(context.exceptionGlobal()));
|
||||||
|
save.setLocation(location);
|
||||||
|
target.add(save);
|
||||||
|
}
|
||||||
|
|
||||||
|
var erase = new WasmSetGlobal(context.exceptionGlobal(), new WasmNullConstant(type));
|
||||||
|
erase.setLocation(location);
|
||||||
|
target.add(erase);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected WasmType mapType(ValueType type) {
|
||||||
|
return context.typeMapper().mapType(type).asUnpackedType();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(SubscriptExpr expr) {
|
||||||
|
accept(expr.getArray());
|
||||||
|
var arrayData = unwrapArray(result);
|
||||||
|
arrayData.acceptVisitor(typeInference);
|
||||||
|
var arrayTypeRef = (WasmType.CompositeReference) typeInference.getResult();
|
||||||
|
var arrayType = (WasmArray) arrayTypeRef.composite;
|
||||||
|
|
||||||
|
accept(expr.getIndex());
|
||||||
|
var index = result;
|
||||||
|
|
||||||
|
result = new WasmArrayGet(arrayType, arrayData, index);
|
||||||
|
result.setLocation(expr.getLocation());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(InvocationExpr expr) {
|
||||||
|
result = invocation(expr, null, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(QualificationExpr expr) {
|
||||||
|
accept(expr.getQualified());
|
||||||
|
var target = result;
|
||||||
|
|
||||||
|
target.acceptVisitor(typeInference);
|
||||||
|
var type = (WasmType.CompositeReference) typeInference.getResult();
|
||||||
|
var struct = (WasmStructure) type.composite;
|
||||||
|
|
||||||
|
var fieldIndex = context.classInfoProvider().getFieldIndex(expr.getField());
|
||||||
|
|
||||||
|
result = new WasmStructGet(struct, target, fieldIndex);
|
||||||
|
result.setLocation(expr.getLocation());
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SimpleCallSite extends CallSiteIdentifier {
|
||||||
|
@Override
|
||||||
|
public void generateRegister(List<WasmExpression> consumer, TextLocation location) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void checkHandlerId(List<WasmExpression> target, TextLocation location) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void generateThrow(List<WasmExpression> target, TextLocation location) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 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.runtime;
|
||||||
|
|
||||||
|
public class WasmGCSupport {
|
||||||
|
private WasmGCSupport() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static NullPointerException npe() {
|
||||||
|
return new NullPointerException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ArrayIndexOutOfBoundsException aiiobe() {
|
||||||
|
return new ArrayIndexOutOfBoundsException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ClassCastException cce() {
|
||||||
|
return new ClassCastException();
|
||||||
|
}
|
||||||
|
}
|
|
@ -82,6 +82,15 @@ public abstract class BaseTypeInference<T> {
|
||||||
visitor.graphBuilder.addEdge(incoming.getValue().getIndex(), phi.getReceiver().getIndex());
|
visitor.graphBuilder.addEdge(incoming.getValue().getIndex(), phi.getReceiver().getIndex());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (var tryCatch : block.getTryCatchBlocks()) {
|
||||||
|
var exceptionVar = tryCatch.getHandler().getExceptionVariable();
|
||||||
|
if (exceptionVar != null) {
|
||||||
|
var exceptionType = tryCatch.getExceptionType() != null
|
||||||
|
? ValueType.object(tryCatch.getExceptionType())
|
||||||
|
: ValueType.object("java.lang.Throwable");
|
||||||
|
visitor.type(exceptionVar, exceptionType);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
graph = visitor.graphBuilder.build();
|
graph = visitor.graphBuilder.build();
|
||||||
arrayGraph = visitor.arrayGraphBuilder.build();
|
arrayGraph = visitor.arrayGraphBuilder.build();
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 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.model.util;
|
||||||
|
|
||||||
|
import org.teavm.model.MethodReference;
|
||||||
|
import org.teavm.model.ProgramReader;
|
||||||
|
|
||||||
|
public class DefaultVariableCategoryProvider implements VariableCategoryProvider {
|
||||||
|
@Override
|
||||||
|
public Object[] getCategories(ProgramReader program, MethodReference method) {
|
||||||
|
TypeInferer inferer = new TypeInferer();
|
||||||
|
inferer.inferTypes(program, method);
|
||||||
|
var categories = new Object[program.variableCount()];
|
||||||
|
for (int i = 0; i < program.variableCount(); ++i) {
|
||||||
|
categories[i] = getCategory(inferer.typeOf(i));
|
||||||
|
}
|
||||||
|
return categories;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getCategory(VariableType type) {
|
||||||
|
if (type == null) {
|
||||||
|
return 255;
|
||||||
|
}
|
||||||
|
switch (type) {
|
||||||
|
case INT:
|
||||||
|
return 0;
|
||||||
|
case LONG:
|
||||||
|
return 1;
|
||||||
|
case FLOAT:
|
||||||
|
return 2;
|
||||||
|
case DOUBLE:
|
||||||
|
return 3;
|
||||||
|
case OBJECT:
|
||||||
|
return 4;
|
||||||
|
default:
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,18 +16,20 @@
|
||||||
package org.teavm.model.util;
|
package org.teavm.model.util;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.BitSet;
|
import java.util.BitSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.teavm.common.Graph;
|
import org.teavm.common.Graph;
|
||||||
import org.teavm.common.IntegerArray;
|
|
||||||
|
|
||||||
public class GraphColorer {
|
public class GraphColorer {
|
||||||
public void colorize(Graph graph, int[] colors) {
|
public void colorize(Graph graph, int[] colors) {
|
||||||
colorize(graph, colors, new int[graph.size()], new String[graph.size()]);
|
var categories = new Object[graph.size()];
|
||||||
|
Arrays.fill(categories, new Object());
|
||||||
|
colorize(graph, colors, categories, new String[graph.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void colorize(Graph graph, int[] colors, int[] categories, String[] names) {
|
public void colorize(Graph graph, int[] colors, Object[] categories, String[] names) {
|
||||||
IntegerArray colorCategories = new IntegerArray(graph.size());
|
var colorCategories = new ArrayList<>(graph.size());
|
||||||
List<String> colorNames = new ArrayList<>();
|
List<String> colorNames = new ArrayList<>();
|
||||||
for (int i = 0; i < colors.length; ++i) {
|
for (int i = 0; i < colors.length; ++i) {
|
||||||
int color = colors[i];
|
int color = colors[i];
|
||||||
|
@ -59,12 +61,12 @@ public class GraphColorer {
|
||||||
while (true) {
|
while (true) {
|
||||||
color = usedColors.nextClearBit(color);
|
color = usedColors.nextClearBit(color);
|
||||||
while (colorCategories.size() <= color) {
|
while (colorCategories.size() <= color) {
|
||||||
colorCategories.add(-1);
|
colorCategories.add(null);
|
||||||
colorNames.add(null);
|
colorNames.add(null);
|
||||||
}
|
}
|
||||||
int category = colorCategories.get(color);
|
var category = colorCategories.get(color);
|
||||||
String name = colorNames.get(color);
|
String name = colorNames.get(color);
|
||||||
if ((category < 0 || category == categories[v])
|
if ((category == null || category.equals(categories[v]))
|
||||||
&& (name == null || names[v] == null || name.equals(names[v]))) {
|
&& (name == null || names[v] == null || name.equals(names[v]))) {
|
||||||
colors[v] = color;
|
colors[v] = color;
|
||||||
colorCategories.set(color, categories[v]);
|
colorCategories.set(color, categories[v]);
|
||||||
|
|
|
@ -38,6 +38,12 @@ import org.teavm.model.instructions.AssignInstruction;
|
||||||
import org.teavm.model.instructions.JumpInstruction;
|
import org.teavm.model.instructions.JumpInstruction;
|
||||||
|
|
||||||
public class RegisterAllocator {
|
public class RegisterAllocator {
|
||||||
|
private VariableCategoryProvider variableCategoryProvider;
|
||||||
|
|
||||||
|
public RegisterAllocator(VariableCategoryProvider variableCategoryProvider) {
|
||||||
|
this.variableCategoryProvider = variableCategoryProvider;
|
||||||
|
}
|
||||||
|
|
||||||
public void allocateRegisters(MethodReference method, Program program, boolean debuggerFriendly) {
|
public void allocateRegisters(MethodReference method, Program program, boolean debuggerFriendly) {
|
||||||
insertPhiArgumentsCopies(program);
|
insertPhiArgumentsCopies(program);
|
||||||
InterferenceGraphBuilder interferenceBuilder = new InterferenceGraphBuilder();
|
InterferenceGraphBuilder interferenceBuilder = new InterferenceGraphBuilder();
|
||||||
|
@ -62,7 +68,7 @@ public class RegisterAllocator {
|
||||||
for (int cls : classArray) {
|
for (int cls : classArray) {
|
||||||
maxClass = Math.max(maxClass, cls + 1);
|
maxClass = Math.max(maxClass, cls + 1);
|
||||||
}
|
}
|
||||||
int[] categories = getVariableCategories(program, method);
|
var categories = variableCategoryProvider.getCategories(program, method);
|
||||||
String[] names = getVariableNames(program, debuggerFriendly);
|
String[] names = getVariableNames(program, debuggerFriendly);
|
||||||
colorer.colorize(MutableGraphNode.toGraph(interferenceGraph), colors, categories, names);
|
colorer.colorize(MutableGraphNode.toGraph(interferenceGraph), colors, categories, names);
|
||||||
|
|
||||||
|
@ -91,36 +97,6 @@ public class RegisterAllocator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int[] getVariableCategories(ProgramReader program, MethodReference method) {
|
|
||||||
TypeInferer inferer = new TypeInferer();
|
|
||||||
inferer.inferTypes(program, method);
|
|
||||||
int[] categories = new int[program.variableCount()];
|
|
||||||
for (int i = 0; i < program.variableCount(); ++i) {
|
|
||||||
categories[i] = getCategory(inferer.typeOf(i));
|
|
||||||
}
|
|
||||||
return categories;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getCategory(VariableType type) {
|
|
||||||
if (type == null) {
|
|
||||||
return 255;
|
|
||||||
}
|
|
||||||
switch (type) {
|
|
||||||
case INT:
|
|
||||||
return 0;
|
|
||||||
case LONG:
|
|
||||||
return 1;
|
|
||||||
case FLOAT:
|
|
||||||
return 2;
|
|
||||||
case DOUBLE:
|
|
||||||
return 3;
|
|
||||||
case OBJECT:
|
|
||||||
return 4;
|
|
||||||
default:
|
|
||||||
return 5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String[] getVariableNames(ProgramReader program, boolean debuggerFriendly) {
|
private String[] getVariableNames(ProgramReader program, boolean debuggerFriendly) {
|
||||||
String[] names = new String[program.variableCount()];
|
String[] names = new String[program.variableCount()];
|
||||||
for (int i = 0; i < names.length; ++i) {
|
for (int i = 0; i < names.length; ++i) {
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 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.model.util;
|
||||||
|
|
||||||
|
import org.teavm.model.MethodReference;
|
||||||
|
import org.teavm.model.ProgramReader;
|
||||||
|
|
||||||
|
public interface VariableCategoryProvider {
|
||||||
|
Object[] getCategories(ProgramReader program, MethodReference method);
|
||||||
|
}
|
|
@ -762,8 +762,9 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
||||||
} while (changed);
|
} while (changed);
|
||||||
|
|
||||||
target.afterOptimizations(optimizedProgram, method);
|
target.afterOptimizations(optimizedProgram, method);
|
||||||
if (target.requiresRegisterAllocation()) {
|
var categoryProvider = target.variableCategoryProvider();
|
||||||
RegisterAllocator allocator = new RegisterAllocator();
|
if (categoryProvider != null) {
|
||||||
|
var allocator = new RegisterAllocator(categoryProvider);
|
||||||
allocator.allocateRegisters(method.getReference(), optimizedProgram,
|
allocator.allocateRegisters(method.getReference(), optimizedProgram,
|
||||||
optimizationLevel == TeaVMOptimizationLevel.SIMPLE);
|
optimizationLevel == TeaVMOptimizationLevel.SIMPLE);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ import org.teavm.model.MethodReader;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
import org.teavm.model.Program;
|
import org.teavm.model.Program;
|
||||||
import org.teavm.model.optimization.InliningFilterFactory;
|
import org.teavm.model.optimization.InliningFilterFactory;
|
||||||
|
import org.teavm.model.util.VariableCategoryProvider;
|
||||||
import org.teavm.vm.spi.TeaVMHostExtension;
|
import org.teavm.vm.spi.TeaVMHostExtension;
|
||||||
|
|
||||||
public interface TeaVMTarget {
|
public interface TeaVMTarget {
|
||||||
|
@ -38,7 +39,7 @@ public interface TeaVMTarget {
|
||||||
|
|
||||||
List<TeaVMHostExtension> getHostExtensions();
|
List<TeaVMHostExtension> getHostExtensions();
|
||||||
|
|
||||||
boolean requiresRegisterAllocation();
|
VariableCategoryProvider variableCategoryProvider();
|
||||||
|
|
||||||
void contributeDependencies(DependencyAnalyzer dependencyAnalyzer);
|
void contributeDependencies(DependencyAnalyzer dependencyAnalyzer);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user