mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 00:04:10 -08:00
JS: add support for CCE in strict mode
This commit is contained in:
parent
02e8955abc
commit
4c0c7872a1
|
@ -26,6 +26,7 @@ import org.teavm.ast.AssignmentStatement;
|
|||
import org.teavm.ast.BinaryOperation;
|
||||
import org.teavm.ast.BoundCheckExpr;
|
||||
import org.teavm.ast.BreakStatement;
|
||||
import org.teavm.ast.CastExpr;
|
||||
import org.teavm.ast.ContinueStatement;
|
||||
import org.teavm.ast.Expr;
|
||||
import org.teavm.ast.InitClassStatement;
|
||||
|
@ -208,7 +209,11 @@ class StatementGenerator implements InstructionVisitor {
|
|||
|
||||
@Override
|
||||
public void visit(CastInstruction insn) {
|
||||
assign(Expr.var(insn.getValue().getIndex()), insn.getReceiver());
|
||||
CastExpr expr = new CastExpr();
|
||||
expr.setLocation(insn.getLocation());
|
||||
expr.setValue(Expr.var(insn.getValue().getIndex()));
|
||||
expr.setTarget(insn.getTargetType());
|
||||
assign(expr, insn.getReceiver());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -284,6 +284,11 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
|
|||
NullPointerException.class, "<init>", void.class));
|
||||
exceptionCons.getVariable(0).propagate(dependencyAnalyzer.getType(NullPointerException.class.getName()));
|
||||
exceptionCons.use();
|
||||
|
||||
exceptionCons = dependencyAnalyzer.linkMethod(new MethodReference(
|
||||
ClassCastException.class, "<init>", void.class));
|
||||
exceptionCons.getVariable(0).propagate(dependencyAnalyzer.getType(ClassCastException.class.getName()));
|
||||
exceptionCons.use();
|
||||
}
|
||||
|
||||
if (stackTraceIncluded) {
|
||||
|
@ -370,7 +375,7 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
|
|||
controller.getUnprocessedClassSource(), classes,
|
||||
controller.getClassLoader(), controller.getServices(), controller.getProperties(), naming,
|
||||
controller.getDependencyInfo(), m -> isVirtual(virtualMethodContributorContext, m),
|
||||
controller.getClassInitializerInfo());
|
||||
controller.getClassInitializerInfo(), strict);
|
||||
renderingContext.setMinifying(obfuscated);
|
||||
Renderer renderer = new Renderer(sourceWriter, asyncMethods, asyncFamilyMethods,
|
||||
controller.getDiagnostics(), renderingContext);
|
||||
|
|
|
@ -22,6 +22,7 @@ import org.teavm.ast.AsyncMethodNode;
|
|||
import org.teavm.ast.AsyncMethodPart;
|
||||
import org.teavm.ast.BinaryExpr;
|
||||
import org.teavm.ast.BoundCheckExpr;
|
||||
import org.teavm.ast.CastExpr;
|
||||
import org.teavm.ast.ConstantExpr;
|
||||
import org.teavm.ast.InitClassStatement;
|
||||
import org.teavm.ast.InstanceOfExpr;
|
||||
|
@ -69,13 +70,16 @@ class NameFrequencyEstimator extends RecursiveVisitor implements MethodNodeVisit
|
|||
private boolean async;
|
||||
private final Set<MethodReference> injectedMethods;
|
||||
private final Set<MethodReference> asyncFamilyMethods;
|
||||
private final boolean strict;
|
||||
|
||||
NameFrequencyEstimator(NameFrequencyConsumer consumer, ClassReaderSource classSource,
|
||||
Set<MethodReference> injectedMethods, Set<MethodReference> asyncFamilyMethods) {
|
||||
Set<MethodReference> injectedMethods, Set<MethodReference> asyncFamilyMethods,
|
||||
boolean strict) {
|
||||
this.consumer = consumer;
|
||||
this.classSource = classSource;
|
||||
this.injectedMethods = injectedMethods;
|
||||
this.asyncFamilyMethods = asyncFamilyMethods;
|
||||
this.strict = strict;
|
||||
}
|
||||
|
||||
public void estimate(PreparedClass cls) {
|
||||
|
@ -470,17 +474,33 @@ class NameFrequencyEstimator extends RecursiveVisitor implements MethodNodeVisit
|
|||
public void visit(InstanceOfExpr expr) {
|
||||
super.visit(expr);
|
||||
visitType(expr.getType());
|
||||
if (expr.getType() instanceof ValueType.Object) {
|
||||
String clsName = ((ValueType.Object) expr.getType()).getClassName();
|
||||
ClassReader cls = classSource.get(clsName);
|
||||
if (cls == null || cls.hasModifier(ElementModifier.INTERFACE)) {
|
||||
consumer.consumeFunction("$rt_isInstance");
|
||||
}
|
||||
} else {
|
||||
if (!isClass(expr.getType())) {
|
||||
consumer.consumeFunction("$rt_isInstance");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(CastExpr expr) {
|
||||
super.visit(expr);
|
||||
if (strict) {
|
||||
visitType(expr.getTarget());
|
||||
if (isClass(expr.getTarget())) {
|
||||
consumer.consumeFunction("$rt_castToClass");
|
||||
} else {
|
||||
consumer.consumeFunction("$rt_castToInterface");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isClass(ValueType type) {
|
||||
if (!(type instanceof ValueType.Object)) {
|
||||
return false;
|
||||
}
|
||||
String className = ((ValueType.Object) type).getClassName();
|
||||
ClassReader cls = classSource.get(className);
|
||||
return cls != null && !cls.hasModifier(ElementModifier.INTERFACE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(BoundCheckExpr expr) {
|
||||
super.visit(expr);
|
||||
|
|
|
@ -261,6 +261,7 @@ public class Renderer implements RenderingManager {
|
|||
"$rt_createLongArrayFromData", "$rt_createBooleanArray", "$rt_createByteArray",
|
||||
"$rt_createShortArray", "$rt_createCharArray", "$rt_createIntArray", "$rt_createLongArray",
|
||||
"$rt_createFloatArray", "$rt_createDoubleArray", "$rt_compare",
|
||||
"$rt_castToClass", "$rt_castToInterface",
|
||||
"Long_toNumber", "Long_fromInt", "Long_fromNumber", "Long_create", "Long_ZERO",
|
||||
"Long_hi", "Long_lo");
|
||||
}
|
||||
|
@ -287,7 +288,7 @@ public class Renderer implements RenderingManager {
|
|||
if (minifying) {
|
||||
NamingOrderer orderer = new NamingOrderer();
|
||||
NameFrequencyEstimator estimator = new NameFrequencyEstimator(orderer, classSource, asyncMethods,
|
||||
asyncFamilyMethods);
|
||||
asyncFamilyMethods, context.isStrict());
|
||||
for (PreparedClass cls : classes) {
|
||||
estimator.estimate(cls);
|
||||
}
|
||||
|
|
|
@ -65,12 +65,14 @@ public class RenderingContext {
|
|||
private boolean minifying;
|
||||
private ClassInitializerInfo classInitializerInfo;
|
||||
private TextLocation lastEmittedLocation = TextLocation.EMPTY;
|
||||
private boolean strict;
|
||||
|
||||
public RenderingContext(DebugInformationEmitter debugEmitter,
|
||||
ClassReaderSource initialClassSource, ListableClassReaderSource classSource,
|
||||
ClassLoader classLoader, ServiceRepository services, Properties properties,
|
||||
NamingStrategy naming, DependencyInfo dependencyInfo,
|
||||
Predicate<MethodReference> virtualPredicate, ClassInitializerInfo classInitializerInfo) {
|
||||
Predicate<MethodReference> virtualPredicate, ClassInitializerInfo classInitializerInfo,
|
||||
boolean strict) {
|
||||
this.debugEmitter = debugEmitter;
|
||||
this.initialClassSource = initialClassSource;
|
||||
this.classSource = classSource;
|
||||
|
@ -81,6 +83,7 @@ public class RenderingContext {
|
|||
this.dependencyInfo = dependencyInfo;
|
||||
this.virtualPredicate = virtualPredicate;
|
||||
this.classInitializerInfo = classInitializerInfo;
|
||||
this.strict = strict;
|
||||
}
|
||||
|
||||
public ClassReaderSource getInitialClassSource() {
|
||||
|
@ -399,6 +402,10 @@ public class RenderingContext {
|
|||
return holder.injector;
|
||||
}
|
||||
|
||||
public boolean isStrict() {
|
||||
return strict;
|
||||
}
|
||||
|
||||
@PlatformMarker
|
||||
private static boolean isBootstrap() {
|
||||
return false;
|
||||
|
|
|
@ -49,6 +49,8 @@ public class RuntimeRenderer {
|
|||
"setStackTrace", StackTraceElement[].class, void.class);
|
||||
private static final MethodReference AIOOBE_INIT_METHOD = new MethodReference(ArrayIndexOutOfBoundsException.class,
|
||||
"<init>", void.class);
|
||||
private static final MethodReference CCE_INIT_METHOD = new MethodReference(ClassCastException.class,
|
||||
"<init>", void.class);
|
||||
|
||||
private final ClassReaderSource classSource;
|
||||
private final SourceWriter writer;
|
||||
|
@ -73,6 +75,7 @@ public class RuntimeRenderer {
|
|||
renderCreateStackTraceElement();
|
||||
renderSetStackTrace();
|
||||
renderThrowAIOOBE();
|
||||
renderThrowCCE();
|
||||
} catch (IOException e) {
|
||||
throw new RenderingException("IO error", e);
|
||||
}
|
||||
|
@ -267,4 +270,18 @@ public class RuntimeRenderer {
|
|||
|
||||
writer.outdent().append("}").newLine();
|
||||
}
|
||||
|
||||
private void renderThrowCCE() throws IOException {
|
||||
writer.append("function $rt_throwCCE()").ws().append("{").indent().softNewLine();
|
||||
|
||||
ClassReader cls = classSource.get(CCE_INIT_METHOD.getClassName());
|
||||
if (cls != null) {
|
||||
MethodReader method = cls.getMethod(CCE_INIT_METHOD.getDescriptor());
|
||||
if (method != null && !method.hasModifier(ElementModifier.ABSTRACT)) {
|
||||
writer.append("$rt_throw(").appendInit(CCE_INIT_METHOD).append("());").softNewLine();
|
||||
}
|
||||
}
|
||||
|
||||
writer.outdent().append("}").newLine();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -915,7 +915,41 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
|
|||
|
||||
@Override
|
||||
public void visit(CastExpr expr) {
|
||||
expr.getValue().acceptVisitor(this);
|
||||
if (context.isStrict()) {
|
||||
try {
|
||||
if (expr.getLocation() != null) {
|
||||
pushLocation(expr.getLocation());
|
||||
}
|
||||
|
||||
if (isClass(expr.getTarget(), context.getClassSource())) {
|
||||
writer.appendFunction("$rt_castToClass");
|
||||
} else {
|
||||
writer.appendFunction("$rt_castToInterface");
|
||||
}
|
||||
writer.append("(");
|
||||
precedence = Precedence.min();
|
||||
expr.getValue().acceptVisitor(this);
|
||||
writer.append(",").ws();
|
||||
context.typeToClsString(writer, expr.getTarget());
|
||||
writer.append(")");
|
||||
if (expr.getLocation() != null) {
|
||||
popLocation();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RenderingException("IO error occurred", e);
|
||||
}
|
||||
} else {
|
||||
expr.getValue().acceptVisitor(this);
|
||||
}
|
||||
}
|
||||
|
||||
static boolean isClass(ValueType type, ClassReaderSource classSource) {
|
||||
if (!(type instanceof ValueType.Object)) {
|
||||
return false;
|
||||
}
|
||||
String className = ((ValueType.Object) type).getClassName();
|
||||
ClassReader cls = classSource.get(className);
|
||||
return cls != null && !cls.hasModifier(ElementModifier.INTERFACE);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1475,32 +1509,26 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
|
|||
if (expr.getLocation() != null) {
|
||||
pushLocation(expr.getLocation());
|
||||
}
|
||||
if (expr.getType() instanceof ValueType.Object) {
|
||||
String clsName = ((ValueType.Object) expr.getType()).getClassName();
|
||||
ClassReader cls = classSource.get(clsName);
|
||||
if (cls != null && !cls.hasModifier(ElementModifier.INTERFACE)) {
|
||||
boolean needsParentheses = Precedence.COMPARISON.ordinal() < precedence.ordinal();
|
||||
if (needsParentheses) {
|
||||
writer.append('(');
|
||||
}
|
||||
precedence = Precedence.CONDITIONAL.next();
|
||||
expr.getExpr().acceptVisitor(this);
|
||||
writer.append(" instanceof ").appendClass(clsName);
|
||||
if (needsParentheses) {
|
||||
writer.append(')');
|
||||
}
|
||||
if (expr.getLocation() != null) {
|
||||
popLocation();
|
||||
}
|
||||
return;
|
||||
if (isClass(expr.getType(), context.getClassSource())) {
|
||||
boolean needsParentheses = Precedence.COMPARISON.ordinal() < precedence.ordinal();
|
||||
if (needsParentheses) {
|
||||
writer.append('(');
|
||||
}
|
||||
precedence = Precedence.CONDITIONAL.next();
|
||||
expr.getExpr().acceptVisitor(this);
|
||||
writer.append(" instanceof ");
|
||||
context.typeToClsString(writer, expr.getType());
|
||||
if (needsParentheses) {
|
||||
writer.append(')');
|
||||
}
|
||||
} else {
|
||||
writer.appendFunction("$rt_isInstance").append("(");
|
||||
precedence = Precedence.min();
|
||||
expr.getExpr().acceptVisitor(this);
|
||||
writer.append(",").ws();
|
||||
context.typeToClsString(writer, expr.getType());
|
||||
writer.append(")");
|
||||
}
|
||||
writer.appendFunction("$rt_isInstance").append("(");
|
||||
precedence = Precedence.min();
|
||||
expr.getExpr().acceptVisitor(this);
|
||||
writer.append(",").ws();
|
||||
context.typeToClsString(writer, expr.getType());
|
||||
writer.append(")");
|
||||
if (expr.getLocation() != null) {
|
||||
popLocation();
|
||||
}
|
||||
|
|
|
@ -227,6 +227,14 @@ abstract class AbstractInstructionAnalyzer extends AbstractInstructionReader {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cast(VariableReader receiver, VariableReader value, ValueType targetType) {
|
||||
String className = extractClassName(targetType);
|
||||
if (className != null) {
|
||||
getAnalyzer().linkClass(className);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initClass(String className) {
|
||||
getAnalyzer().linkClass(className).initClass(getCallLocation());
|
||||
|
|
|
@ -220,6 +220,7 @@ class DependencyGraphBuilder {
|
|||
|
||||
@Override
|
||||
public void cast(VariableReader receiver, VariableReader value, ValueType targetType) {
|
||||
super.cast(receiver, value, targetType);
|
||||
DependencyNode valueNode = nodes[value.getIndex()];
|
||||
DependencyNode receiverNode = nodes[receiver.getIndex()];
|
||||
ClassReaderSource classSource = dependencyAnalyzer.getClassSource();
|
||||
|
@ -253,6 +254,7 @@ class DependencyGraphBuilder {
|
|||
valueNode.connect(receiverNode);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exit(VariableReader valueToReturn) {
|
||||
if (valueToReturn != null) {
|
||||
|
|
|
@ -30,6 +30,9 @@ import org.teavm.model.Instruction;
|
|||
import org.teavm.model.MethodHolder;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.Program;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.model.instructions.AssignInstruction;
|
||||
import org.teavm.model.instructions.CastInstruction;
|
||||
import org.teavm.model.instructions.InvocationType;
|
||||
import org.teavm.model.instructions.InvokeInstruction;
|
||||
|
||||
|
@ -41,6 +44,8 @@ public class Devirtualization {
|
|||
private Set<? extends MethodReference> readonlyVirtualMethods = Collections.unmodifiableSet(virtualMethods);
|
||||
private int virtualCallSites;
|
||||
private int directCallSites;
|
||||
private int remainingCasts;
|
||||
private int eliminatedCasts;
|
||||
|
||||
public Devirtualization(DependencyInfo dependency, ClassHierarchy hierarchy) {
|
||||
this.dependency = dependency;
|
||||
|
@ -55,6 +60,14 @@ public class Devirtualization {
|
|||
return directCallSites;
|
||||
}
|
||||
|
||||
public int getRemainingCasts() {
|
||||
return remainingCasts;
|
||||
}
|
||||
|
||||
public int getEliminatedCasts() {
|
||||
return eliminatedCasts;
|
||||
}
|
||||
|
||||
public void apply(MethodHolder method) {
|
||||
MethodDependencyInfo methodDep = dependency.getMethod(method.getReference());
|
||||
if (methodDep == null) {
|
||||
|
@ -69,50 +82,10 @@ public class Devirtualization {
|
|||
for (int i = 0; i < program.basicBlockCount(); ++i) {
|
||||
BasicBlock block = program.basicBlockAt(i);
|
||||
for (Instruction insn : block) {
|
||||
if (!(insn instanceof InvokeInstruction)) {
|
||||
continue;
|
||||
}
|
||||
InvokeInstruction invoke = (InvokeInstruction) insn;
|
||||
if (invoke.getType() != InvocationType.VIRTUAL) {
|
||||
continue;
|
||||
}
|
||||
ValueDependencyInfo var = methodDep.getVariable(invoke.getInstance().getIndex());
|
||||
Set<MethodReference> implementations = getImplementations(var.getTypes(),
|
||||
invoke.getMethod());
|
||||
if (implementations.size() == 1) {
|
||||
MethodReference resolvedImplementaiton = implementations.iterator().next();
|
||||
if (shouldLog) {
|
||||
System.out.print("DIRECT CALL " + invoke.getMethod() + " resolved to "
|
||||
+ resolvedImplementaiton.getClassName());
|
||||
if (insn.getLocation() != null) {
|
||||
System.out.print(" at " + insn.getLocation().getFileName() + ":"
|
||||
+ insn.getLocation().getLine());
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
invoke.setType(InvocationType.SPECIAL);
|
||||
invoke.setMethod(resolvedImplementaiton);
|
||||
directCallSites++;
|
||||
} else {
|
||||
virtualMethods.addAll(implementations);
|
||||
if (shouldLog) {
|
||||
System.out.print("VIRTUAL CALL " + invoke.getMethod() + " resolved to [");
|
||||
boolean first = true;
|
||||
for (MethodReference impl : implementations) {
|
||||
if (!first) {
|
||||
System.out.print(", ");
|
||||
}
|
||||
first = false;
|
||||
System.out.print(impl.getClassName());
|
||||
}
|
||||
System.out.print("]");
|
||||
if (insn.getLocation() != null) {
|
||||
System.out.print(" at " + insn.getLocation().getFileName() + ":"
|
||||
+ insn.getLocation().getLine());
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
virtualCallSites++;
|
||||
if (insn instanceof InvokeInstruction) {
|
||||
applyToInvoke(methodDep, (InvokeInstruction) insn);
|
||||
} else if (insn instanceof CastInstruction) {
|
||||
applyToCast(methodDep, (CastInstruction) insn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -122,6 +95,104 @@ public class Devirtualization {
|
|||
}
|
||||
}
|
||||
|
||||
private void applyToInvoke(MethodDependencyInfo methodDep, InvokeInstruction invoke) {
|
||||
if (invoke.getType() != InvocationType.VIRTUAL) {
|
||||
return;
|
||||
}
|
||||
ValueDependencyInfo var = methodDep.getVariable(invoke.getInstance().getIndex());
|
||||
Set<MethodReference> implementations = getImplementations(var.getTypes(),
|
||||
invoke.getMethod());
|
||||
if (implementations.size() == 1) {
|
||||
MethodReference resolvedImplementaiton = implementations.iterator().next();
|
||||
if (shouldLog) {
|
||||
System.out.print("DIRECT CALL " + invoke.getMethod() + " resolved to "
|
||||
+ resolvedImplementaiton.getClassName());
|
||||
if (invoke.getLocation() != null) {
|
||||
System.out.print(" at " + invoke.getLocation().getFileName() + ":"
|
||||
+ invoke.getLocation().getLine());
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
invoke.setType(InvocationType.SPECIAL);
|
||||
invoke.setMethod(resolvedImplementaiton);
|
||||
directCallSites++;
|
||||
} else {
|
||||
virtualMethods.addAll(implementations);
|
||||
if (shouldLog) {
|
||||
System.out.print("VIRTUAL CALL " + invoke.getMethod() + " resolved to [");
|
||||
boolean first = true;
|
||||
for (MethodReference impl : implementations) {
|
||||
if (!first) {
|
||||
System.out.print(", ");
|
||||
}
|
||||
first = false;
|
||||
System.out.print(impl.getClassName());
|
||||
}
|
||||
System.out.print("]");
|
||||
if (invoke.getLocation() != null) {
|
||||
System.out.print(" at " + invoke.getLocation().getFileName() + ":"
|
||||
+ invoke.getLocation().getLine());
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
virtualCallSites++;
|
||||
}
|
||||
}
|
||||
|
||||
private void applyToCast(MethodDependencyInfo methodDep, CastInstruction cast) {
|
||||
ValueDependencyInfo var = methodDep.getVariable(cast.getValue().getIndex());
|
||||
boolean canFail = false;
|
||||
String failType = null;
|
||||
for (String type : var.getTypes()) {
|
||||
if (castCanFail(type, cast.getTargetType())) {
|
||||
failType = type;
|
||||
canFail = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (canFail) {
|
||||
if (shouldLog) {
|
||||
System.out.print("REMAINING CAST to " + cast.getTargetType() + " (example is " + failType + ")");
|
||||
if (cast.getLocation() != null) {
|
||||
System.out.print(" at " + cast.getLocation().getFileName() + ":"
|
||||
+ cast.getLocation().getLine());
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
remainingCasts++;
|
||||
} else {
|
||||
if (shouldLog) {
|
||||
System.out.print("ELIMINATED CAST to " + cast.getTargetType());
|
||||
if (cast.getLocation() != null) {
|
||||
System.out.print(" at " + cast.getLocation().getFileName() + ":"
|
||||
+ cast.getLocation().getLine());
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
AssignInstruction assign = new AssignInstruction();
|
||||
assign.setAssignee(cast.getValue());
|
||||
assign.setReceiver(cast.getReceiver());
|
||||
assign.setLocation(cast.getLocation());
|
||||
cast.replace(assign);
|
||||
eliminatedCasts++;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean castCanFail(String type, ValueType target) {
|
||||
if (type.startsWith("[")) {
|
||||
ValueType valueType = ValueType.parse(type);
|
||||
if (hierarchy.isSuperType(target, valueType, false)) {
|
||||
return false;
|
||||
}
|
||||
} else if (target instanceof ValueType.Object) {
|
||||
String targetClassName = ((ValueType.Object) target).getClassName();
|
||||
if (hierarchy.isSuperType(targetClassName, type, false)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private Set<MethodReference> getImplementations(String[] classNames, MethodReference ref) {
|
||||
return implementations(hierarchy, dependency, classNames, ref);
|
||||
}
|
||||
|
|
|
@ -44,6 +44,18 @@ function $rt_isAssignable(from, to) {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
function $rt_castToInterface(obj, cls) {
|
||||
if (obj !== null && !$rt_isInstance(obj, cls)) {
|
||||
$rt_throwCCE();
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
function $rt_castToClass(obj, cls) {
|
||||
if (obj !== null && !(obj instanceof cls)) {
|
||||
$rt_throwCCE();
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
Array.prototype.fill = Array.prototype.fill || function(value,start,end) {
|
||||
var len = this.length;
|
||||
if (!len) return this;
|
||||
|
|
|
@ -247,7 +247,12 @@ class JSClassProcessor {
|
|||
}
|
||||
ClassReader targetClass = classSource.get(targetClassName);
|
||||
if (targetClass.getAnnotations().get(JSFunctor.class.getName()) == null) {
|
||||
return false;
|
||||
AssignInstruction assign = new AssignInstruction();
|
||||
assign.setLocation(location.getSourceLocation());
|
||||
assign.setAssignee(cast.getValue());
|
||||
assign.setReceiver(cast.getReceiver());
|
||||
replacement.add(assign);
|
||||
return true;
|
||||
}
|
||||
|
||||
Variable result = marshaller.unwrapFunctor(location, cast.getValue(), targetClass);
|
||||
|
|
|
@ -33,7 +33,6 @@ import org.teavm.model.ReferenceCache;
|
|||
import org.teavm.model.TextLocation;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.model.Variable;
|
||||
import org.teavm.model.instructions.CastInstruction;
|
||||
import org.teavm.model.instructions.ClassConstantInstruction;
|
||||
import org.teavm.model.instructions.InvocationType;
|
||||
import org.teavm.model.instructions.InvokeInstruction;
|
||||
|
@ -290,14 +289,7 @@ class JSValueMarshaller {
|
|||
} else if (className.equals("java.lang.String")) {
|
||||
return unwrap(var, "unwrapString", JSMethods.JS_OBJECT, stringType, location.getSourceLocation());
|
||||
} else if (typeHelper.isJavaScriptClass(className)) {
|
||||
Variable result = program.createVariable();
|
||||
CastInstruction castInsn = new CastInstruction();
|
||||
castInsn.setReceiver(result);
|
||||
castInsn.setValue(var);
|
||||
castInsn.setTargetType(type);
|
||||
castInsn.setLocation(location.getSourceLocation());
|
||||
replacement.add(castInsn);
|
||||
return result;
|
||||
return var;
|
||||
}
|
||||
} else if (type instanceof ValueType.Array) {
|
||||
return unwrapArray(location, var, (ValueType.Array) type);
|
||||
|
@ -314,14 +306,6 @@ class JSValueMarshaller {
|
|||
itemType = ((ValueType.Array) itemType).getItemType();
|
||||
}
|
||||
|
||||
CastInstruction castInsn = new CastInstruction();
|
||||
castInsn.setValue(var);
|
||||
castInsn.setTargetType(ValueType.parse(JSArrayReader.class));
|
||||
var = program.createVariable();
|
||||
castInsn.setReceiver(var);
|
||||
castInsn.setLocation(location.getSourceLocation());
|
||||
replacement.add(castInsn);
|
||||
|
||||
var = degree == 1
|
||||
? unwrapSingleDimensionArray(location, var, itemType)
|
||||
: unwrapMultiDimensionArray(location, var, itemType, degree);
|
||||
|
@ -477,16 +461,6 @@ class JSValueMarshaller {
|
|||
|
||||
private Variable unwrap(Variable var, String methodName, ValueType argType, ValueType resultType,
|
||||
TextLocation location) {
|
||||
if (!argType.isObject(JSObject.class.getName())) {
|
||||
Variable castValue = program.createVariable();
|
||||
CastInstruction castInsn = new CastInstruction();
|
||||
castInsn.setValue(var);
|
||||
castInsn.setReceiver(castValue);
|
||||
castInsn.setLocation(location);
|
||||
castInsn.setTargetType(argType);
|
||||
replacement.add(castInsn);
|
||||
var = castValue;
|
||||
}
|
||||
Variable result = program.createVariable();
|
||||
InvokeInstruction insn = new InvokeInstruction();
|
||||
insn.setMethod(referenceCache.getCached(referenceCache.getCached(new MethodReference(
|
||||
|
|
|
@ -1084,7 +1084,7 @@ public class CompositeMethodGenerator {
|
|||
|
||||
private Variable unwrapArray(ValueType type, Variable array) {
|
||||
CastInstruction cast = new CastInstruction();
|
||||
cast.setTargetType(ValueType.arrayOf(type));
|
||||
cast.setTargetType(type);
|
||||
cast.setValue(array);
|
||||
cast.setReceiver(program.createVariable());
|
||||
add(cast);
|
||||
|
|
|
@ -35,6 +35,7 @@ class ResourceProgramTransformer {
|
|||
Object.class, String[].class);
|
||||
private static final MethodReference GET_PROPERTY = new MethodReference(ResourceAccessor.class, "getProperty",
|
||||
Object.class, String.class, Object.class);
|
||||
private static final ValueType RESOURCE = ValueType.parse(Resource.class);
|
||||
|
||||
private ClassHierarchy hierarchy;
|
||||
private Program program;
|
||||
|
@ -59,6 +60,15 @@ class ResourceProgramTransformer {
|
|||
insn.insertNextAll(replacement);
|
||||
insn.delete();
|
||||
}
|
||||
} else if (insn instanceof CastInstruction) {
|
||||
CastInstruction cast = (CastInstruction) insn;
|
||||
if (hierarchy.isSuperType(RESOURCE, cast.getTargetType(), false)) {
|
||||
AssignInstruction assign = new AssignInstruction();
|
||||
assign.setReceiver(cast.getReceiver());
|
||||
assign.setAssignee(cast.getValue());
|
||||
assign.setLocation(cast.getLocation());
|
||||
insn.replace(assign);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -171,13 +181,7 @@ class ResourceProgramTransformer {
|
|||
return instructions;
|
||||
}
|
||||
default: {
|
||||
Variable resultVar = insn.getProgram().createVariable();
|
||||
getProperty(insn, property, instructions, resultVar);
|
||||
CastInstruction castInsn = new CastInstruction();
|
||||
castInsn.setReceiver(insn.getReceiver());
|
||||
castInsn.setTargetType(type);
|
||||
castInsn.setValue(resultVar);
|
||||
instructions.add(castInsn);
|
||||
getProperty(insn, property, instructions, insn.getReceiver());
|
||||
return instructions;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user