Further work on decreasing generated code size

This commit is contained in:
Alexey Andreev 2020-03-03 12:17:39 +03:00
parent b71a2b6c65
commit c1891a1908
5 changed files with 100 additions and 11 deletions

View File

@ -25,7 +25,7 @@ import org.teavm.model.util.ProgramUtils;
public class ObfuscationHacks implements ClassHolderTransformer { public class ObfuscationHacks implements ClassHolderTransformer {
@Override @Override
public void transformClass(ClassHolder cls, ClassHolderTransformerContext context) { public void transformClass(ClassHolder cls, ClassHolderTransformerContext context) {
if (cls.getName().equals("java.lang.Object")) { if (cls.getName().equals("java.lang.Object") || cls.getName().equals("java.lang.Class")) {
if (context.isObfuscated() && !context.isStrict()) { if (context.isObfuscated() && !context.isStrict()) {
processObjectClass(cls); processObjectClass(cls);
} }

View File

@ -82,8 +82,11 @@ public class TClass<T> extends TObject implements TAnnotatedElement, TType {
@Override @Override
public String toString() { public String toString() {
return (isInterface() ? "interface " : (isPrimitive() ? "" : "class ")) return (isInterface() ? "interface " : (isPrimitive() ? "" : "class ")) + getName();
+ getName(); }
private String obfuscatedToString() {
return "javaClass@" + identity();
} }
public PlatformClass getPlatformClass() { public PlatformClass getPlatformClass() {

View File

@ -65,7 +65,7 @@ public abstract class TEnum<E extends TEnum<E>> extends TObject implements TComp
public final int compareTo(E o) { public final int compareTo(E o) {
if (o.getDeclaringClass() != getDeclaringClass()) { if (o.getDeclaringClass() != getDeclaringClass()) {
throw new TIllegalArgumentException("Can't compare " throw new TIllegalArgumentException("Can't compare "
+ getDeclaringClass().getName() + " to " + o.getDeclaringClass().getName()); + getDeclaringClass() + " to " + o.getDeclaringClass());
} }
return TInteger.compare(ordinal, o.ordinal()); return TInteger.compare(ordinal, o.ordinal());
} }
@ -81,6 +81,6 @@ public abstract class TEnum<E extends TEnum<E>> extends TObject implements TComp
return constant; return constant;
} }
} }
throw new TIllegalArgumentException("Enum does not have the " + name + "constant"); throw new TIllegalArgumentException("Enum " + enumType + " does not have the " + name + "constant");
} }
} }

View File

@ -326,10 +326,10 @@ class DependencyGraphBuilder {
@Override @Override
protected void invokeSpecial(VariableReader receiver, VariableReader instance, MethodReference method, protected void invokeSpecial(VariableReader receiver, VariableReader instance, MethodReference method,
List<? extends VariableReader> arguments) { List<? extends VariableReader> arguments) {
if (method.getDescriptor().equals(GET_CLASS)) { if (handleSpecialMethod(receiver, instance, method)) {
invokeGetClass(receiver, instance);
return; return;
} }
CallLocation callLocation = getCallLocation(); CallLocation callLocation = getCallLocation();
if (instance == null) { if (instance == null) {
dependencyAnalyzer.linkClass(method.getClassName()).initClass(callLocation); dependencyAnalyzer.linkClass(method.getClassName()).initClass(callLocation);
@ -366,8 +366,7 @@ class DependencyGraphBuilder {
@Override @Override
protected void invokeVirtual(VariableReader receiver, VariableReader instance, MethodReference method, protected void invokeVirtual(VariableReader receiver, VariableReader instance, MethodReference method,
List<? extends VariableReader> arguments) { List<? extends VariableReader> arguments) {
if (method.getDescriptor().equals(GET_CLASS)) { if (handleSpecialMethod(receiver, instance, method)) {
invokeGetClass(receiver, instance);
return; return;
} }
@ -387,6 +386,26 @@ class DependencyGraphBuilder {
}); });
} }
private boolean handleSpecialMethod(VariableReader receiver, VariableReader instance, MethodReference method) {
if (method.getDescriptor().equals(GET_CLASS)) {
invokeGetClass(receiver, instance);
return true;
} else if (method.getClassName().equals("java.lang.Class")) {
switch (method.getName()) {
case "getComponentType":
invokeGetComponentType(receiver, instance, method);
return true;
case "getSuperclass":
invokeGetSuperclass(receiver, instance, method);
return true;
case "getInterfaces":
invokeGetInterfaces(receiver, instance, method);
return true;
}
}
return false;
}
private void invokeGetClass(VariableReader receiver, VariableReader instance) { private void invokeGetClass(VariableReader receiver, VariableReader instance) {
MethodDependency getClassDep = dependencyAnalyzer.linkMethod("java.lang.Object", GET_CLASS); MethodDependency getClassDep = dependencyAnalyzer.linkMethod("java.lang.Object", GET_CLASS);
getClassDep.addLocation(getCallLocation()); getClassDep.addLocation(getCallLocation());
@ -402,6 +421,75 @@ class DependencyGraphBuilder {
getClassDep.use(); getClassDep.use();
} }
private void invokeGetComponentType(VariableReader receiver, VariableReader instance,
MethodReference methodReference) {
MethodDependency methodDep = dependencyAnalyzer.linkMethod(methodReference);
methodDep.use();
DependencyNode instanceNode = getNode(instance);
DependencyNode receiverNode = getNode(receiver);
receiverNode.propagate(dependencyAnalyzer.classType);
instanceNode.getClassValueNode().addConsumer(t -> {
if (!t.getName().startsWith("[")) {
return;
}
String typeName = t.getName().substring(1);
if (typeName.charAt(0) == 'L') {
typeName = ((ValueType.Object) ValueType.parse(typeName)).getClassName();
}
receiverNode.getClassValueNode().propagate(dependencyAnalyzer.getType(typeName));
methodDep.getVariable(0).propagate(t);
});
}
private void invokeGetSuperclass(VariableReader receiver, VariableReader instance,
MethodReference methodReference) {
MethodDependency methodDep = dependencyAnalyzer.linkMethod(methodReference);
methodDep.use();
DependencyNode instanceNode = getNode(instance);
DependencyNode receiverNode = getNode(receiver);
receiverNode.propagate(dependencyAnalyzer.classType);
instanceNode.getClassValueNode().addConsumer(type -> {
String className = type.getName();
if (className.startsWith("[")) {
return;
}
ClassReader cls = dependencyAnalyzer.getClassSource().get(className);
if (cls != null && cls.getParent() != null) {
receiverNode.getClassValueNode().propagate(dependencyAnalyzer.getType(cls.getParent()));
}
methodDep.getVariable(0).propagate(type);
});
}
private void invokeGetInterfaces(VariableReader receiver, VariableReader instance,
MethodReference methodReference) {
MethodDependency methodDep = dependencyAnalyzer.linkMethod(methodReference);
methodDep.use();
DependencyNode instanceNode = getNode(instance);
DependencyNode receiverNode = getNode(receiver);
receiverNode.propagate(dependencyAnalyzer.classType);
instanceNode.getClassValueNode().addConsumer(type -> {
String className = type.getName();
if (className.startsWith("[")) {
return;
}
ClassReader cls = dependencyAnalyzer.getClassSource().get(className);
if (cls != null) {
for (String iface : cls.getInterfaces()) {
receiverNode.getClassValueNode().propagate(dependencyAnalyzer.getType(iface));
}
}
methodDep.getVariable(0).propagate(type);
});
}
@Override @Override
public void nullCheck(VariableReader receiver, VariableReader value) { public void nullCheck(VariableReader receiver, VariableReader value) {
super.nullCheck(receiver, value); super.nullCheck(receiver, value);

View File

@ -21,7 +21,6 @@ import net.java.html.json.tests.KnockoutTest;
import net.java.html.json.tests.MinesTest; import net.java.html.json.tests.MinesTest;
import net.java.html.json.tests.OperationsTest; import net.java.html.json.tests.OperationsTest;
import net.java.html.json.tests.WebSocketTest; import net.java.html.json.tests.WebSocketTest;
import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.teavm.junit.SkipJVM; import org.teavm.junit.SkipJVM;
@ -323,7 +322,6 @@ public class KnockoutTCKTest {
} }
@Test @Test
@Ignore
public void deserializeWrongEnum() throws Exception { public void deserializeWrongEnum() throws Exception {
jsonTest.deserializeWrongEnum(); jsonTest.deserializeWrongEnum();
} }