mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
wasm gc: fix issues with virtual calls
This commit is contained in:
parent
2805631025
commit
40fbce0ddd
|
@ -74,6 +74,7 @@ public class WasmGCDependencies {
|
||||||
analyzer.linkMethod(new MethodReference(WasmGCSupport.class, "aiiobe", ArrayIndexOutOfBoundsException.class))
|
analyzer.linkMethod(new MethodReference(WasmGCSupport.class, "aiiobe", ArrayIndexOutOfBoundsException.class))
|
||||||
.use();
|
.use();
|
||||||
analyzer.linkMethod(new MethodReference(WasmGCSupport.class, "cce", ClassCastException.class)).use();
|
analyzer.linkMethod(new MethodReference(WasmGCSupport.class, "cce", ClassCastException.class)).use();
|
||||||
|
analyzer.linkMethod(new MethodReference(WasmGCSupport.class, "cnse", CloneNotSupportedException.class)).use();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void contributeInitializerUtils() {
|
private void contributeInitializerUtils() {
|
||||||
|
|
|
@ -56,6 +56,8 @@ import org.teavm.backend.wasm.model.expression.WasmInt64Subtype;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmIntBinary;
|
import org.teavm.backend.wasm.model.expression.WasmIntBinary;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmIntBinaryOperation;
|
import org.teavm.backend.wasm.model.expression.WasmIntBinaryOperation;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmIntType;
|
import org.teavm.backend.wasm.model.expression.WasmIntType;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmIntUnary;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmIntUnaryOperation;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmLoadFloat32;
|
import org.teavm.backend.wasm.model.expression.WasmLoadFloat32;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmLoadFloat64;
|
import org.teavm.backend.wasm.model.expression.WasmLoadFloat64;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmLoadInt32;
|
import org.teavm.backend.wasm.model.expression.WasmLoadInt32;
|
||||||
|
@ -302,6 +304,11 @@ public class WasmGenerationVisitor extends BaseWasmGenerationVisitor {
|
||||||
return new WasmInt32Constant(0);
|
return new WasmInt32Constant(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected WasmExpression genIsNull(WasmExpression value) {
|
||||||
|
return new WasmIntUnary(WasmIntType.INT32, WasmIntUnaryOperation.EQZ, value);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(SubscriptExpr expr) {
|
public void visit(SubscriptExpr expr) {
|
||||||
WasmExpression ptr = getArrayElementPointer(expr);
|
WasmExpression ptr = getArrayElementPointer(expr);
|
||||||
|
|
|
@ -92,8 +92,6 @@ import org.teavm.backend.wasm.model.expression.WasmInt64Constant;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmIntBinary;
|
import org.teavm.backend.wasm.model.expression.WasmIntBinary;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmIntBinaryOperation;
|
import org.teavm.backend.wasm.model.expression.WasmIntBinaryOperation;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmIntType;
|
import org.teavm.backend.wasm.model.expression.WasmIntType;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmIntUnary;
|
|
||||||
import org.teavm.backend.wasm.model.expression.WasmIntUnaryOperation;
|
|
||||||
import org.teavm.backend.wasm.model.expression.WasmReturn;
|
import org.teavm.backend.wasm.model.expression.WasmReturn;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmSetLocal;
|
import org.teavm.backend.wasm.model.expression.WasmSetLocal;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmSwitch;
|
import org.teavm.backend.wasm.model.expression.WasmSwitch;
|
||||||
|
@ -902,9 +900,16 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
|
||||||
var block = new WasmBlock(false);
|
var block = new WasmBlock(false);
|
||||||
block.setType(mapType(reference.getReturnType()));
|
block.setType(mapType(reference.getReturnType()));
|
||||||
|
|
||||||
var instanceVar = tempVars.acquire(instanceWasmType);
|
WasmLocal instanceVar;
|
||||||
block.getBody().add(new WasmSetLocal(instanceVar, instance));
|
var isTemporary = false;
|
||||||
instance = new WasmGetLocal(instanceVar);
|
if (instance instanceof WasmGetLocal) {
|
||||||
|
instanceVar = ((WasmGetLocal) instance).getLocal();
|
||||||
|
} else {
|
||||||
|
instanceVar = tempVars.acquire(instanceWasmType);
|
||||||
|
block.getBody().add(new WasmSetLocal(instanceVar, instance));
|
||||||
|
instance = new WasmGetLocal(instanceVar);
|
||||||
|
isTemporary = true;
|
||||||
|
}
|
||||||
|
|
||||||
var arguments = new ArrayList<WasmExpression>();
|
var arguments = new ArrayList<WasmExpression>();
|
||||||
arguments.add(instance);
|
arguments.add(instance);
|
||||||
|
@ -918,7 +923,9 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
|
||||||
var call = generateVirtualCall(instanceVar, reference, arguments);
|
var call = generateVirtualCall(instanceVar, reference, arguments);
|
||||||
|
|
||||||
block.getBody().add(call);
|
block.getBody().add(call);
|
||||||
tempVars.release(instanceVar);
|
if (isTemporary) {
|
||||||
|
tempVars.release(instanceVar);
|
||||||
|
}
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1133,7 +1140,7 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
|
||||||
result.acceptVisitor(typeInference);
|
result.acceptVisitor(typeInference);
|
||||||
var cachedObject = exprCache.create(result, typeInference.getResult(), expr.getLocation(), block.getBody());
|
var cachedObject = exprCache.create(result, typeInference.getResult(), expr.getLocation(), block.getBody());
|
||||||
|
|
||||||
var ifNull = new WasmBranch(genIsZero(cachedObject.expr()), block);
|
var ifNull = new WasmBranch(genIsNull(cachedObject.expr()), block);
|
||||||
ifNull.setResult(new WasmInt32Constant(0));
|
ifNull.setResult(new WasmInt32Constant(0));
|
||||||
block.getBody().add(new WasmDrop(ifNull));
|
block.getBody().add(new WasmDrop(ifNull));
|
||||||
|
|
||||||
|
@ -1171,7 +1178,7 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
|
||||||
var wasmSourceType = typeInference.getResult();
|
var wasmSourceType = typeInference.getResult();
|
||||||
var valueToCast = exprCache.create(result, wasmSourceType, expr.getLocation(), block.getBody());
|
var valueToCast = exprCache.create(result, wasmSourceType, expr.getLocation(), block.getBody());
|
||||||
|
|
||||||
var nullCheck = new WasmBranch(genIsZero(valueToCast.expr()), block);
|
var nullCheck = new WasmBranch(genIsNull(valueToCast.expr()), block);
|
||||||
nullCheck.setResult(valueToCast.expr());
|
nullCheck.setResult(valueToCast.expr());
|
||||||
block.getBody().add(new WasmDrop(nullCheck));
|
block.getBody().add(new WasmDrop(nullCheck));
|
||||||
|
|
||||||
|
@ -1544,9 +1551,7 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private WasmExpression genIsZero(WasmExpression value) {
|
protected abstract WasmExpression genIsNull(WasmExpression value);
|
||||||
return new WasmIntUnary(WasmIntType.INT32, WasmIntUnaryOperation.EQZ, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract WasmType mapType(ValueType type);
|
protected abstract WasmType mapType(ValueType type);
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,7 @@ import org.teavm.backend.wasm.model.expression.WasmIntBinary;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmIntBinaryOperation;
|
import org.teavm.backend.wasm.model.expression.WasmIntBinaryOperation;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmIntType;
|
import org.teavm.backend.wasm.model.expression.WasmIntType;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmNullConstant;
|
import org.teavm.backend.wasm.model.expression.WasmNullConstant;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmReturn;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmSetGlobal;
|
import org.teavm.backend.wasm.model.expression.WasmSetGlobal;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmStructNewDefault;
|
import org.teavm.backend.wasm.model.expression.WasmStructNewDefault;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmStructSet;
|
import org.teavm.backend.wasm.model.expression.WasmStructSet;
|
||||||
|
@ -122,7 +123,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
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);
|
||||||
typeMapper = new WasmGCTypeMapper(this);
|
typeMapper = new WasmGCTypeMapper(this, functionTypes, module);
|
||||||
}
|
}
|
||||||
|
|
||||||
public WasmGCSupertypeFunctionProvider getSupertypeProvider() {
|
public WasmGCSupertypeFunctionProvider getSupertypeProvider() {
|
||||||
|
@ -143,6 +144,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void contributeToInitializerDefinitions(WasmFunction function) {
|
public void contributeToInitializerDefinitions(WasmFunction function) {
|
||||||
|
fillVirtualTableSupertypes();
|
||||||
for (var classInfo : classInfoMap.values()) {
|
for (var classInfo : classInfoMap.values()) {
|
||||||
var classInstanceType = classInfo.virtualTableStructure != null
|
var classInstanceType = classInfo.virtualTableStructure != null
|
||||||
? classInfo.virtualTableStructure
|
? classInfo.virtualTableStructure
|
||||||
|
@ -152,6 +154,35 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void fillVirtualTableSupertypes() {
|
||||||
|
for (var classInfo : classInfoMap.values()) {
|
||||||
|
if (classInfo.virtualTableStructure != null && classInfo.getValueType() instanceof ValueType.Object
|
||||||
|
&& classInfo.hasOwnVirtualTable) {
|
||||||
|
var className = ((ValueType.Object) classInfo.getValueType()).getClassName();
|
||||||
|
classInfo.virtualTableStructure.setSupertype(findVirtualTableSupertype(className));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private WasmStructure findVirtualTableSupertype(String className) {
|
||||||
|
while (className != null) {
|
||||||
|
var cls = classSource.get(className);
|
||||||
|
if (cls == null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
className = cls.getParent();
|
||||||
|
if (className == null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
var parentInfo = classInfoMap.get(ValueType.object(className));
|
||||||
|
if (parentInfo != null && parentInfo.virtualTableStructure != null) {
|
||||||
|
return parentInfo.virtualTableStructure;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var classClass = classInfoMap.get(ValueType.object("java.lang.Class"));
|
||||||
|
return classClass != null ? classClass.structure : null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void contributeToInitializer(WasmFunction function) {
|
public void contributeToInitializer(WasmFunction function) {
|
||||||
var classClass = standardClasses.classClass();
|
var classClass = standardClasses.classClass();
|
||||||
|
@ -209,7 +240,8 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
fillFields(classInfo, type);
|
fillFields(classInfo, type);
|
||||||
}
|
}
|
||||||
var pointerName = names.forClassInstance(type);
|
var pointerName = names.forClassInstance(type);
|
||||||
var classStructure = virtualTable != null && virtualTable.hasValidEntries()
|
classInfo.hasOwnVirtualTable = virtualTable != null && virtualTable.hasValidEntries();
|
||||||
|
var classStructure = classInfo.hasOwnVirtualTable
|
||||||
? initRegularClassStructure(((ValueType.Object) type).getClassName())
|
? initRegularClassStructure(((ValueType.Object) type).getClassName())
|
||||||
: standardClasses.classClass().getStructure();
|
: standardClasses.classClass().getStructure();
|
||||||
classInfo.virtualTableStructure = classStructure;
|
classInfo.virtualTableStructure = classStructure;
|
||||||
|
@ -330,21 +362,30 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (virtualTable != null && virtualTable.hasValidEntries()) {
|
if (virtualTable != null && virtualTable.hasValidEntries()) {
|
||||||
fillVirtualTableMethods(target, classStructure, classInfo.pointer, virtualTable,
|
fillVirtualTableMethods(target, classStructure, classInfo.pointer, virtualTable, virtualTable,
|
||||||
virtualTableFieldOffset, name, new HashSet<>());
|
new HashSet<>());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private int fillVirtualTableMethods(List<WasmExpression> target, WasmStructure structure, WasmGlobal global,
|
private void fillVirtualTableMethods(List<WasmExpression> target, WasmStructure structure, WasmGlobal global,
|
||||||
VirtualTable virtualTable, int index, String origin, Set<MethodDescriptor> filled) {
|
VirtualTable virtualTable, VirtualTable original, Set<MethodDescriptor> filled) {
|
||||||
|
if (virtualTable.getParent() != null) {
|
||||||
|
fillVirtualTableMethods(target, structure, global, virtualTable.getParent(), original, filled);
|
||||||
|
}
|
||||||
for (var method : virtualTable.getMethods()) {
|
for (var method : virtualTable.getMethods()) {
|
||||||
var entry = virtualTable.getEntry(method);
|
var entry = original.getEntry(method);
|
||||||
if (entry != null && entry.getImplementor() != null && filled.add(method)
|
if (entry != null && entry.getImplementor() != null && filled.add(method)
|
||||||
&& !method.equals(GET_CLASS_METHOD)) {
|
&& !method.equals(GET_CLASS_METHOD)) {
|
||||||
|
var fieldIndex = virtualTableFieldOffset + entry.getIndex();
|
||||||
|
var expectedType = (WasmType.CompositeReference) structure.getFields().get(fieldIndex)
|
||||||
|
.asUnpackedType();
|
||||||
|
var expectedFunctionType = (WasmFunctionType) expectedType.composite;
|
||||||
var function = functionProvider.forInstanceMethod(entry.getImplementor());
|
var function = functionProvider.forInstanceMethod(entry.getImplementor());
|
||||||
if (!origin.equals(entry.getImplementor().getClassName())) {
|
if (!virtualTable.getClassName().equals(entry.getImplementor().getClassName())
|
||||||
var functionType = getFunctionType(virtualTable.getClassName(), method);
|
|| expectedFunctionType != function.getType()) {
|
||||||
|
var functionType = typeMapper.getFunctionType(virtualTable.getClassName(), method, true);
|
||||||
|
functionType.getSupertypes().add(expectedFunctionType);
|
||||||
var wrapperFunction = new WasmFunction(functionType);
|
var wrapperFunction = new WasmFunction(functionType);
|
||||||
module.functions.add(wrapperFunction);
|
module.functions.add(wrapperFunction);
|
||||||
var call = new WasmCall(function);
|
var call = new WasmCall(function);
|
||||||
|
@ -358,17 +399,14 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
call.getArguments().add(new WasmGetLocal(params[i]));
|
call.getArguments().add(new WasmGetLocal(params[i]));
|
||||||
wrapperFunction.add(params[i]);
|
wrapperFunction.add(params[i]);
|
||||||
}
|
}
|
||||||
|
wrapperFunction.getBody().add(new WasmReturn(call));
|
||||||
|
function = wrapperFunction;
|
||||||
}
|
}
|
||||||
function.setReferenced(true);
|
function.setReferenced(true);
|
||||||
var ref = new WasmFunctionReference(function);
|
var ref = new WasmFunctionReference(function);
|
||||||
target.add(new WasmStructSet(structure, new WasmGetGlobal(global), index + entry.getIndex(), ref));
|
target.add(new WasmStructSet(structure, new WasmGetGlobal(global), fieldIndex, ref));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (virtualTable.getParent() != null) {
|
|
||||||
index = fillVirtualTableMethods(target, structure, global, virtualTable.getParent(), index, origin,
|
|
||||||
filled);
|
|
||||||
}
|
|
||||||
return index;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private WasmStructure initRegularClassStructure(String className) {
|
private WasmStructure initRegularClassStructure(String className) {
|
||||||
|
@ -391,23 +429,12 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
if (methodDesc == null) {
|
if (methodDesc == null) {
|
||||||
structure.getFields().add(WasmType.Reference.FUNC.asStorage());
|
structure.getFields().add(WasmType.Reference.FUNC.asStorage());
|
||||||
} else {
|
} else {
|
||||||
var functionType = getFunctionType(virtualTable.getClassName(), methodDesc);
|
var functionType = typeMapper.getFunctionType(virtualTable.getClassName(), methodDesc, false);
|
||||||
structure.getFields().add(functionType.getReference().asStorage());
|
structure.getFields().add(functionType.getReference().asStorage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private WasmFunctionType getFunctionType(String className, MethodDescriptor methodDesc) {
|
|
||||||
var returnType = typeMapper.mapType(methodDesc.getResultType());
|
|
||||||
var javaParamTypes = methodDesc.getParameterTypes();
|
|
||||||
var paramTypes = new WasmType[javaParamTypes.length + 1];
|
|
||||||
paramTypes[0] = getClassInfo(className).getType();
|
|
||||||
for (var i = 0; i < javaParamTypes.length; ++i) {
|
|
||||||
paramTypes[i + 1] = typeMapper.mapType(javaParamTypes[i]);
|
|
||||||
}
|
|
||||||
return functionTypes.of(returnType, paramTypes);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initArrayClass(WasmGCClassInfo classInfo, ValueType.Array type) {
|
private void initArrayClass(WasmGCClassInfo classInfo, ValueType.Array type) {
|
||||||
classInfo.initializer = target -> {
|
classInfo.initializer = target -> {
|
||||||
var itemTypeInfo = getClassInfo(type.getItemType());
|
var itemTypeInfo = getClassInfo(type.getItemType());
|
||||||
|
@ -497,6 +524,9 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
if (className.equals("java.lang.Object") && field.getName().equals("monitor")) {
|
if (className.equals("java.lang.Object") && field.getName().equals("monitor")) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (className.equals("java.lang.Class") && field.getName().equals("platformClass")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (field.hasModifier(ElementModifier.STATIC)) {
|
if (field.hasModifier(ElementModifier.STATIC)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ public class WasmGCClassInfo {
|
||||||
private ValueType valueType;
|
private ValueType valueType;
|
||||||
WasmStructure structure;
|
WasmStructure structure;
|
||||||
WasmArray array;
|
WasmArray array;
|
||||||
|
boolean hasOwnVirtualTable;
|
||||||
WasmStructure virtualTableStructure;
|
WasmStructure virtualTableStructure;
|
||||||
WasmGlobal pointer;
|
WasmGlobal pointer;
|
||||||
WasmGlobal initializerPointer;
|
WasmGlobal initializerPointer;
|
||||||
|
|
|
@ -15,16 +15,26 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.backend.wasm.generate.gc.classes;
|
package org.teavm.backend.wasm.generate.gc.classes;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import org.teavm.backend.wasm.WasmFunctionTypes;
|
||||||
|
import org.teavm.backend.wasm.model.WasmFunctionType;
|
||||||
|
import org.teavm.backend.wasm.model.WasmModule;
|
||||||
import org.teavm.backend.wasm.model.WasmPackedType;
|
import org.teavm.backend.wasm.model.WasmPackedType;
|
||||||
import org.teavm.backend.wasm.model.WasmStorageType;
|
import org.teavm.backend.wasm.model.WasmStorageType;
|
||||||
import org.teavm.backend.wasm.model.WasmType;
|
import org.teavm.backend.wasm.model.WasmType;
|
||||||
|
import org.teavm.model.MethodDescriptor;
|
||||||
import org.teavm.model.ValueType;
|
import org.teavm.model.ValueType;
|
||||||
|
|
||||||
public class WasmGCTypeMapper {
|
public class WasmGCTypeMapper {
|
||||||
private WasmGCClassInfoProvider classInfoProvider;
|
private WasmGCClassInfoProvider classInfoProvider;
|
||||||
|
private WasmFunctionTypes functionTypes;
|
||||||
|
private WasmModule module;
|
||||||
|
|
||||||
WasmGCTypeMapper(WasmGCClassInfoProvider classInfoProvider) {
|
WasmGCTypeMapper(WasmGCClassInfoProvider classInfoProvider, WasmFunctionTypes functionTypes,
|
||||||
|
WasmModule module) {
|
||||||
this.classInfoProvider = classInfoProvider;
|
this.classInfoProvider = classInfoProvider;
|
||||||
|
this.functionTypes = functionTypes;
|
||||||
|
this.module = module;
|
||||||
}
|
}
|
||||||
|
|
||||||
public WasmStorageType mapStorageType(ValueType type) {
|
public WasmStorageType mapStorageType(ValueType type) {
|
||||||
|
@ -76,4 +86,21 @@ public class WasmGCTypeMapper {
|
||||||
return classInfoProvider.getClassInfo(type).getType();
|
return classInfoProvider.getClassInfo(type).getType();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public WasmFunctionType getFunctionType(String className, MethodDescriptor methodDesc, boolean fresh) {
|
||||||
|
var returnType = mapType(methodDesc.getResultType());
|
||||||
|
var javaParamTypes = methodDesc.getParameterTypes();
|
||||||
|
var paramTypes = new WasmType[javaParamTypes.length + 1];
|
||||||
|
paramTypes[0] = classInfoProvider.getClassInfo(className).getType();
|
||||||
|
for (var i = 0; i < javaParamTypes.length; ++i) {
|
||||||
|
paramTypes[i + 1] = mapType(javaParamTypes[i]);
|
||||||
|
}
|
||||||
|
if (fresh) {
|
||||||
|
var type = new WasmFunctionType(null, returnType, List.of(paramTypes));
|
||||||
|
module.types.add(type);
|
||||||
|
return type;
|
||||||
|
} else {
|
||||||
|
return functionTypes.of(returnType, paramTypes);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -211,6 +211,11 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
|
||||||
: WasmType.Reference.STRUCT);
|
: WasmType.Reference.STRUCT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected WasmExpression genIsNull(WasmExpression value) {
|
||||||
|
return new WasmReferencesEqual(value, new WasmNullConstant(WasmType.Reference.STRUCT));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected CallSiteIdentifier generateCallSiteId(TextLocation location) {
|
protected CallSiteIdentifier generateCallSiteId(TextLocation location) {
|
||||||
return new SimpleCallSite();
|
return new SimpleCallSite();
|
||||||
|
@ -268,12 +273,19 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
|
||||||
}
|
}
|
||||||
var instanceStruct = context.classInfoProvider().getClassInfo(vtable.getClassName()).getStructure();
|
var instanceStruct = context.classInfoProvider().getClassInfo(vtable.getClassName()).getStructure();
|
||||||
|
|
||||||
|
var actualInstanceType = (WasmType.CompositeReference) instance.getType();
|
||||||
|
var actualInstanceStruct = (WasmStructure) actualInstanceType.composite;
|
||||||
|
var actualVtableType = (WasmType.CompositeReference) actualInstanceStruct.getFields().get(0).asUnpackedType();
|
||||||
|
var actualVtableStruct = (WasmStructure) actualVtableType.composite;
|
||||||
|
|
||||||
WasmExpression classRef = new WasmStructGet(instanceStruct, new WasmGetLocal(instance),
|
WasmExpression classRef = new WasmStructGet(instanceStruct, new WasmGetLocal(instance),
|
||||||
WasmGCClassInfoProvider.CLASS_FIELD_OFFSET);
|
WasmGCClassInfoProvider.CLASS_FIELD_OFFSET);
|
||||||
var index = context.classInfoProvider().getVirtualMethodsOffset() + vtableIndex;
|
var index = context.classInfoProvider().getVirtualMethodsOffset() + vtableIndex;
|
||||||
var vtableStruct = context.classInfoProvider().getClassInfo(vtable.getClassName())
|
var vtableStruct = context.classInfoProvider().getClassInfo(vtable.getClassName())
|
||||||
.getVirtualTableStructure();
|
.getVirtualTableStructure();
|
||||||
classRef = new WasmCast(classRef, vtableStruct.getReference());
|
if (!vtableStruct.isSupertypeOf(actualVtableStruct)) {
|
||||||
|
classRef = new WasmCast(classRef, vtableStruct.getReference());
|
||||||
|
}
|
||||||
|
|
||||||
var functionRef = new WasmStructGet(vtableStruct, classRef, index);
|
var functionRef = new WasmStructGet(vtableStruct, classRef, index);
|
||||||
var functionTypeRef = (WasmType.CompositeReference) vtableStruct.getFields().get(index).asUnpackedType();
|
var functionTypeRef = (WasmType.CompositeReference) vtableStruct.getFields().get(index).asUnpackedType();
|
||||||
|
@ -432,7 +444,6 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
|
||||||
result = invocation(expr, null, false);
|
result = invocation(expr, null, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected WasmExpression invocation(InvocationExpr expr, List<WasmExpression> resultConsumer, boolean willDrop) {
|
protected WasmExpression invocation(InvocationExpr expr, List<WasmExpression> resultConsumer, boolean willDrop) {
|
||||||
if (expr.getType() == InvocationType.SPECIAL || expr.getType() == InvocationType.STATIC) {
|
if (expr.getType() == InvocationType.SPECIAL || expr.getType() == InvocationType.STATIC) {
|
||||||
|
|
|
@ -72,6 +72,9 @@ public class WasmGCStringPool implements WasmGCStringProvider, WasmGCInitializer
|
||||||
var value = new WasmCall(nextCharArrayFunction);
|
var value = new WasmCall(nextCharArrayFunction);
|
||||||
function.getBody().add(new WasmStructSet(stringStruct, new WasmGetGlobal(str.global),
|
function.getBody().add(new WasmStructSet(stringStruct, new WasmGetGlobal(str.global),
|
||||||
WasmGCClassInfoProvider.CUSTOM_FIELD_OFFSETS, value));
|
WasmGCClassInfoProvider.CUSTOM_FIELD_OFFSETS, value));
|
||||||
|
function.getBody().add(new WasmStructSet(stringStruct, new WasmGetGlobal(str.global),
|
||||||
|
WasmGCClassInfoProvider.CLASS_FIELD_OFFSET,
|
||||||
|
new WasmGetGlobal(standardClasses.stringClass().getPointer())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,9 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.backend.wasm.model;
|
package org.teavm.backend.wasm.model;
|
||||||
|
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public class WasmFunctionType extends WasmCompositeType {
|
public class WasmFunctionType extends WasmCompositeType {
|
||||||
|
@ -23,6 +25,7 @@ public class WasmFunctionType extends WasmCompositeType {
|
||||||
private WasmType returnType;
|
private WasmType returnType;
|
||||||
private Supplier<List<? extends WasmType>> parameterTypesSupplier;
|
private Supplier<List<? extends WasmType>> parameterTypesSupplier;
|
||||||
private Supplier<WasmType> returnTypeSupplier;
|
private Supplier<WasmType> returnTypeSupplier;
|
||||||
|
private Set<WasmFunctionType> supertypes = new LinkedHashSet<>();
|
||||||
|
|
||||||
public WasmFunctionType(String name, WasmType returnType, List<? extends WasmType> parameterTypes) {
|
public WasmFunctionType(String name, WasmType returnType, List<? extends WasmType> parameterTypes) {
|
||||||
super(name);
|
super(name);
|
||||||
|
@ -53,6 +56,10 @@ public class WasmFunctionType extends WasmCompositeType {
|
||||||
return returnType;
|
return returnType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<WasmFunctionType> getSupertypes() {
|
||||||
|
return supertypes;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void acceptVisitor(WasmCompositeTypeVisitor visitor) {
|
public void acceptVisitor(WasmCompositeTypeVisitor visitor) {
|
||||||
visitor.visit(this);
|
visitor.visit(this);
|
||||||
|
|
|
@ -121,6 +121,7 @@ public class WasmModule {
|
||||||
sorting.original = types;
|
sorting.original = types;
|
||||||
sorting.graph = typeGraph;
|
sorting.graph = typeGraph;
|
||||||
sorting.visited = new boolean[types.size()];
|
sorting.visited = new boolean[types.size()];
|
||||||
|
sorting.sccVisited = new boolean[types.size()];
|
||||||
sorting.sccMap = sccStartNode;
|
sorting.sccMap = sccStartNode;
|
||||||
sorting.sccsByIndex = sccsByIndex;
|
sorting.sccsByIndex = sccsByIndex;
|
||||||
for (var i = 0; i < types.size(); ++i) {
|
for (var i = 0; i < types.size(); ++i) {
|
||||||
|
@ -137,6 +138,7 @@ public class WasmModule {
|
||||||
WasmCollection<WasmCompositeType> original;
|
WasmCollection<WasmCompositeType> original;
|
||||||
Graph graph;
|
Graph graph;
|
||||||
boolean[] visited;
|
boolean[] visited;
|
||||||
|
boolean[] sccVisited;
|
||||||
int[] sccMap;
|
int[] sccMap;
|
||||||
int[][] sccsByIndex;
|
int[][] sccsByIndex;
|
||||||
List<WasmCompositeType> sorted = new ArrayList<>();
|
List<WasmCompositeType> sorted = new ArrayList<>();
|
||||||
|
@ -146,18 +148,46 @@ public class WasmModule {
|
||||||
if (visited[typeIndex]) {
|
if (visited[typeIndex]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
visited[typeIndex] = true;
|
|
||||||
for (var outgoing : graph.outgoingEdges(typeIndex)) {
|
|
||||||
visit(outgoing);
|
|
||||||
}
|
|
||||||
var scc = sccsByIndex[typeIndex];
|
var scc = sccsByIndex[typeIndex];
|
||||||
if (scc == null) {
|
if (scc == null) {
|
||||||
|
visited[typeIndex] = true;
|
||||||
|
for (var outgoing : graph.outgoingEdges(typeIndex)) {
|
||||||
|
visit(outgoing);
|
||||||
|
}
|
||||||
sorted.add(original.get(typeIndex));
|
sorted.add(original.get(typeIndex));
|
||||||
} else {
|
} else {
|
||||||
|
visited[typeIndex] = true;
|
||||||
for (var index : scc) {
|
for (var index : scc) {
|
||||||
sorted.add(original.get(index));
|
for (var outgoing : graph.outgoingEdges(index)) {
|
||||||
|
visit(outgoing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (var index : scc) {
|
||||||
|
visitScc(index, typeIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void visitScc(int index, int sccBase) {
|
||||||
|
if (sccVisited[index]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sccVisited[index] = true;
|
||||||
|
var type = original.get(index);
|
||||||
|
if (type instanceof WasmStructure) {
|
||||||
|
var supertype = ((WasmStructure) type).getSupertype();
|
||||||
|
if (supertype != null && sccMap[supertype.index] == sccBase) {
|
||||||
|
visitScc(supertype.index, sccBase);
|
||||||
|
}
|
||||||
|
} else if (type instanceof WasmFunctionType) {
|
||||||
|
var supertypes = ((WasmFunctionType) type).getSupertypes();
|
||||||
|
for (var supertype : supertypes) {
|
||||||
|
if (sccMap[supertype.index] == sccBase) {
|
||||||
|
visitScc(supertype.index, sccBase);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sorted.add(type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,6 +57,9 @@ final class WasmTypeGraphBuilder {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(WasmFunctionType type) {
|
public void visit(WasmFunctionType type) {
|
||||||
|
for (var supertype : type.getSupertypes()) {
|
||||||
|
addEdge(supertype.getReference());
|
||||||
|
}
|
||||||
for (var parameter : type.getParameterTypes()) {
|
for (var parameter : type.getParameterTypes()) {
|
||||||
addEdge(parameter);
|
addEdge(parameter);
|
||||||
}
|
}
|
||||||
|
|
|
@ -381,6 +381,9 @@ public class WasmBinaryRenderer {
|
||||||
|
|
||||||
var visitor = new WasmBinaryRenderingVisitor(code, module, dwarfGenerator,
|
var visitor = new WasmBinaryRenderingVisitor(code, module, dwarfGenerator,
|
||||||
function.getJavaMethod() != null ? debugLines : null, offset);
|
function.getJavaMethod() != null ? debugLines : null, offset);
|
||||||
|
for (var part : function.getBody()) {
|
||||||
|
visitor.preprocess(part);
|
||||||
|
}
|
||||||
for (var part : function.getBody()) {
|
for (var part : function.getBody()) {
|
||||||
part.acceptVisitor(visitor);
|
part.acceptVisitor(visitor);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,9 +18,11 @@ package org.teavm.backend.wasm.render;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
import org.teavm.backend.wasm.debug.DebugLines;
|
import org.teavm.backend.wasm.debug.DebugLines;
|
||||||
import org.teavm.backend.wasm.generate.DwarfGenerator;
|
import org.teavm.backend.wasm.generate.DwarfGenerator;
|
||||||
import org.teavm.backend.wasm.model.WasmModule;
|
import org.teavm.backend.wasm.model.WasmModule;
|
||||||
|
@ -39,6 +41,7 @@ import org.teavm.backend.wasm.model.expression.WasmCast;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmConditional;
|
import org.teavm.backend.wasm.model.expression.WasmConditional;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmConversion;
|
import org.teavm.backend.wasm.model.expression.WasmConversion;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmCopy;
|
import org.teavm.backend.wasm.model.expression.WasmCopy;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmDefaultExpressionVisitor;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmDrop;
|
import org.teavm.backend.wasm.model.expression.WasmDrop;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmExpressionVisitor;
|
import org.teavm.backend.wasm.model.expression.WasmExpressionVisitor;
|
||||||
|
@ -95,6 +98,7 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
|
||||||
private TextLocation lastEmittedLocation;
|
private TextLocation lastEmittedLocation;
|
||||||
private int positionToEmit;
|
private int positionToEmit;
|
||||||
private List<TextLocation> locationStack = new ArrayList<>();
|
private List<TextLocation> locationStack = new ArrayList<>();
|
||||||
|
private Set<WasmBlock> blocksToPreserve = new HashSet<>();
|
||||||
|
|
||||||
WasmBinaryRenderingVisitor(WasmBinaryWriter writer, WasmModule module,
|
WasmBinaryRenderingVisitor(WasmBinaryWriter writer, WasmModule module,
|
||||||
DwarfGenerator dwarfGenerator, DebugLines debugLines, int addressOffset) {
|
DwarfGenerator dwarfGenerator, DebugLines debugLines, int addressOffset) {
|
||||||
|
@ -105,23 +109,60 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
|
||||||
this.debugLines = debugLines;
|
this.debugLines = debugLines;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void preprocess(WasmExpression expression) {
|
||||||
|
expression.acceptVisitor(new WasmDefaultExpressionVisitor() {
|
||||||
|
@Override
|
||||||
|
public void visit(WasmBranch expression) {
|
||||||
|
super.visit(expression);
|
||||||
|
register(expression.getTarget());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(WasmBreak expression) {
|
||||||
|
super.visit(expression);
|
||||||
|
register(expression.getTarget());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(WasmSwitch expression) {
|
||||||
|
super.visit(expression);
|
||||||
|
for (WasmBlock target : expression.getTargets()) {
|
||||||
|
register(target);
|
||||||
|
}
|
||||||
|
register(expression.getDefaultTarget());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void register(WasmBlock block) {
|
||||||
|
blocksToPreserve.add(block);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(WasmBlock expression) {
|
public void visit(WasmBlock expression) {
|
||||||
pushLocation(expression);
|
if (blocksToPreserve.contains(expression) || expression.isLoop()) {
|
||||||
pushLocation(expression);
|
pushLocation(expression);
|
||||||
int blockDepth = 1;
|
pushLocation(expression);
|
||||||
depth += blockDepth;
|
int blockDepth = 1;
|
||||||
blockDepths.put(expression, depth);
|
depth += blockDepth;
|
||||||
writer.writeByte(expression.isLoop() ? 0x03 : 0x02);
|
blockDepths.put(expression, depth);
|
||||||
writeBlockType(expression.getType());
|
writer.writeByte(expression.isLoop() ? 0x03 : 0x02);
|
||||||
for (WasmExpression part : expression.getBody()) {
|
writeBlockType(expression.getType());
|
||||||
part.acceptVisitor(this);
|
for (WasmExpression part : expression.getBody()) {
|
||||||
|
part.acceptVisitor(this);
|
||||||
|
}
|
||||||
|
popLocation();
|
||||||
|
writer.writeByte(0x0B);
|
||||||
|
popLocation();
|
||||||
|
blockDepths.remove(expression);
|
||||||
|
depth -= blockDepth;
|
||||||
|
} else {
|
||||||
|
pushLocation(expression);
|
||||||
|
for (var part : expression.getBody()) {
|
||||||
|
part.acceptVisitor(this);
|
||||||
|
}
|
||||||
|
popLocation();
|
||||||
}
|
}
|
||||||
popLocation();
|
|
||||||
writer.writeByte(0x0B);
|
|
||||||
popLocation();
|
|
||||||
blockDepths.remove(expression);
|
|
||||||
depth -= blockDepth;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeBlockType(WasmType type) {
|
private void writeBlockType(WasmType type) {
|
||||||
|
|
|
@ -57,6 +57,11 @@ public class WasmCompositeTypeBinaryRenderer implements WasmCompositeTypeVisitor
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(WasmFunctionType type) {
|
public void visit(WasmFunctionType type) {
|
||||||
|
section.writeByte(0x50);
|
||||||
|
section.writeLEB(type.getSupertypes().size());
|
||||||
|
for (var supertype : type.getSupertypes()) {
|
||||||
|
section.writeLEB(module.types.indexOf(supertype));
|
||||||
|
}
|
||||||
section.writeByte(0x60);
|
section.writeByte(0x60);
|
||||||
section.writeLEB(type.getParameterTypes().size());
|
section.writeLEB(type.getParameterTypes().size());
|
||||||
for (var inputType : type.getParameterTypes()) {
|
for (var inputType : type.getParameterTypes()) {
|
||||||
|
|
|
@ -33,6 +33,10 @@ public class WasmGCSupport {
|
||||||
return new ClassCastException();
|
return new ClassCastException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static CloneNotSupportedException cnse() {
|
||||||
|
return new CloneNotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
@Import(name = "putcharStdout")
|
@Import(name = "putcharStdout")
|
||||||
public static native void putCharStdout(char c);
|
public static native void putCharStdout(char c);
|
||||||
|
|
||||||
|
|
|
@ -15,10 +15,12 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.backend.wasm.transformation.gc;
|
package org.teavm.backend.wasm.transformation.gc;
|
||||||
|
|
||||||
|
import org.teavm.backend.wasm.runtime.WasmGCSupport;
|
||||||
import org.teavm.model.ClassHolder;
|
import org.teavm.model.ClassHolder;
|
||||||
import org.teavm.model.ClassHolderTransformer;
|
import org.teavm.model.ClassHolderTransformer;
|
||||||
import org.teavm.model.ClassHolderTransformerContext;
|
import org.teavm.model.ClassHolderTransformerContext;
|
||||||
import org.teavm.model.ElementModifier;
|
import org.teavm.model.ElementModifier;
|
||||||
|
import org.teavm.model.emit.ProgramEmitter;
|
||||||
|
|
||||||
public class BaseClassesTransformation implements ClassHolderTransformer {
|
public class BaseClassesTransformation implements ClassHolderTransformer {
|
||||||
@Override
|
@Override
|
||||||
|
@ -30,6 +32,11 @@ public class BaseClassesTransformation implements ClassHolderTransformer {
|
||||||
method.setProgram(null);
|
method.setProgram(null);
|
||||||
method.getModifiers().add(ElementModifier.NATIVE);
|
method.getModifiers().add(ElementModifier.NATIVE);
|
||||||
break;
|
break;
|
||||||
|
case "clone": {
|
||||||
|
var em = ProgramEmitter.create(method, context.getHierarchy());
|
||||||
|
em.invoke(WasmGCSupport.class, "cnse", CloneNotSupportedException.class).raise();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (cls.getName().equals("java.lang.Class")) {
|
} else if (cls.getName().equals("java.lang.Class")) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user