diff --git a/teavm-core/src/main/java/org/teavm/tooling/InstructionLocationReader.java b/teavm-core/src/main/java/org/teavm/tooling/InstructionLocationReader.java new file mode 100644 index 000000000..872200350 --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/tooling/InstructionLocationReader.java @@ -0,0 +1,205 @@ +/* + * Copyright 2015 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.tooling; + +import java.util.List; +import java.util.Set; +import org.teavm.model.BasicBlockReader; +import org.teavm.model.FieldReference; +import org.teavm.model.InstructionLocation; +import org.teavm.model.MethodReference; +import org.teavm.model.ValueType; +import org.teavm.model.VariableReader; +import org.teavm.model.instructions.ArrayElementType; +import org.teavm.model.instructions.BinaryBranchingCondition; +import org.teavm.model.instructions.BinaryOperation; +import org.teavm.model.instructions.BranchingCondition; +import org.teavm.model.instructions.CastIntegerDirection; +import org.teavm.model.instructions.InstructionReader; +import org.teavm.model.instructions.IntegerSubtype; +import org.teavm.model.instructions.InvocationType; +import org.teavm.model.instructions.NumericOperandType; +import org.teavm.model.instructions.SwitchTableEntryReader; + +/** + * + * @author Alexey Andreev + */ +class InstructionLocationReader implements InstructionReader { + private Set resources; + + public InstructionLocationReader(Set resources) { + this.resources = resources; + } + + @Override + public void location(InstructionLocation location) { + if (location != null && location.getFileName() != null) { + resources.add(location.getFileName()); + } + } + + @Override + public void nop() { + } + + @Override + public void classConstant(VariableReader receiver, ValueType cst) { + } + + @Override + public void nullConstant(VariableReader receiver) { + } + + @Override + public void integerConstant(VariableReader receiver, int cst) { + } + + @Override + public void longConstant(VariableReader receiver, long cst) { + } + + @Override + public void floatConstant(VariableReader receiver, float cst) { + } + + @Override + public void doubleConstant(VariableReader receiver, double cst) { + } + + @Override + public void stringConstant(VariableReader receiver, String cst) { + } + + @Override + public void binary(BinaryOperation op, VariableReader receiver, VariableReader first, VariableReader second, + NumericOperandType type) { + } + + @Override + public void negate(VariableReader receiver, VariableReader operand, NumericOperandType type) { + } + + @Override + public void assign(VariableReader receiver, VariableReader assignee) { + } + + @Override + public void cast(VariableReader receiver, VariableReader value, ValueType targetType) { + } + + @Override + public void cast(VariableReader receiver, VariableReader value, NumericOperandType sourceType, + NumericOperandType targetType) { + } + + @Override + public void cast(VariableReader receiver, VariableReader value, IntegerSubtype type, + CastIntegerDirection targetType) { + } + + @Override + public void jumpIf(BranchingCondition cond, VariableReader operand, BasicBlockReader consequent, + BasicBlockReader alternative) { + } + + @Override + public void jumpIf(BinaryBranchingCondition cond, VariableReader first, VariableReader second, + BasicBlockReader consequent, BasicBlockReader alternative) { + } + + @Override + public void jump(BasicBlockReader target) { + } + + @Override + public void choose(VariableReader condition, List table, + BasicBlockReader defaultTarget) { + } + + @Override + public void exit(VariableReader valueToReturn) { + } + + @Override + public void raise(VariableReader exception) { + } + + @Override + public void createArray(VariableReader receiver, ValueType itemType, VariableReader size) { + } + + @Override + public void createArray(VariableReader receiver, ValueType itemType, List dimensions) { + } + + @Override + public void create(VariableReader receiver, String type) { + } + + @Override + public void getField(VariableReader receiver, VariableReader instance, FieldReference field, ValueType fieldType) { + } + + @Override + public void putField(VariableReader instance, FieldReference field, VariableReader value, ValueType fieldType) { + } + + @Override + public void arrayLength(VariableReader receiver, VariableReader array) { + } + + @Override + public void cloneArray(VariableReader receiver, VariableReader array) { + } + + @Override + public void unwrapArray(VariableReader receiver, VariableReader array, ArrayElementType elementType) { + } + + @Override + public void getElement(VariableReader receiver, VariableReader array, VariableReader index) { + } + + @Override + public void putElement(VariableReader array, VariableReader index, VariableReader value) { + } + + @Override + public void invoke(VariableReader receiver, VariableReader instance, MethodReference method, + List arguments, InvocationType type) { + } + + @Override + public void isInstance(VariableReader receiver, VariableReader value, ValueType type) { + } + + @Override + public void initClass(String className) { + } + + @Override + public void nullCheck(VariableReader receiver, VariableReader value) { + } + + @Override + public void monitorEnter(VariableReader objectRef) { + } + + @Override + public void monitorExit(VariableReader objectRef) { + } +} diff --git a/teavm-core/src/main/java/org/teavm/tooling/TeaVMTool.java b/teavm-core/src/main/java/org/teavm/tooling/TeaVMTool.java index 83ffe6def..ff4c0bfbe 100644 --- a/teavm-core/src/main/java/org/teavm/tooling/TeaVMTool.java +++ b/teavm-core/src/main/java/org/teavm/tooling/TeaVMTool.java @@ -213,6 +213,38 @@ public class TeaVMTool { return vm != null ? vm.getClasses() : Collections.emptyList(); } + public Collection getUsedResources() { + if (vm == null) { + return Collections.emptyList(); + } + + Set resources = new HashSet<>(); + ClassReaderSource classSource = vm.getDependencyClassSource(); + InstructionLocationReader reader = new InstructionLocationReader(resources); + for (MethodReference methodRef : vm.getMethods()) { + ClassReader cls = classSource.get(methodRef.getClassName()); + if (cls == null) { + continue; + } + + MethodReader method = cls.getMethod(methodRef.getDescriptor()); + if (method == null) { + continue; + } + + ProgramReader program = method.getProgram(); + if (program == null) { + continue; + } + + for (int i = 0; i < program.basicBlockCount(); ++i) { + program.basicBlockAt(i).readAllInstructions(reader); + } + } + + return resources; + } + public void addSourceFileProvider(SourceFileProvider sourceFileProvider) { sourceFileProviders.add(sourceFileProvider); } diff --git a/teavm-core/src/main/java/org/teavm/vm/TeaVM.java b/teavm-core/src/main/java/org/teavm/vm/TeaVM.java index 086b7e7c7..3a204221e 100644 --- a/teavm-core/src/main/java/org/teavm/vm/TeaVM.java +++ b/teavm-core/src/main/java/org/teavm/vm/TeaVM.java @@ -297,10 +297,23 @@ public class TeaVM implements TeaVMHost, ServiceRepository { return classSource; } + /** + * Gets a {@link ClassReaderSource} which is similar to that of {@link #getClassSource()}, + * except that it also contains classes with applied transformations together with + * classes, generated via {@link DependencyChecker#submitClass(ClassHolder)}. + */ + public ClassReaderSource getDependencyClassSource() { + return dependencyChecker.getClassSource(); + } + public Collection getClasses() { return dependencyChecker.getAchievableClasses(); } + public Collection getMethods() { + return dependencyChecker.getAchievableMethods(); + } + public DependencyInfo getDependencyInfo() { return dependencyChecker; } diff --git a/teavm-eclipse/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/TeaVMProjectBuilder.java b/teavm-eclipse/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/TeaVMProjectBuilder.java index b0f3b8fd3..64b167b03 100644 --- a/teavm-eclipse/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/TeaVMProjectBuilder.java +++ b/teavm-eclipse/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/TeaVMProjectBuilder.java @@ -50,7 +50,7 @@ public class TeaVMProjectBuilder extends IncrementalProjectBuilder { private SourceFileProvider[] sourceProviders; private Set usedProjects = new HashSet<>(); private static Map> profileClasses = new WeakHashMap<>(); - private static Map> profileClassNames = new WeakHashMap<>(); + private static Map> profileDependencies = new WeakHashMap<>(); private static Pattern newLinePattern = Pattern.compile("\\r|\\n|\\r\\n"); @Override @@ -93,8 +93,14 @@ public class TeaVMProjectBuilder extends IncrementalProjectBuilder { private void buildProfile(int kind, IProgressMonitor monitor, TeaVMProfile profile, ClassLoader classLoader) throws CoreException { - if ((kind == AUTO_BUILD || kind == INCREMENTAL_BUILD) && !shouldBuild(profile)) { - return; + if ((kind == AUTO_BUILD || kind == INCREMENTAL_BUILD)) { + if (!shouldBuild(profile)) { + Set dependencies = profileDependencies.get(profile); + if (dependencies != null) { + usedProjects.addAll(dependencies); + } + return; + } } IStringVariableManager varManager = VariablesPlugin.getDefault().getStringVariableManager(); TeaVMTool tool = new TeaVMTool(); @@ -133,9 +139,8 @@ public class TeaVMProjectBuilder extends IncrementalProjectBuilder { removeMarkers(profile); putMarkers(tool.getDependencyInfo().getCallGraph(), tool.getProblemProvider().getProblems(), profile); - Set classNames = new HashSet(tool.getClasses()); - profileClassNames.put(profile, classNames); - setClasses(profile, classesToResources(classNames)); + profileDependencies.put(profile, new HashSet(usedProjects)); + classesToResources(profile, tool); refreshTarget(tool.getTargetDirectory()); } if (!monitor.isCanceled()) { @@ -179,9 +184,9 @@ public class TeaVMProjectBuilder extends IncrementalProjectBuilder { } } - private Set classesToResources(Collection classNames) { + private void classesToResources(TeaVMProfile profile, TeaVMTool tool) { Set resourcePaths = new HashSet<>(); - for (String className : classNames) { + for (String className : tool.getClasses()) { for (IContainer clsContainer : classFileContainers) { IResource res = clsContainer.findMember(className.replace('.', '/') + ".class"); if (res != null) { @@ -190,7 +195,16 @@ public class TeaVMProjectBuilder extends IncrementalProjectBuilder { } } } - return resourcePaths; + for (String resourceName : tool.getUsedResources()) { + for (IContainer clsContainer : classFileContainers) { + IResource res = clsContainer.findMember(resourceName); + if (res != null) { + resourcePaths.add(res.getFullPath().toString()); + usedProjects.add(res.getProject()); + } + } + } + setClasses(profile, resourcePaths); } private boolean shouldBuild(TeaVMProfile profile) throws CoreException { @@ -204,10 +218,6 @@ public class TeaVMProjectBuilder extends IncrementalProjectBuilder { return true; } } - Set classNames = profileClassNames.get(profile); - if (classNames != null) { - classesToResources(classNames); - } return false; }