diff --git a/classlib/src/main/java/org/teavm/classlib/impl/ReflectionDependencyListener.java b/classlib/src/main/java/org/teavm/classlib/impl/ReflectionDependencyListener.java index 3211576bb..fca9cbf56 100644 --- a/classlib/src/main/java/org/teavm/classlib/impl/ReflectionDependencyListener.java +++ b/classlib/src/main/java/org/teavm/classlib/impl/ReflectionDependencyListener.java @@ -57,6 +57,12 @@ public class ReflectionDependencyListener extends AbstractDependencyListener { private MethodReference forName = new MethodReference(Class.class, "forName", String.class, Boolean.class, ClassLoader.class, Class.class); private MethodReference forNameShort = new MethodReference(Class.class, "forName", String.class, Class.class); + private MethodReference fieldGetType = new MethodReference(Field.class, "getType", Class.class); + private MethodReference methodGetReturnType = new MethodReference(Method.class, "getReturnType", Class.class); + private MethodReference methodGetParameterTypes = new MethodReference(Method.class, "getParameterTypes", + Class[].class); + private MethodReference constructorGetParameterTypes = new MethodReference(Constructor.class, "getParameterTypes", + Class[].class); private boolean fieldGetHandled; private boolean fieldSetHandled; private boolean newInstanceHandled; @@ -66,6 +72,7 @@ public class ReflectionDependencyListener extends AbstractDependencyListener { private Set classesWithReflectableFields = new LinkedHashSet<>(); private Set classesWithReflectableMethods = new LinkedHashSet<>(); private DependencyNode allClasses; + private DependencyNode typesInReflectableSignaturesNode; public ReflectionDependencyListener(List reflectionSuppliers) { this.reflectionSuppliers = reflectionSuppliers; @@ -74,6 +81,7 @@ public class ReflectionDependencyListener extends AbstractDependencyListener { @Override public void started(DependencyAgent agent) { allClasses = agent.createNode(); + typesInReflectableSignaturesNode = agent.createNode(); } public Set getClassesWithReflectableFields() { @@ -138,6 +146,13 @@ public class ReflectionDependencyListener extends AbstractDependencyListener { }); } else if (method.getReference().equals(forName) || method.getReference().equals(forNameShort)) { allClasses.connect(method.getResult().getClassValueNode()); + } else if (method.getReference().equals(fieldGetType) || method.getReference().equals(methodGetReturnType)) { + method.getResult().propagate(agent.getType("java.lang.Class")); + typesInReflectableSignaturesNode.connect(method.getResult().getClassValueNode()); + } else if (method.getReference().equals(methodGetParameterTypes) + || method.getReference().equals(constructorGetParameterTypes)) { + method.getResult().getArrayItem().propagate(agent.getType("java.lang.Class")); + typesInReflectableSignaturesNode.connect(method.getResult().getArrayItem().getClassValueNode()); } } @@ -251,7 +266,9 @@ public class ReflectionDependencyListener extends AbstractDependencyListener { type = ((ValueType.Array) type).getItemType(); } if (type instanceof ValueType.Object) { - agent.linkClass(((ValueType.Object) type).getClassName(), null); + String className = ((ValueType.Object) type).getClassName(); + agent.linkClass(className, null); + typesInReflectableSignaturesNode.propagate(agent.getType(className)); } } diff --git a/classlib/src/main/java/org/teavm/classlib/java/lang/reflect/TConstructor.java b/classlib/src/main/java/org/teavm/classlib/java/lang/reflect/TConstructor.java index 5c3189769..af2f33605 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/lang/reflect/TConstructor.java +++ b/classlib/src/main/java/org/teavm/classlib/java/lang/reflect/TConstructor.java @@ -80,6 +80,7 @@ public class TConstructor extends TAccessibleObject implements TMember { sb.append(' '); } sb.append(declaringClass.getName().toString()).append('('); + TClass[] parameterTypes = getParameterTypes(); for (int i = 0; i < parameterTypes.length; ++i) { if (i > 0) { sb.append(','); diff --git a/classlib/src/main/java/org/teavm/classlib/java/lang/reflect/TField.java b/classlib/src/main/java/org/teavm/classlib/java/lang/reflect/TField.java index c57025bd3..c0ef731e9 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/lang/reflect/TField.java +++ b/classlib/src/main/java/org/teavm/classlib/java/lang/reflect/TField.java @@ -81,7 +81,7 @@ public class TField extends TAccessibleObject implements TMember { if (sb.length() > 0) { sb.append(' '); } - sb.append(type.getName()).append(' ').append(declaringClass.getName()).append(".").append(name); + sb.append(getType().getName()).append(' ').append(declaringClass.getName()).append(".").append(name); return sb.toString(); } diff --git a/classlib/src/main/java/org/teavm/classlib/java/lang/reflect/TMethod.java b/classlib/src/main/java/org/teavm/classlib/java/lang/reflect/TMethod.java index 98ada3477..36dd9e968 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/lang/reflect/TMethod.java +++ b/classlib/src/main/java/org/teavm/classlib/java/lang/reflect/TMethod.java @@ -80,8 +80,9 @@ public class TMethod extends TAccessibleObject implements TMember { if (sb.length() > 0) { sb.append(' '); } - sb.append(returnType.getName()).append(' ').append(declaringClass.getName()).append('.') + sb.append(getReturnType().getName()).append(' ').append(declaringClass.getName()).append('.') .append(name).append('('); + TClass[] parameterTypes = getParameterTypes(); if (parameterTypes.length > 0) { sb.append(parameterTypes[0].getName()); for (int i = 1; i < parameterTypes.length; ++i) { diff --git a/core/src/main/java/org/teavm/backend/javascript/JavaScriptTarget.java b/core/src/main/java/org/teavm/backend/javascript/JavaScriptTarget.java index 172dcc59a..06b002e19 100644 --- a/core/src/main/java/org/teavm/backend/javascript/JavaScriptTarget.java +++ b/core/src/main/java/org/teavm/backend/javascript/JavaScriptTarget.java @@ -266,7 +266,8 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost { } RenderingContext renderingContext = new RenderingContext(debugEmitterToUse, controller.getUnprocessedClassSource(), classes, - controller.getClassLoader(), controller.getServices(), controller.getProperties(), naming); + controller.getClassLoader(), controller.getServices(), controller.getProperties(), naming, + controller.getDependencyInfo()); renderingContext.setMinifying(minifying); Renderer renderer = new Renderer(sourceWriter, asyncMethods, asyncFamilyMethods, controller.getDiagnostics(), renderingContext); diff --git a/core/src/main/java/org/teavm/backend/javascript/rendering/Renderer.java b/core/src/main/java/org/teavm/backend/javascript/rendering/Renderer.java index 96c3998a0..a3d16b629 100644 --- a/core/src/main/java/org/teavm/backend/javascript/rendering/Renderer.java +++ b/core/src/main/java/org/teavm/backend/javascript/rendering/Renderer.java @@ -19,6 +19,7 @@ import com.carrotsearch.hppc.ObjectIntHashMap; import com.carrotsearch.hppc.ObjectIntMap; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Properties; @@ -41,6 +42,7 @@ import org.teavm.backend.javascript.spi.GeneratorContext; import org.teavm.common.ServiceRepository; import org.teavm.debugging.information.DebugInformationEmitter; import org.teavm.debugging.information.DummyDebugInformationEmitter; +import org.teavm.dependency.MethodDependencyInfo; import org.teavm.diagnostics.Diagnostics; import org.teavm.model.ClassReader; import org.teavm.model.ClassReaderSource; @@ -485,6 +487,19 @@ public class Renderer implements RenderingManager { } private void renderClassMetadata(List classes) { + Set classesRequiringName = new HashSet<>(); + MethodDependencyInfo getNameMethod = context.getDependencyInfo().getMethod( + new MethodReference(Class.class, "getName", String.class)); + if (getNameMethod != null) { + classesRequiringName.addAll(Arrays.asList(getNameMethod.getVariable(0).getClassValueNode().getTypes())); + } + MethodDependencyInfo getSimpleNameMethod = context.getDependencyInfo().getMethod( + new MethodReference(Class.class, "getSimpleName", String.class)); + if (getSimpleNameMethod != null) { + classesRequiringName.addAll(Arrays.asList( + getSimpleNameMethod.getVariable(0).getClassValueNode().getTypes())); + } + int start = writer.getOffset(); try { writer.append("$rt_metadata(["); @@ -495,7 +510,14 @@ public class Renderer implements RenderingManager { } first = false; writer.appendClass(cls.getName()).append(",").ws(); - writer.append("\"").append(RenderingUtil.escapeString(cls.getName())).append("\",").ws(); + + if (classesRequiringName.contains(cls.getName())) { + writer.append("\"").append(RenderingUtil.escapeString(cls.getName())).append("\""); + } else { + writer.append("0"); + } + writer.append(",").ws(); + if (cls.getParentName() != null) { writer.appendClass(cls.getParentName()); } else { diff --git a/core/src/main/java/org/teavm/backend/javascript/rendering/RenderingContext.java b/core/src/main/java/org/teavm/backend/javascript/rendering/RenderingContext.java index d883a9774..28badd6bd 100644 --- a/core/src/main/java/org/teavm/backend/javascript/rendering/RenderingContext.java +++ b/core/src/main/java/org/teavm/backend/javascript/rendering/RenderingContext.java @@ -30,6 +30,7 @@ import org.teavm.backend.javascript.spi.InjectedBy; import org.teavm.backend.javascript.spi.Injector; import org.teavm.common.ServiceRepository; import org.teavm.debugging.information.DebugInformationEmitter; +import org.teavm.dependency.DependencyInfo; import org.teavm.interop.PlatformMarker; import org.teavm.model.AnnotationReader; import org.teavm.model.ClassReader; @@ -48,6 +49,7 @@ public class RenderingContext { private ServiceRepository services; private Properties properties; private NamingStrategy naming; + private DependencyInfo dependencyInfo; private final Deque locationStack = new ArrayDeque<>(); private final Map stringPoolMap = new HashMap<>(); private final List stringPool = new ArrayList<>(); @@ -58,7 +60,7 @@ public class RenderingContext { public RenderingContext(DebugInformationEmitter debugEmitter, ClassReaderSource initialClassSource, ListableClassReaderSource classSource, ClassLoader classLoader, ServiceRepository services, Properties properties, - NamingStrategy naming) { + NamingStrategy naming, DependencyInfo dependencyInfo) { this.debugEmitter = debugEmitter; this.initialClassSource = initialClassSource; this.classSource = classSource; @@ -66,6 +68,7 @@ public class RenderingContext { this.services = services; this.properties = properties; this.naming = naming; + this.dependencyInfo = dependencyInfo; } public ClassReaderSource getInitialClassSource() { @@ -92,6 +95,10 @@ public class RenderingContext { return naming; } + public DependencyInfo getDependencyInfo() { + return dependencyInfo; + } + public void setMinifying(boolean minifying) { this.minifying = minifying; } diff --git a/core/src/main/resources/org/teavm/backend/javascript/runtime.js b/core/src/main/resources/org/teavm/backend/javascript/runtime.js index cbb559afc..cb27b8cd5 100644 --- a/core/src/main/resources/org/teavm/backend/javascript/runtime.js +++ b/core/src/main/resources/org/teavm/backend/javascript/runtime.js @@ -433,7 +433,8 @@ function $rt_metadata(data) { var cls = data[i]; cls.$meta = {}; var m = cls.$meta; - m.name = data[i + 1]; + var className = data[i + 1]; + m.name = className !== 0 ? className : null; m.binaryName = "L" + m.name + ";"; var superclass = data[i + 2]; m.superclass = superclass !== 0 ? superclass : null;