Add class handling in dependency checker

This commit is contained in:
Alexey Andreev 2016-02-22 19:29:51 +03:00
parent 8db424809a
commit 1826e04951
9 changed files with 205 additions and 149 deletions

View File

@ -20,159 +20,33 @@
<profile default="true" name="Default" enabled="false"> <profile default="true" name="Default" enabled="false">
<processorPath useClasspath="true" /> <processorPath useClasspath="true" />
</profile> </profile>
<profile default="false" name="Annotation profile for teavm-cli" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<processorPath useClasspath="true" />
<module name="teavm-cli" />
</profile>
<profile default="false" name="Annotation profile for teavm-tooling" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<processorPath useClasspath="true" />
<module name="teavm-tooling" />
</profile>
<profile default="false" name="Annotation profile for teavm-platform" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<processorPath useClasspath="true" />
<module name="teavm-platform" />
</profile>
<profile default="false" name="Annotation profile for teavm-html4j" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<processorPath useClasspath="true" />
<module name="teavm-html4j" />
</profile>
<profile default="false" name="Maven default annotation processors profile" enabled="true"> <profile default="false" name="Maven default annotation processors profile" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<processorPath useClasspath="true" />
<module name="teavm-maven-webapp" />
</profile>
<profile default="false" name="Annotation profile for teavm-jso-impl" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<processorPath useClasspath="true" />
<module name="teavm-jso-impl" />
</profile>
<profile default="false" name="Annotation profile for teavm-maven-plugin" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<processorPath useClasspath="true" />
<module name="teavm-maven-plugin" />
</profile>
<profile default="false" name="Annotation profile for teavm-jso-apis" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<processorPath useClasspath="true" />
<module name="teavm-jso-apis" />
</profile>
<profile default="false" name="Annotation profile for teavm-samples-scala" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<processorPath useClasspath="true" />
<module name="teavm-samples-scala" />
</profile>
<profile default="false" name="Annotation profile for teavm-jso" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<processorPath useClasspath="true" />
<module name="teavm-jso" />
</profile>
<profile default="false" name="Annotation profile for teavm-core" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<processorPath useClasspath="true" />
<module name="teavm-core" />
</profile>
<profile default="false" name="Annotation profile for teavm-samples-kotlin" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<processorPath useClasspath="true" />
<module name="teavm-samples-kotlin" />
</profile>
<profile default="false" name="Annotation profile for teavm-classlib" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<processorPath useClasspath="true" />
<module name="teavm-classlib" />
</profile>
<profile default="false" name="Annotation profile for teavm-samples-async" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<processorPath useClasspath="true" />
<module name="teavm-samples-async" />
</profile>
<profile default="false" name="Annotation profile for teavm-samples-video" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<processorPath useClasspath="true" />
<module name="teavm-samples-video" />
</profile>
<profile default="false" name="Annotation profile for teavm-samples-storage" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<processorPath useClasspath="true" />
<module name="teavm-samples-storage" />
</profile>
<profile default="false" name="Annotation profile for teavm-samples-benchmark" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<processorPath useClasspath="true" />
<module name="teavm-samples-benchmark" />
</profile>
<profile default="false" name="Annotation profile for teavm-samples-hello" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<processorPath useClasspath="true" />
<module name="teavm-samples-hello" />
</profile>
<profile default="false" name="Annotation profile for teavm-extras-slf4j" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<processorPath useClasspath="true" />
<module name="teavm-extras-slf4j" />
</profile>
<profile default="false" name="Annotation profile for teavm-chrome-rdp" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" /> <sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" /> <sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" /> <outputRelativeToContentRoot value="true" />
<processorPath useClasspath="true" /> <processorPath useClasspath="true" />
<module name="teavm-chrome-rdp" /> <module name="teavm-chrome-rdp" />
</profile> <module name="teavm-classlib" />
<profile default="false" name="Annotation profile for teavm-tests" enabled="true"> <module name="teavm-cli" />
<sourceOutputDir name="target/generated-sources/annotations" /> <module name="teavm-core" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" /> <module name="teavm-extras-slf4j" />
<outputRelativeToContentRoot value="true" /> <module name="teavm-html4j" />
<processorPath useClasspath="true" /> <module name="teavm-jso" />
<module name="teavm-tests" /> <module name="teavm-jso-apis" />
</profile> <module name="teavm-jso-impl" />
<profile default="false" name="Annotation profile for teavm-metaprogramming-api" enabled="true"> <module name="teavm-maven-plugin" />
<sourceOutputDir name="target/generated-sources/annotations" /> <module name="teavm-maven-webapp" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<processorPath useClasspath="true" />
<module name="teavm-metaprogramming-api" /> <module name="teavm-metaprogramming-api" />
<module name="teavm-platform" />
<module name="teavm-samples-async" />
<module name="teavm-samples-benchmark" />
<module name="teavm-samples-hello" />
<module name="teavm-samples-kotlin" />
<module name="teavm-samples-scala" />
<module name="teavm-samples-storage" />
<module name="teavm-samples-video" />
<module name="teavm-tests" />
<module name="teavm-tooling" />
</profile> </profile>
</annotationProcessing> </annotationProcessing>
<bytecodeTargetLevel> <bytecodeTargetLevel>

View File

@ -388,6 +388,19 @@ class DependencyGraphBuilder {
DependencyNode node = nodes[receiver.getIndex()]; DependencyNode node = nodes[receiver.getIndex()];
if (node != null) { if (node != null) {
node.propagate(dependencyChecker.getType("java.lang.Class")); node.propagate(dependencyChecker.getType("java.lang.Class"));
if (!(cst instanceof ValueType.Primitive)) {
StringBuilder sb = new StringBuilder();
while (cst instanceof ValueType.Array) {
cst = ((ValueType.Array) cst).getItemType();
sb.append('[');
}
if (cst instanceof ValueType.Object) {
sb.append(((ValueType.Object) cst).getClassName());
} else {
sb.append(cst.toString());
}
node.getClassValueNode().propagate(dependencyChecker.getType(sb.toString()));
}
} }
while (cst instanceof ValueType.Array) { while (cst instanceof ValueType.Array) {
cst = ((ValueType.Array) cst).getItemType(); cst = ((ValueType.Array) cst).getItemType();
@ -656,6 +669,10 @@ class DependencyGraphBuilder {
invokeVirtual(receiver, instance, method, arguments); invokeVirtual(receiver, instance, method, arguments);
break; break;
} }
if (method.getName().equals("getClass") && method.parameterCount() == 0
&& method.getReturnType().isObject(Class.class) && receiver != null) {
nodes[instance.getIndex()].connect(nodes[receiver.getIndex()].getClassValueNode());
}
} }
} }

View File

@ -30,6 +30,7 @@ public class DependencyNode implements ValueDependencyInfo {
private List<DependencyNodeToNodeTransition> transitions; private List<DependencyNodeToNodeTransition> transitions;
private volatile String tag; private volatile String tag;
private DependencyNode arrayItemNode; private DependencyNode arrayItemNode;
private DependencyNode classValueNode;
private int degree; private int degree;
int index; int index;
boolean locked; boolean locked;
@ -201,6 +202,18 @@ public class DependencyNode implements ValueDependencyInfo {
return arrayItemNode; return arrayItemNode;
} }
public DependencyNode getClassValueNode() {
if (classValueNode == null) {
classValueNode = new DependencyNode(dependencyChecker, dependencyChecker.nodes.size(), degree);
dependencyChecker.nodes.add(classValueNode);
if (DependencyChecker.shouldLog) {
classValueNode.tag = tag + "@";
}
classValueNode.addConsumer(this::propagate);
}
return classValueNode;
}
@Override @Override
public boolean hasArrayType() { public boolean hasArrayType() {
return arrayItemNode != null && (arrayItemNode.types != null || arrayItemNode.smallTypes != null); return arrayItemNode != null && (arrayItemNode.types != null || arrayItemNode.smallTypes != null);

View File

@ -40,6 +40,9 @@ class DependencyNodeToNodeTransition implements DependencyConsumer {
source.getArrayItem().connect(destination.getArrayItem()); source.getArrayItem().connect(destination.getArrayItem());
destination.getArrayItem().connect(source.getArrayItem()); destination.getArrayItem().connect(source.getArrayItem());
} }
if (type.getName().equals("java.lang.Class")) {
source.getClassValueNode().connect(destination.getClassValueNode());
}
if (!destination.hasType(type)) { if (!destination.hasType(type)) {
destination.propagate(type); destination.propagate(type);
} }

View File

@ -30,9 +30,9 @@ public interface MethodDependencyInfo {
int getParameterCount(); int getParameterCount();
DependencyNode getResult(); ValueDependencyInfo getResult();
DependencyNode getThrown(); ValueDependencyInfo getThrown();
MethodReference getReference(); MethodReference getReference();

View File

@ -26,5 +26,7 @@ public interface ValueDependencyInfo {
boolean hasArrayType(); boolean hasArrayType();
DependencyNode getArrayItem(); ValueDependencyInfo getArrayItem();
ValueDependencyInfo getClassValueNode();
} }

View File

@ -60,6 +60,12 @@
<artifactId>junit</artifactId> <artifactId>junit</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.teavm</groupId>
<artifactId>teavm-tooling</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
</dependencies> </dependencies>
<build> <build>

View File

@ -0,0 +1,140 @@
/*
* Copyright 2016 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.dependency;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import org.junit.Test;
import org.teavm.model.MethodReference;
import org.teavm.model.ValueType;
import org.teavm.tooling.TeaVMProblemRenderer;
import org.teavm.tooling.TeaVMToolLog;
import org.teavm.vm.TeaVM;
import org.teavm.vm.TeaVMBuilder;
public class ClassValueTest {
@Test
public void simple() {
ValueDependencyInfo info = runTestWithConsume("simpleSnippet").getClassValueNode();
assertTrue("Long must be consumed", info.hasType("java.lang.Long"));
assertTrue("String must be consumed", info.hasType("java.lang.String"));
assertTrue("Nothing except Long and String expected", info.getTypes().length == 2);
}
@SuppressWarnings("unused")
public static void simpleSnippet() {
consume(Long.class);
consume(String.class);
}
@Test
public void fromGetClass() {
ValueDependencyInfo info = runTestWithConsume("fromGetClassSnippet").getClassValueNode();
assertTrue("Long must be consumed", info.hasType("java.lang.Long"));
assertTrue("String must be consumed", info.hasType("java.lang.String"));
assertTrue("Nothing except Long and String expected", info.getTypes().length == 2);
}
@SuppressWarnings("unused")
public static void fromGetClassSnippet() {
consumeClass(23L);
consumeClass("foo");
}
private static void consumeClass(Object value) {
consume(value.getClass());
}
protected static void consume(@SuppressWarnings("unused") Object value) {
// do nothing
}
private ValueDependencyInfo runTestWithConsume(String methodName) {
DependencyInfo info = runTest(methodName);
MethodDependencyInfo methodInfo = info.getMethod(new MethodReference(ClassValueTest.class, "consume",
Object.class, void.class));
if (methodInfo == null) {
fail("consume method never reached");
}
return methodInfo.getVariable(1);
}
private DependencyInfo runTest(String methodName) {
TeaVM vm = new TeaVMBuilder().build();
vm.installPlugins();
vm.entryPoint(new MethodReference(getClass().getName(), methodName, ValueType.VOID));
vm.build(new StringBuilder(), null);
if (!vm.getProblemProvider().getSevereProblems().isEmpty()) {
fail("Code compiled with errors:\n" + describeProblems(vm));
}
return vm.getDependencyInfo();
}
private String describeProblems(TeaVM vm) {
Log log = new Log();
TeaVMProblemRenderer.describeProblems(vm, log);
return log.sb.toString();
}
static class Log implements TeaVMToolLog {
StringBuilder sb = new StringBuilder();
@Override
public void info(String text) {
appendLine(text);
}
@Override
public void debug(String text) {
appendLine(text);
}
@Override
public void warning(String text) {
appendLine(text);
}
@Override
public void error(String text) {
appendLine(text);
}
@Override
public void info(String text, Throwable e) {
appendLine(text);
}
@Override
public void debug(String text, Throwable e) {
appendLine(text);
}
@Override
public void warning(String text, Throwable e) {
appendLine(text);
}
@Override
public void error(String text, Throwable e) {
appendLine(text);
}
private void appendLine(String text) {
sb.append(text).append('\n');
}
}
}

View File

@ -26,5 +26,6 @@
<orderEntry type="module" module-name="teavm-jso-apis" production-on-test="" /> <orderEntry type="module" module-name="teavm-jso-apis" production-on-test="" />
<orderEntry type="library" scope="TEST" name="Maven: junit:junit:4.11" level="project" /> <orderEntry type="library" scope="TEST" name="Maven: junit:junit:4.11" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.hamcrest:hamcrest-core:1.3" level="project" /> <orderEntry type="library" scope="TEST" name="Maven: org.hamcrest:hamcrest-core:1.3" level="project" />
<orderEntry type="module" module-name="teavm-tooling" scope="TEST" />
</component> </component>
</module> </module>