mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 00:04:10 -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))
|
||||
.use();
|
||||
analyzer.linkMethod(new MethodReference(WasmGCSupport.class, "cce", ClassCastException.class)).use();
|
||||
analyzer.linkMethod(new MethodReference(WasmGCSupport.class, "cnse", CloneNotSupportedException.class)).use();
|
||||
}
|
||||
|
||||
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.WasmIntBinaryOperation;
|
||||
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.WasmLoadFloat64;
|
||||
import org.teavm.backend.wasm.model.expression.WasmLoadInt32;
|
||||
|
@ -302,6 +304,11 @@ public class WasmGenerationVisitor extends BaseWasmGenerationVisitor {
|
|||
return new WasmInt32Constant(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected WasmExpression genIsNull(WasmExpression value) {
|
||||
return new WasmIntUnary(WasmIntType.INT32, WasmIntUnaryOperation.EQZ, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(SubscriptExpr 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.WasmIntBinaryOperation;
|
||||
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.WasmSetLocal;
|
||||
import org.teavm.backend.wasm.model.expression.WasmSwitch;
|
||||
|
@ -902,9 +900,16 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
|
|||
var block = new WasmBlock(false);
|
||||
block.setType(mapType(reference.getReturnType()));
|
||||
|
||||
var instanceVar = tempVars.acquire(instanceWasmType);
|
||||
block.getBody().add(new WasmSetLocal(instanceVar, instance));
|
||||
instance = new WasmGetLocal(instanceVar);
|
||||
WasmLocal instanceVar;
|
||||
var isTemporary = false;
|
||||
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>();
|
||||
arguments.add(instance);
|
||||
|
@ -918,7 +923,9 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
|
|||
var call = generateVirtualCall(instanceVar, reference, arguments);
|
||||
|
||||
block.getBody().add(call);
|
||||
tempVars.release(instanceVar);
|
||||
if (isTemporary) {
|
||||
tempVars.release(instanceVar);
|
||||
}
|
||||
return block;
|
||||
}
|
||||
}
|
||||
|
@ -1133,7 +1140,7 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
|
|||
result.acceptVisitor(typeInference);
|
||||
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));
|
||||
block.getBody().add(new WasmDrop(ifNull));
|
||||
|
||||
|
@ -1171,7 +1178,7 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
|
|||
var wasmSourceType = typeInference.getResult();
|
||||
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());
|
||||
block.getBody().add(new WasmDrop(nullCheck));
|
||||
|
||||
|
@ -1544,9 +1551,7 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
|
|||
}
|
||||
}
|
||||
|
||||
private WasmExpression genIsZero(WasmExpression value) {
|
||||
return new WasmIntUnary(WasmIntType.INT32, WasmIntUnaryOperation.EQZ, value);
|
||||
}
|
||||
protected abstract WasmExpression genIsNull(WasmExpression value);
|
||||
|
||||
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.WasmIntType;
|
||||
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.WasmStructNewDefault;
|
||||
import org.teavm.backend.wasm.model.expression.WasmStructSet;
|
||||
|
@ -122,7 +123,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
|||
standardClasses = new WasmGCStandardClasses(this);
|
||||
strings = new WasmGCStringPool(standardClasses, module, functionProvider);
|
||||
supertypeGenerator = new WasmGCSupertypeFunctionGenerator(module, this, names, tagRegistry, functionTypes);
|
||||
typeMapper = new WasmGCTypeMapper(this);
|
||||
typeMapper = new WasmGCTypeMapper(this, functionTypes, module);
|
||||
}
|
||||
|
||||
public WasmGCSupertypeFunctionProvider getSupertypeProvider() {
|
||||
|
@ -143,6 +144,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
|||
|
||||
@Override
|
||||
public void contributeToInitializerDefinitions(WasmFunction function) {
|
||||
fillVirtualTableSupertypes();
|
||||
for (var classInfo : classInfoMap.values()) {
|
||||
var classInstanceType = classInfo.virtualTableStructure != null
|
||||
? 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
|
||||
public void contributeToInitializer(WasmFunction function) {
|
||||
var classClass = standardClasses.classClass();
|
||||
|
@ -209,7 +240,8 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
|||
fillFields(classInfo, 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())
|
||||
: standardClasses.classClass().getStructure();
|
||||
classInfo.virtualTableStructure = classStructure;
|
||||
|
@ -330,21 +362,30 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
|||
}
|
||||
}
|
||||
if (virtualTable != null && virtualTable.hasValidEntries()) {
|
||||
fillVirtualTableMethods(target, classStructure, classInfo.pointer, virtualTable,
|
||||
virtualTableFieldOffset, name, new HashSet<>());
|
||||
fillVirtualTableMethods(target, classStructure, classInfo.pointer, virtualTable, virtualTable,
|
||||
new HashSet<>());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private int fillVirtualTableMethods(List<WasmExpression> target, WasmStructure structure, WasmGlobal global,
|
||||
VirtualTable virtualTable, int index, String origin, Set<MethodDescriptor> filled) {
|
||||
private void fillVirtualTableMethods(List<WasmExpression> target, WasmStructure structure, WasmGlobal global,
|
||||
VirtualTable virtualTable, VirtualTable original, Set<MethodDescriptor> filled) {
|
||||
if (virtualTable.getParent() != null) {
|
||||
fillVirtualTableMethods(target, structure, global, virtualTable.getParent(), original, filled);
|
||||
}
|
||||
for (var method : virtualTable.getMethods()) {
|
||||
var entry = virtualTable.getEntry(method);
|
||||
var entry = original.getEntry(method);
|
||||
if (entry != null && entry.getImplementor() != null && filled.add(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());
|
||||
if (!origin.equals(entry.getImplementor().getClassName())) {
|
||||
var functionType = getFunctionType(virtualTable.getClassName(), method);
|
||||
if (!virtualTable.getClassName().equals(entry.getImplementor().getClassName())
|
||||
|| expectedFunctionType != function.getType()) {
|
||||
var functionType = typeMapper.getFunctionType(virtualTable.getClassName(), method, true);
|
||||
functionType.getSupertypes().add(expectedFunctionType);
|
||||
var wrapperFunction = new WasmFunction(functionType);
|
||||
module.functions.add(wrapperFunction);
|
||||
var call = new WasmCall(function);
|
||||
|
@ -358,17 +399,14 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
|||
call.getArguments().add(new WasmGetLocal(params[i]));
|
||||
wrapperFunction.add(params[i]);
|
||||
}
|
||||
wrapperFunction.getBody().add(new WasmReturn(call));
|
||||
function = wrapperFunction;
|
||||
}
|
||||
function.setReferenced(true);
|
||||
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) {
|
||||
|
@ -391,23 +429,12 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
|||
if (methodDesc == null) {
|
||||
structure.getFields().add(WasmType.Reference.FUNC.asStorage());
|
||||
} else {
|
||||
var functionType = getFunctionType(virtualTable.getClassName(), methodDesc);
|
||||
var functionType = typeMapper.getFunctionType(virtualTable.getClassName(), methodDesc, false);
|
||||
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) {
|
||||
classInfo.initializer = target -> {
|
||||
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")) {
|
||||
continue;
|
||||
}
|
||||
if (className.equals("java.lang.Class") && field.getName().equals("platformClass")) {
|
||||
continue;
|
||||
}
|
||||
if (field.hasModifier(ElementModifier.STATIC)) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ public class WasmGCClassInfo {
|
|||
private ValueType valueType;
|
||||
WasmStructure structure;
|
||||
WasmArray array;
|
||||
boolean hasOwnVirtualTable;
|
||||
WasmStructure virtualTableStructure;
|
||||
WasmGlobal pointer;
|
||||
WasmGlobal initializerPointer;
|
||||
|
|
|
@ -15,16 +15,26 @@
|
|||
*/
|
||||
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.WasmStorageType;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
import org.teavm.model.MethodDescriptor;
|
||||
import org.teavm.model.ValueType;
|
||||
|
||||
public class WasmGCTypeMapper {
|
||||
private WasmGCClassInfoProvider classInfoProvider;
|
||||
private WasmFunctionTypes functionTypes;
|
||||
private WasmModule module;
|
||||
|
||||
WasmGCTypeMapper(WasmGCClassInfoProvider classInfoProvider) {
|
||||
WasmGCTypeMapper(WasmGCClassInfoProvider classInfoProvider, WasmFunctionTypes functionTypes,
|
||||
WasmModule module) {
|
||||
this.classInfoProvider = classInfoProvider;
|
||||
this.functionTypes = functionTypes;
|
||||
this.module = module;
|
||||
}
|
||||
|
||||
public WasmStorageType mapStorageType(ValueType type) {
|
||||
|
@ -76,4 +86,21 @@ public class WasmGCTypeMapper {
|
|||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected WasmExpression genIsNull(WasmExpression value) {
|
||||
return new WasmReferencesEqual(value, new WasmNullConstant(WasmType.Reference.STRUCT));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CallSiteIdentifier generateCallSiteId(TextLocation location) {
|
||||
return new SimpleCallSite();
|
||||
|
@ -268,12 +273,19 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
|
|||
}
|
||||
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),
|
||||
WasmGCClassInfoProvider.CLASS_FIELD_OFFSET);
|
||||
var index = context.classInfoProvider().getVirtualMethodsOffset() + vtableIndex;
|
||||
var vtableStruct = context.classInfoProvider().getClassInfo(vtable.getClassName())
|
||||
.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 functionTypeRef = (WasmType.CompositeReference) vtableStruct.getFields().get(index).asUnpackedType();
|
||||
|
@ -432,7 +444,6 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
|
|||
result = invocation(expr, null, false);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected WasmExpression invocation(InvocationExpr expr, List<WasmExpression> resultConsumer, boolean willDrop) {
|
||||
if (expr.getType() == InvocationType.SPECIAL || expr.getType() == InvocationType.STATIC) {
|
||||
|
|
|
@ -72,6 +72,9 @@ public class WasmGCStringPool implements WasmGCStringProvider, WasmGCInitializer
|
|||
var value = new WasmCall(nextCharArrayFunction);
|
||||
function.getBody().add(new WasmStructSet(stringStruct, new WasmGetGlobal(str.global),
|
||||
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;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class WasmFunctionType extends WasmCompositeType {
|
||||
|
@ -23,6 +25,7 @@ public class WasmFunctionType extends WasmCompositeType {
|
|||
private WasmType returnType;
|
||||
private Supplier<List<? extends WasmType>> parameterTypesSupplier;
|
||||
private Supplier<WasmType> returnTypeSupplier;
|
||||
private Set<WasmFunctionType> supertypes = new LinkedHashSet<>();
|
||||
|
||||
public WasmFunctionType(String name, WasmType returnType, List<? extends WasmType> parameterTypes) {
|
||||
super(name);
|
||||
|
@ -53,6 +56,10 @@ public class WasmFunctionType extends WasmCompositeType {
|
|||
return returnType;
|
||||
}
|
||||
|
||||
public Set<WasmFunctionType> getSupertypes() {
|
||||
return supertypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptVisitor(WasmCompositeTypeVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
|
|
|
@ -121,6 +121,7 @@ public class WasmModule {
|
|||
sorting.original = types;
|
||||
sorting.graph = typeGraph;
|
||||
sorting.visited = new boolean[types.size()];
|
||||
sorting.sccVisited = new boolean[types.size()];
|
||||
sorting.sccMap = sccStartNode;
|
||||
sorting.sccsByIndex = sccsByIndex;
|
||||
for (var i = 0; i < types.size(); ++i) {
|
||||
|
@ -137,6 +138,7 @@ public class WasmModule {
|
|||
WasmCollection<WasmCompositeType> original;
|
||||
Graph graph;
|
||||
boolean[] visited;
|
||||
boolean[] sccVisited;
|
||||
int[] sccMap;
|
||||
int[][] sccsByIndex;
|
||||
List<WasmCompositeType> sorted = new ArrayList<>();
|
||||
|
@ -146,18 +148,46 @@ public class WasmModule {
|
|||
if (visited[typeIndex]) {
|
||||
return;
|
||||
}
|
||||
visited[typeIndex] = true;
|
||||
for (var outgoing : graph.outgoingEdges(typeIndex)) {
|
||||
visit(outgoing);
|
||||
}
|
||||
var scc = sccsByIndex[typeIndex];
|
||||
if (scc == null) {
|
||||
visited[typeIndex] = true;
|
||||
for (var outgoing : graph.outgoingEdges(typeIndex)) {
|
||||
visit(outgoing);
|
||||
}
|
||||
sorted.add(original.get(typeIndex));
|
||||
} else {
|
||||
visited[typeIndex] = true;
|
||||
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
|
||||
public void visit(WasmFunctionType type) {
|
||||
for (var supertype : type.getSupertypes()) {
|
||||
addEdge(supertype.getReference());
|
||||
}
|
||||
for (var parameter : type.getParameterTypes()) {
|
||||
addEdge(parameter);
|
||||
}
|
||||
|
|
|
@ -381,6 +381,9 @@ public class WasmBinaryRenderer {
|
|||
|
||||
var visitor = new WasmBinaryRenderingVisitor(code, module, dwarfGenerator,
|
||||
function.getJavaMethod() != null ? debugLines : null, offset);
|
||||
for (var part : function.getBody()) {
|
||||
visitor.preprocess(part);
|
||||
}
|
||||
for (var part : function.getBody()) {
|
||||
part.acceptVisitor(visitor);
|
||||
}
|
||||
|
|
|
@ -18,9 +18,11 @@ package org.teavm.backend.wasm.render;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import org.teavm.backend.wasm.debug.DebugLines;
|
||||
import org.teavm.backend.wasm.generate.DwarfGenerator;
|
||||
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.WasmConversion;
|
||||
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.WasmExpression;
|
||||
import org.teavm.backend.wasm.model.expression.WasmExpressionVisitor;
|
||||
|
@ -95,6 +98,7 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
|
|||
private TextLocation lastEmittedLocation;
|
||||
private int positionToEmit;
|
||||
private List<TextLocation> locationStack = new ArrayList<>();
|
||||
private Set<WasmBlock> blocksToPreserve = new HashSet<>();
|
||||
|
||||
WasmBinaryRenderingVisitor(WasmBinaryWriter writer, WasmModule module,
|
||||
DwarfGenerator dwarfGenerator, DebugLines debugLines, int addressOffset) {
|
||||
|
@ -105,23 +109,60 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
|
|||
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
|
||||
public void visit(WasmBlock expression) {
|
||||
pushLocation(expression);
|
||||
pushLocation(expression);
|
||||
int blockDepth = 1;
|
||||
depth += blockDepth;
|
||||
blockDepths.put(expression, depth);
|
||||
writer.writeByte(expression.isLoop() ? 0x03 : 0x02);
|
||||
writeBlockType(expression.getType());
|
||||
for (WasmExpression part : expression.getBody()) {
|
||||
part.acceptVisitor(this);
|
||||
if (blocksToPreserve.contains(expression) || expression.isLoop()) {
|
||||
pushLocation(expression);
|
||||
pushLocation(expression);
|
||||
int blockDepth = 1;
|
||||
depth += blockDepth;
|
||||
blockDepths.put(expression, depth);
|
||||
writer.writeByte(expression.isLoop() ? 0x03 : 0x02);
|
||||
writeBlockType(expression.getType());
|
||||
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) {
|
||||
|
|
|
@ -57,6 +57,11 @@ public class WasmCompositeTypeBinaryRenderer implements WasmCompositeTypeVisitor
|
|||
|
||||
@Override
|
||||
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.writeLEB(type.getParameterTypes().size());
|
||||
for (var inputType : type.getParameterTypes()) {
|
||||
|
|
|
@ -33,6 +33,10 @@ public class WasmGCSupport {
|
|||
return new ClassCastException();
|
||||
}
|
||||
|
||||
public static CloneNotSupportedException cnse() {
|
||||
return new CloneNotSupportedException();
|
||||
}
|
||||
|
||||
@Import(name = "putcharStdout")
|
||||
public static native void putCharStdout(char c);
|
||||
|
||||
|
|
|
@ -15,10 +15,12 @@
|
|||
*/
|
||||
package org.teavm.backend.wasm.transformation.gc;
|
||||
|
||||
import org.teavm.backend.wasm.runtime.WasmGCSupport;
|
||||
import org.teavm.model.ClassHolder;
|
||||
import org.teavm.model.ClassHolderTransformer;
|
||||
import org.teavm.model.ClassHolderTransformerContext;
|
||||
import org.teavm.model.ElementModifier;
|
||||
import org.teavm.model.emit.ProgramEmitter;
|
||||
|
||||
public class BaseClassesTransformation implements ClassHolderTransformer {
|
||||
@Override
|
||||
|
@ -30,6 +32,11 @@ public class BaseClassesTransformation implements ClassHolderTransformer {
|
|||
method.setProgram(null);
|
||||
method.getModifiers().add(ElementModifier.NATIVE);
|
||||
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")) {
|
||||
|
|
Loading…
Reference in New Issue
Block a user