Introduce concept of 'weak' cast.

Use weak casts to maintain proper typing within methods during various operations on IR. At generation level, ignore weak casts, except for Wasm GC BE, which turns weak casts into platform casts.
This commit is contained in:
Alexey Andreev 2024-08-18 18:47:04 +02:00
parent 8b52741e04
commit a97e6574ac
33 changed files with 84 additions and 136 deletions

View File

@ -21,6 +21,7 @@ import org.teavm.model.ValueType;
public class CastExpr extends Expr { public class CastExpr extends Expr {
private Expr value; private Expr value;
private ValueType target; private ValueType target;
private boolean weak;
public Expr getValue() { public Expr getValue() {
return value; return value;
@ -38,6 +39,14 @@ public class CastExpr extends Expr {
this.target = target; this.target = target;
} }
public boolean isWeak() {
return weak;
}
public void setWeak(boolean weak) {
this.weak = weak;
}
@Override @Override
public void acceptVisitor(ExprVisitor visitor) { public void acceptVisitor(ExprVisitor visitor) {
visitor.visit(this); visitor.visit(this);
@ -48,6 +57,7 @@ public class CastExpr extends Expr {
CastExpr copy = new CastExpr(); CastExpr copy = new CastExpr();
copy.value = value.clone(cache); copy.value = value.clone(cache);
copy.target = target; copy.target = target;
copy.weak = weak;
return copy; return copy;
} }
} }

View File

@ -214,6 +214,7 @@ class StatementGenerator implements InstructionVisitor {
expr.setVariableIndex(insn.getReceiver().getIndex()); expr.setVariableIndex(insn.getReceiver().getIndex());
expr.setValue(Expr.var(insn.getValue().getIndex())); expr.setValue(Expr.var(insn.getValue().getIndex()));
expr.setTarget(insn.getTargetType()); expr.setTarget(insn.getTargetType());
expr.setWeak(insn.isWeak());
assign(expr, insn.getReceiver()); assign(expr, insn.getReceiver());
} }

View File

@ -1056,6 +1056,11 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor {
@Override @Override
public void visit(CastExpr expr) { public void visit(CastExpr expr) {
if (expr.isWeak()) {
expr.getValue().acceptVisitor(this);
return;
}
if (expr.getTarget() instanceof ValueType.Object) { if (expr.getTarget() instanceof ValueType.Object) {
String className = ((ValueType.Object) expr.getTarget()).getClassName(); String className = ((ValueType.Object) expr.getTarget()).getClassName();
if (!context.getCharacteristics().isManaged(className)) { if (!context.getCharacteristics().isManaged(className)) {

View File

@ -878,7 +878,7 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
@Override @Override
public void visit(CastExpr expr) { public void visit(CastExpr expr) {
if (context.isStrict()) { if (context.isStrict() && !expr.isWeak()) {
if (expr.getLocation() != null) { if (expr.getLocation() != null) {
pushLocation(expr.getLocation()); pushLocation(expr.getLocation());
} }

View File

@ -20,19 +20,15 @@ import org.teavm.model.MethodReference;
import org.teavm.model.Program; import org.teavm.model.Program;
import org.teavm.model.ValueType; import org.teavm.model.ValueType;
import org.teavm.model.analysis.BaseTypeInference; import org.teavm.model.analysis.BaseTypeInference;
import org.teavm.model.instructions.InvocationType;
public class PreciseTypeInference extends BaseTypeInference<PreciseValueType> { public class PreciseTypeInference extends BaseTypeInference<PreciseValueType> {
public static final PreciseValueType OBJECT_TYPE = new PreciseValueType(ValueType.object("java.lang.Object"), public static final PreciseValueType OBJECT_TYPE = new PreciseValueType(ValueType.object("java.lang.Object"),
false); false);
private ClassHierarchy hierarchy; private ClassHierarchy hierarchy;
private WasmGCMethodReturnTypes returnTypes;
public PreciseTypeInference(Program program, MethodReference reference, ClassHierarchy hierarchy, public PreciseTypeInference(Program program, MethodReference reference, ClassHierarchy hierarchy) {
WasmGCMethodReturnTypes returnTypes) {
super(program, reference); super(program, reference);
this.hierarchy = hierarchy; this.hierarchy = hierarchy;
this.returnTypes = returnTypes;
} }
@Override @Override
@ -108,14 +104,6 @@ public class PreciseTypeInference extends BaseTypeInference<PreciseValueType> {
return new PreciseValueType(ValueType.arrayOf(preciseValueType.valueType), false); return new PreciseValueType(ValueType.arrayOf(preciseValueType.valueType), false);
} }
@Override
protected PreciseValueType methodReturnType(InvocationType invocationType, MethodReference methodRef) {
if (invocationType == InvocationType.SPECIAL) {
return new PreciseValueType(returnTypes.returnTypeOf(methodRef), false);
}
return super.methodReturnType(invocationType, methodRef);
}
@Override @Override
protected PreciseValueType arrayUnwrapType(PreciseValueType type) { protected PreciseValueType arrayUnwrapType(PreciseValueType type) {
return new PreciseValueType(type.valueType, true); return new PreciseValueType(type.valueType, true);

View File

@ -1,64 +0,0 @@
/*
* 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.gc;
import java.util.HashMap;
import java.util.Map;
import org.teavm.dependency.DependencyInfo;
import org.teavm.model.ClassHierarchy;
import org.teavm.model.MethodReference;
import org.teavm.model.ValueType;
public class WasmGCMethodReturnTypes {
private DependencyInfo dependencyInfo;
private ClassHierarchy hierarchy;
private Map<MethodReference, ValueType> cache = new HashMap<>();
public WasmGCMethodReturnTypes(DependencyInfo dependencyInfo, ClassHierarchy hierarchy) {
this.dependencyInfo = dependencyInfo;
this.hierarchy = hierarchy;
}
public ValueType returnTypeOf(MethodReference reference) {
return cache.computeIfAbsent(reference, this::calculateReturnType);
}
private ValueType calculateReturnType(MethodReference reference) {
if (!(reference.getReturnType() instanceof ValueType.Object)) {
return reference.getReturnType();
}
var method = dependencyInfo.getMethod(reference);
if (method == null) {
return reference.getReturnType();
}
var types = method.getResult().getTypes();
if (types.length == 0) {
return reference.getReturnType();
}
var type = hierarchy.getClassSource().get(types[0]);
if (type == null) {
return reference.getReturnType();
}
for (var i = 1; i < types.length; ++i) {
var otherType = hierarchy.getClassSource().get(types[i]);
if (otherType == null) {
return reference.getReturnType();
}
type = hierarchy.getClassSource().get(WasmGCUtil.findCommonSuperclass(hierarchy, type, otherType));
}
return ValueType.object(type.getName());
}
}

View File

@ -23,11 +23,9 @@ import org.teavm.model.util.VariableCategoryProvider;
public class WasmGCVariableCategoryProvider implements VariableCategoryProvider { public class WasmGCVariableCategoryProvider implements VariableCategoryProvider {
private ClassHierarchy hierarchy; private ClassHierarchy hierarchy;
private PreciseTypeInference inference; private PreciseTypeInference inference;
private WasmGCMethodReturnTypes returnTypes;
public WasmGCVariableCategoryProvider(ClassHierarchy hierarchy, WasmGCMethodReturnTypes returnTypes) { public WasmGCVariableCategoryProvider(ClassHierarchy hierarchy) {
this.hierarchy = hierarchy; this.hierarchy = hierarchy;
this.returnTypes = returnTypes;
} }
public PreciseTypeInference getTypeInference() { public PreciseTypeInference getTypeInference() {
@ -36,7 +34,7 @@ public class WasmGCVariableCategoryProvider implements VariableCategoryProvider
@Override @Override
public Object[] getCategories(Program program, MethodReference method) { public Object[] getCategories(Program program, MethodReference method) {
inference = new PreciseTypeInference(program, method, hierarchy, returnTypes); inference = new PreciseTypeInference(program, method, hierarchy);
inference.setPhisSkipped(true); inference.setPhisSkipped(true);
inference.setBackPropagation(true); inference.setBackPropagation(true);
var result = new Object[program.variableCount()]; var result = new Object[program.variableCount()];

View File

@ -1170,6 +1170,11 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
@Override @Override
public void visit(CastExpr expr) { public void visit(CastExpr expr) {
if (expr.isWeak()) {
acceptWithType(expr.getValue(), expr.getTarget());
result = generateCast(result, mapType(expr.getTarget()));
return;
}
var block = new WasmBlock(false); var block = new WasmBlock(false);
var wasmTargetType = mapType(expr.getTarget()); var wasmTargetType = mapType(expr.getTarget());
block.setType(wasmTargetType); block.setType(wasmTargetType);

View File

@ -19,7 +19,6 @@ import java.util.List;
import java.util.function.Predicate; import java.util.function.Predicate;
import org.teavm.backend.wasm.BaseWasmFunctionRepository; import org.teavm.backend.wasm.BaseWasmFunctionRepository;
import org.teavm.backend.wasm.WasmFunctionTypes; import org.teavm.backend.wasm.WasmFunctionTypes;
import org.teavm.backend.wasm.gc.WasmGCMethodReturnTypes;
import org.teavm.backend.wasm.generate.WasmNameProvider; import org.teavm.backend.wasm.generate.WasmNameProvider;
import org.teavm.backend.wasm.generate.gc.classes.WasmGCClassGenerator; import org.teavm.backend.wasm.generate.gc.classes.WasmGCClassGenerator;
import org.teavm.backend.wasm.generate.gc.classes.WasmGCClassInfoProvider; import org.teavm.backend.wasm.generate.gc.classes.WasmGCClassInfoProvider;
@ -47,7 +46,6 @@ public class WasmGCDeclarationsGenerator {
public final WasmFunctionTypes functionTypes; public final WasmFunctionTypes functionTypes;
private final WasmGCClassGenerator classGenerator; private final WasmGCClassGenerator classGenerator;
private final WasmGCMethodGenerator methodGenerator; private final WasmGCMethodGenerator methodGenerator;
private final WasmGCMethodReturnTypes returnTypes;
public WasmGCDeclarationsGenerator( public WasmGCDeclarationsGenerator(
WasmModule module, WasmModule module,
@ -64,7 +62,6 @@ public class WasmGCDeclarationsGenerator {
var virtualTables = createVirtualTableProvider(classes, virtualMethods); var virtualTables = createVirtualTableProvider(classes, virtualMethods);
functionTypes = new WasmFunctionTypes(module); functionTypes = new WasmFunctionTypes(module);
var names = new WasmNameProvider(); var names = new WasmNameProvider();
returnTypes = new WasmGCMethodReturnTypes(dependencyInfo, hierarchy);
methodGenerator = new WasmGCMethodGenerator( methodGenerator = new WasmGCMethodGenerator(
module, module,
hierarchy, hierarchy,
@ -74,7 +71,6 @@ public class WasmGCDeclarationsGenerator {
functionTypes, functionTypes,
names, names,
diagnostics, diagnostics,
returnTypes,
customGenerators, customGenerators,
intrinsics intrinsics
); );

View File

@ -23,7 +23,6 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import org.teavm.backend.wasm.BaseWasmFunctionRepository; import org.teavm.backend.wasm.BaseWasmFunctionRepository;
import org.teavm.backend.wasm.WasmFunctionTypes; import org.teavm.backend.wasm.WasmFunctionTypes;
import org.teavm.backend.wasm.gc.WasmGCMethodReturnTypes;
import org.teavm.backend.wasm.generate.common.methods.BaseWasmGenerationContext; 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.WasmGCClassInfoProvider;
import org.teavm.backend.wasm.generate.gc.classes.WasmGCStandardClasses; import org.teavm.backend.wasm.generate.gc.classes.WasmGCStandardClasses;
@ -57,7 +56,6 @@ public class WasmGCGenerationContext implements BaseWasmGenerationContext {
private WasmGCSupertypeFunctionProvider supertypeFunctions; private WasmGCSupertypeFunctionProvider supertypeFunctions;
private WasmGCCustomGeneratorProvider customGenerators; private WasmGCCustomGeneratorProvider customGenerators;
private WasmGCIntrinsicProvider intrinsics; private WasmGCIntrinsicProvider intrinsics;
private WasmGCMethodReturnTypes returnTypes;
private WasmFunction npeMethod; private WasmFunction npeMethod;
private WasmFunction aaiobeMethod; private WasmFunction aaiobeMethod;
private WasmFunction cceMethod; private WasmFunction cceMethod;
@ -70,8 +68,7 @@ public class WasmGCGenerationContext implements BaseWasmGenerationContext {
ClassHierarchy hierarchy, BaseWasmFunctionRepository functions, ClassHierarchy hierarchy, BaseWasmFunctionRepository functions,
WasmGCSupertypeFunctionProvider supertypeFunctions, WasmGCClassInfoProvider classInfoProvider, WasmGCSupertypeFunctionProvider supertypeFunctions, WasmGCClassInfoProvider classInfoProvider,
WasmGCStandardClasses standardClasses, WasmGCStringProvider strings, WasmGCStandardClasses standardClasses, WasmGCStringProvider strings,
WasmGCCustomGeneratorProvider customGenerators, WasmGCIntrinsicProvider intrinsics, WasmGCCustomGeneratorProvider customGenerators, WasmGCIntrinsicProvider intrinsics) {
WasmGCMethodReturnTypes returnTypes) {
this.module = module; this.module = module;
this.virtualTables = virtualTables; this.virtualTables = virtualTables;
this.typeMapper = typeMapper; this.typeMapper = typeMapper;
@ -85,7 +82,6 @@ public class WasmGCGenerationContext implements BaseWasmGenerationContext {
this.strings = strings; this.strings = strings;
this.customGenerators = customGenerators; this.customGenerators = customGenerators;
this.intrinsics = intrinsics; this.intrinsics = intrinsics;
this.returnTypes = returnTypes;
} }
public WasmGCClassInfoProvider classInfoProvider() { public WasmGCClassInfoProvider classInfoProvider() {
@ -186,10 +182,6 @@ public class WasmGCGenerationContext implements BaseWasmGenerationContext {
return intrinsics; return intrinsics;
} }
public WasmGCMethodReturnTypes returnTypes() {
return returnTypes;
}
public Collection<String> getInterfaceImplementors(String className) { public Collection<String> getInterfaceImplementors(String className) {
if (interfaceImplementors == null) { if (interfaceImplementors == null) {
fillInterfaceImplementors(); fillInterfaceImplementors();

View File

@ -481,7 +481,7 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
@Override @Override
protected WasmExpression forceType(WasmExpression expression, ValueType type) { protected WasmExpression forceType(WasmExpression expression, ValueType type) {
return forceType(expression, mapType(context.returnTypes().returnTypeOf(currentMethod))); return forceType(expression, mapType(currentMethod.getReturnType()));
} }
private WasmExpression forceType(WasmExpression expression, WasmType expectedType) { private WasmExpression forceType(WasmExpression expression, WasmType expectedType) {

View File

@ -25,7 +25,6 @@ import org.teavm.ast.decompilation.Decompiler;
import org.teavm.backend.lowlevel.generate.NameProvider; import org.teavm.backend.lowlevel.generate.NameProvider;
import org.teavm.backend.wasm.BaseWasmFunctionRepository; import org.teavm.backend.wasm.BaseWasmFunctionRepository;
import org.teavm.backend.wasm.WasmFunctionTypes; import org.teavm.backend.wasm.WasmFunctionTypes;
import org.teavm.backend.wasm.gc.WasmGCMethodReturnTypes;
import org.teavm.backend.wasm.gc.WasmGCVariableCategoryProvider; import org.teavm.backend.wasm.gc.WasmGCVariableCategoryProvider;
import org.teavm.backend.wasm.generate.gc.classes.WasmGCClassInfoProvider; 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.WasmGCStandardClasses;
@ -78,7 +77,6 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
private WasmGCClassInfoProvider classInfoProvider; private WasmGCClassInfoProvider classInfoProvider;
private WasmGCStandardClasses standardClasses; private WasmGCStandardClasses standardClasses;
private WasmGCStringProvider strings; private WasmGCStringProvider strings;
private WasmGCMethodReturnTypes returnTypes;
public WasmGCMethodGenerator( public WasmGCMethodGenerator(
WasmModule module, WasmModule module,
@ -89,7 +87,6 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
WasmFunctionTypes functionTypes, WasmFunctionTypes functionTypes,
NameProvider names, NameProvider names,
Diagnostics diagnostics, Diagnostics diagnostics,
WasmGCMethodReturnTypes returnTypes,
WasmGCCustomGeneratorProvider customGenerators, WasmGCCustomGeneratorProvider customGenerators,
WasmGCIntrinsicProvider intrinsics WasmGCIntrinsicProvider intrinsics
) { ) {
@ -101,7 +98,6 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
this.functionTypes = functionTypes; this.functionTypes = functionTypes;
this.names = names; this.names = names;
this.diagnostics = diagnostics; this.diagnostics = diagnostics;
this.returnTypes = returnTypes;
this.customGenerators = customGenerators; this.customGenerators = customGenerators;
this.intrinsics = intrinsics; this.intrinsics = intrinsics;
} }
@ -146,7 +142,7 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
} }
private WasmFunction createStaticFunction(MethodReference methodReference) { private WasmFunction createStaticFunction(MethodReference methodReference) {
var returnType = typeMapper.mapType(returnTypes.returnTypeOf(methodReference)); var returnType = typeMapper.mapType(methodReference.getReturnType());
var parameterTypes = new WasmType[methodReference.parameterCount()]; var parameterTypes = new WasmType[methodReference.parameterCount()];
for (var i = 0; i < parameterTypes.length; ++i) { for (var i = 0; i < parameterTypes.length; ++i) {
parameterTypes[i] = typeMapper.mapType(methodReference.parameterType(i)); parameterTypes[i] = typeMapper.mapType(methodReference.parameterType(i));
@ -173,7 +169,7 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
} }
private WasmFunction createInstanceFunction(MethodReference methodReference) { private WasmFunction createInstanceFunction(MethodReference methodReference) {
var returnType = typeMapper.mapType(returnTypes.returnTypeOf(methodReference)); var returnType = typeMapper.mapType(methodReference.getReturnType());
var parameterTypes = new WasmType[methodReference.parameterCount() + 1]; var parameterTypes = new WasmType[methodReference.parameterCount() + 1];
parameterTypes[0] = typeMapper.mapType(ValueType.object(methodReference.getClassName())); parameterTypes[0] = typeMapper.mapType(ValueType.object(methodReference.getClassName()));
for (var i = 0; i < methodReference.parameterCount(); ++i) { for (var i = 0; i < methodReference.parameterCount(); ++i) {
@ -213,7 +209,7 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
private void generateRegularMethodBody(MethodHolder method, WasmFunction function) { private void generateRegularMethodBody(MethodHolder method, WasmFunction function) {
var decompiler = getDecompiler(); var decompiler = getDecompiler();
var categoryProvider = new WasmGCVariableCategoryProvider(hierarchy, returnTypes); var categoryProvider = new WasmGCVariableCategoryProvider(hierarchy);
var allocator = new RegisterAllocator(categoryProvider); var allocator = new RegisterAllocator(categoryProvider);
allocator.allocateRegisters(method.getReference(), method.getProgram(), friendlyToDebugger); allocator.allocateRegisters(method.getReference(), method.getProgram(), friendlyToDebugger);
var ast = decompiler.decompileRegular(method); var ast = decompiler.decompileRegular(method);
@ -302,8 +298,7 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
standardClasses, standardClasses,
strings, strings,
customGenerators, customGenerators,
intrinsics, intrinsics
returnTypes
); );
} }
return context; return context;

View File

@ -714,6 +714,7 @@ public class AstIO {
output.writeUnsigned(23); output.writeUnsigned(23);
output.writeUnsigned(symbolTable.lookup(expr.getTarget().toString())); output.writeUnsigned(symbolTable.lookup(expr.getTarget().toString()));
writeExpr(expr.getValue()); writeExpr(expr.getValue());
output.writeUnsigned(expr.isWeak() ? 1 : 0);
} catch (IOException e) { } catch (IOException e) {
throw new IOExceptionWrapper(e); throw new IOExceptionWrapper(e);
} }
@ -1106,6 +1107,7 @@ public class AstIO {
expr.setLocation(lastReadLocation); expr.setLocation(lastReadLocation);
expr.setTarget(ValueType.parse(symbolTable.at(input.readUnsigned()))); expr.setTarget(ValueType.parse(symbolTable.at(input.readUnsigned())));
expr.setValue(readExpr(input)); expr.setValue(readExpr(input));
expr.setWeak(input.readUnsigned() != 0);
return expr; return expr;
} }
case 24: { case 24: {

View File

@ -451,12 +451,13 @@ public class ProgramIO {
} }
@Override @Override
public void cast(VariableReader receiver, VariableReader value, ValueType targetType) { public void cast(VariableReader receiver, VariableReader value, ValueType targetType, boolean weak) {
try { try {
output.writeUnsigned(25); output.writeUnsigned(25);
output.writeUnsigned(receiver.getIndex()); output.writeUnsigned(receiver.getIndex());
output.writeUnsigned(symbolTable.lookup(targetType.toString())); output.writeUnsigned(symbolTable.lookup(targetType.toString()));
output.writeUnsigned(value.getIndex()); output.writeUnsigned(value.getIndex());
output.writeUnsigned(weak ? 1 : 0);
} catch (IOException e) { } catch (IOException e) {
throw new IOExceptionWrapper(e); throw new IOExceptionWrapper(e);
} }
@ -988,6 +989,7 @@ public class ProgramIO {
insn.setReceiver(program.variableAt(input.readUnsigned())); insn.setReceiver(program.variableAt(input.readUnsigned()));
insn.setTargetType(parseValueType(symbolTable.at(input.readUnsigned()))); insn.setTargetType(parseValueType(symbolTable.at(input.readUnsigned())));
insn.setValue(program.variableAt(input.readUnsigned())); insn.setValue(program.variableAt(input.readUnsigned()));
insn.setWeak(input.readUnsigned() != 0);
return insn; return insn;
} }
case 26: { case 26: {

View File

@ -228,12 +228,14 @@ abstract class AbstractInstructionAnalyzer extends AbstractInstructionReader {
} }
@Override @Override
public void cast(VariableReader receiver, VariableReader value, ValueType targetType) { public void cast(VariableReader receiver, VariableReader value, ValueType targetType, boolean weak) {
String className = extractClassName(targetType); if (!weak) {
if (className != null) { String className = extractClassName(targetType);
getAnalyzer().linkClass(className); if (className != null) {
getAnalyzer().linkClass(className);
}
getAnalyzer().linkClass("java.lang.ClassCastException");
} }
getAnalyzer().linkClass("java.lang.ClassCastException");
} }
@Override @Override

View File

@ -95,7 +95,7 @@ class ClassClosureAnalyzer extends AbstractInstructionReader {
} }
@Override @Override
public void cast(VariableReader receiver, VariableReader value, ValueType targetType) { public void cast(VariableReader receiver, VariableReader value, ValueType targetType, boolean weak) {
build(targetType); build(targetType);
} }

View File

@ -143,7 +143,7 @@ public class DataFlowGraphBuilder extends AbstractInstructionReader {
} }
@Override @Override
public void cast(VariableReader receiver, VariableReader value, ValueType targetType) { public void cast(VariableReader receiver, VariableReader value, ValueType targetType, boolean weak) {
builder.addEdge(value.getIndex(), receiver.getIndex()); builder.addEdge(value.getIndex(), receiver.getIndex());
} }

View File

@ -221,9 +221,11 @@ class DependencyGraphBuilder {
} }
@Override @Override
public void cast(VariableReader receiver, VariableReader value, ValueType targetType) { public void cast(VariableReader receiver, VariableReader value, ValueType targetType, boolean weak) {
super.cast(receiver, value, targetType); super.cast(receiver, value, targetType, weak);
currentExceptionConsumer.consume(dependencyAnalyzer.getType("java.lang.ClassCastException")); if (!weak) {
currentExceptionConsumer.consume(dependencyAnalyzer.getType("java.lang.ClassCastException"));
}
DependencyNode valueNode = nodes[value.getIndex()]; DependencyNode valueNode = nodes[value.getIndex()];
DependencyNode receiverNode = nodes[receiver.getIndex()]; DependencyNode receiverNode = nodes[receiver.getIndex()];
ClassReaderSource classSource = dependencyAnalyzer.getClassSource(); ClassReaderSource classSource = dependencyAnalyzer.getClassSource();

View File

@ -83,7 +83,7 @@ public class InstructionReadVisitor implements InstructionVisitor {
@Override @Override
public void visit(CastInstruction insn) { public void visit(CastInstruction insn) {
reader.cast(insn.getReceiver(), insn.getValue(), insn.getTargetType()); reader.cast(insn.getReceiver(), insn.getValue(), insn.getTargetType(), insn.isWeak());
} }
@Override @Override

View File

@ -340,7 +340,7 @@ public class Interpreter {
} }
@Override @Override
public void cast(VariableReader receiver, VariableReader value, ValueType targetType) { public void cast(VariableReader receiver, VariableReader value, ValueType targetType, boolean cast) {
variables[receiver.getIndex()] = asJvmClass(targetType).cast(variables[value.getIndex()]); variables[receiver.getIndex()] = asJvmClass(targetType).cast(variables[value.getIndex()]);
} }

View File

@ -77,7 +77,7 @@ public class AbstractInstructionReader implements InstructionReader {
} }
@Override @Override
public void cast(VariableReader receiver, VariableReader value, ValueType targetType) { public void cast(VariableReader receiver, VariableReader value, ValueType targetType, boolean weak) {
} }
@Override @Override

View File

@ -23,6 +23,7 @@ public class CastInstruction extends Instruction {
private Variable value; private Variable value;
private Variable receiver; private Variable receiver;
private ValueType targetType; private ValueType targetType;
private boolean weak;
public Variable getValue() { public Variable getValue() {
return value; return value;
@ -48,6 +49,14 @@ public class CastInstruction extends Instruction {
this.targetType = targetType; this.targetType = targetType;
} }
public boolean isWeak() {
return weak;
}
public void setWeak(boolean weak) {
this.weak = weak;
}
@Override @Override
public void acceptVisitor(InstructionVisitor visitor) { public void acceptVisitor(InstructionVisitor visitor) {
visitor.visit(this); visitor.visit(this);

View File

@ -44,7 +44,7 @@ public interface InstructionReader {
void assign(VariableReader receiver, VariableReader assignee); void assign(VariableReader receiver, VariableReader assignee);
void cast(VariableReader receiver, VariableReader value, ValueType targetType); void cast(VariableReader receiver, VariableReader value, ValueType targetType, boolean weak);
void cast(VariableReader receiver, VariableReader value, NumericOperandType sourceType, void cast(VariableReader receiver, VariableReader value, NumericOperandType sourceType,
NumericOperandType targetType); NumericOperandType targetType);

View File

@ -43,9 +43,10 @@ public final class ExceptionHandlingUtil {
|| insn instanceof ConstructArrayInstruction || insn instanceof ConstructMultiArrayInstruction || insn instanceof ConstructArrayInstruction || insn instanceof ConstructMultiArrayInstruction
|| insn instanceof CloneArrayInstruction || insn instanceof RaiseInstruction || insn instanceof CloneArrayInstruction || insn instanceof RaiseInstruction
|| insn instanceof MonitorEnterInstruction || insn instanceof MonitorExitInstruction || insn instanceof MonitorEnterInstruction || insn instanceof MonitorExitInstruction
|| insn instanceof NullCheckInstruction || insn instanceof BoundCheckInstruction || insn instanceof NullCheckInstruction || insn instanceof BoundCheckInstruction) {
|| insn instanceof CastInstruction) {
return true; return true;
} else if (insn instanceof CastInstruction) {
return !((CastInstruction) insn).isWeak();
} else if (insn instanceof InvokeInstruction) { } else if (insn instanceof InvokeInstruction) {
return isManagedMethodCall(characteristics, ((InvokeInstruction) insn).getMethod()); return isManagedMethodCall(characteristics, ((InvokeInstruction) insn).getMethod());
} }

View File

@ -93,7 +93,7 @@ public class NativePointerFinder {
} }
@Override @Override
public void cast(VariableReader receiver, VariableReader value, ValueType targetType) { public void cast(VariableReader receiver, VariableReader value, ValueType targetType, boolean weak) {
assignmentGraph.addEdge(value.getIndex(), receiver.getIndex()); assignmentGraph.addEdge(value.getIndex(), receiver.getIndex());
} }

View File

@ -31,7 +31,6 @@ import org.teavm.model.MethodHolder;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
import org.teavm.model.Program; import org.teavm.model.Program;
import org.teavm.model.ValueType; import org.teavm.model.ValueType;
import org.teavm.model.instructions.AssignInstruction;
import org.teavm.model.instructions.CastInstruction; import org.teavm.model.instructions.CastInstruction;
import org.teavm.model.instructions.InvocationType; import org.teavm.model.instructions.InvocationType;
import org.teavm.model.instructions.InvokeInstruction; import org.teavm.model.instructions.InvokeInstruction;
@ -172,11 +171,7 @@ public class Devirtualization {
} }
System.out.println(); System.out.println();
} }
AssignInstruction assign = new AssignInstruction(); cast.setWeak(true);
assign.setAssignee(cast.getValue());
assign.setReceiver(cast.getReceiver());
assign.setLocation(cast.getLocation());
cast.replace(assign);
eliminatedCasts++; eliminatedCasts++;
} }
} }

View File

@ -570,7 +570,8 @@ public class GlobalValueNumbering implements MethodOptimization {
int a = map[insn.getValue().getIndex()]; int a = map[insn.getValue().getIndex()];
int p = replaceMap[insn.getValue().getIndex()]; int p = replaceMap[insn.getValue().getIndex()];
insn.setValue(program.variableAt(p)); insn.setValue(program.variableAt(p));
bind(insn.getReceiver().getIndex(), "@" + a + "::" + insn.getTargetType()); var operator = insn.isWeak() ? ":::" : "::";
bind(insn.getReceiver().getIndex(), "@" + a + operator + insn.getTargetType());
} }
@Override @Override

View File

@ -240,8 +240,12 @@ class InstructionStringifier implements InstructionReader {
} }
@Override @Override
public void cast(VariableReader receiver, VariableReader value, ValueType targetType) { public void cast(VariableReader receiver, VariableReader value, ValueType targetType, boolean weak) {
appendLocalVar(receiver).append(" := cast ").appendLocalVar(value).append(" to ") appendLocalVar(receiver).append(" := ");
if (weak) {
append("weak ");
}
append("cast ").appendLocalVar(value).append(" to ")
.escapeIdentifierIfNeeded(targetType.toString()); .escapeIdentifierIfNeeded(targetType.toString());
} }

View File

@ -208,11 +208,12 @@ public class InstructionCopyReader implements InstructionReader {
} }
@Override @Override
public void cast(VariableReader receiver, VariableReader value, ValueType targetType) { public void cast(VariableReader receiver, VariableReader value, ValueType targetType, boolean weak) {
CastInstruction insnCopy = new CastInstruction(); CastInstruction insnCopy = new CastInstruction();
insnCopy.setValue(copyVar(value)); insnCopy.setValue(copyVar(value));
insnCopy.setReceiver(copyVar(receiver)); insnCopy.setReceiver(copyVar(receiver));
insnCopy.setTargetType(targetType); insnCopy.setTargetType(targetType);
insnCopy.setWeak(weak);
copy = insnCopy; copy = insnCopy;
copy.setLocation(location); copy.setLocation(location);
} }

View File

@ -296,7 +296,7 @@ public class TypeInferer {
} }
@Override @Override
public void cast(VariableReader receiver, VariableReader value, ValueType targetType) { public void cast(VariableReader receiver, VariableReader value, ValueType targetType, boolean weak) {
types[receiver.getIndex()] = convert(targetType); types[receiver.getIndex()] = convert(targetType);
} }

View File

@ -465,6 +465,9 @@ class JSClassProcessor {
} }
private boolean processCast(CastInstruction cast, CallLocation location) { private boolean processCast(CastInstruction cast, CallLocation location) {
if (cast.isWeak()) {
return false;
}
if (!(cast.getTargetType() instanceof ValueType.Object)) { if (!(cast.getTargetType() instanceof ValueType.Object)) {
cast.setTargetType(processType(cast.getTargetType())); cast.setTargetType(processType(cast.getTargetType()));
return false; return false;

View File

@ -607,7 +607,7 @@ public class CompositeMethodGenerator {
} }
@Override @Override
public void cast(VariableReader receiver, VariableReader value, ValueType targetType) { public void cast(VariableReader receiver, VariableReader value, ValueType targetType, boolean weak) {
CastInstruction insn = new CastInstruction(); CastInstruction insn = new CastInstruction();
insn.setTargetType(targetType); insn.setTargetType(targetType);
insn.setValue(var(value)); insn.setValue(var(value));

View File

@ -77,7 +77,7 @@ class ResourceProgramTransformer {
} }
private void removeCastToResource(CastInstruction cast) { private void removeCastToResource(CastInstruction cast) {
if (hierarchy.isSuperType(RESOURCE, cast.getTargetType(), false)) { if (!cast.isWeak() && hierarchy.isSuperType(RESOURCE, cast.getTargetType(), false)) {
AssignInstruction assign = new AssignInstruction(); AssignInstruction assign = new AssignInstruction();
assign.setReceiver(cast.getReceiver()); assign.setReceiver(cast.getReceiver());
assign.setAssignee(cast.getValue()); assign.setAssignee(cast.getValue());