First attempt to refactor dependency checker

This commit is contained in:
Alexey Andreev 2014-03-24 13:26:32 +04:00
parent 8286ad9289
commit 00d160e92b
19 changed files with 475 additions and 312 deletions

View File

@ -26,29 +26,29 @@ public class ClassLookupDependencySupport implements DependencyListener {
private DependencyNode allClasses; private DependencyNode allClasses;
@Override @Override
public void started(DependencyChecker dependencyChecker) { public void started(DependencyAgent agent) {
allClasses = dependencyChecker.createNode(); allClasses = agent.createNode();
} }
@Override @Override
public void classAchieved(DependencyChecker dependencyChecker, String className) { public void classAchieved(DependencyAgent agent, String className) {
allClasses.propagate(className); allClasses.propagate(className);
} }
@Override @Override
public void methodAchieved(final DependencyChecker dependencyChecker, MethodDependency method) { public void methodAchieved(final DependencyAgent agent, MethodDependency method) {
MethodReference ref = method.getReference(); MethodReference ref = method.getReference();
if (ref.getClassName().equals("java.lang.Class") && ref.getName().equals("forNameImpl")) { if (ref.getClassName().equals("java.lang.Class") && ref.getName().equals("forNameImpl")) {
final DependencyStack stack = method.getStack(); final DependencyStack stack = method.getStack();
allClasses.addConsumer(new DependencyConsumer() { allClasses.addConsumer(new DependencyConsumer() {
@Override public void consume(String type) { @Override public void consume(String type) {
ClassReader cls = dependencyChecker.getClassSource().get(type); ClassReader cls = agent.getClassSource().get(type);
if (cls == null) { if (cls == null) {
return; return;
} }
MethodReader initMethod = cls.getMethod(new MethodDescriptor("<clinit>", ValueType.VOID)); MethodReader initMethod = cls.getMethod(new MethodDescriptor("<clinit>", ValueType.VOID));
if (initMethod != null) { if (initMethod != null) {
dependencyChecker.linkMethod(initMethod.getReference(), stack).use(); agent.linkMethod(initMethod.getReference(), stack).use();
} }
} }
}); });
@ -56,6 +56,6 @@ public class ClassLookupDependencySupport implements DependencyListener {
} }
@Override @Override
public void fieldAchieved(DependencyChecker dependencyChecker, FieldDependency field) { public void fieldAchieved(DependencyAgent dependencyChecker, FieldDependency field) {
} }
} }

View File

@ -30,13 +30,13 @@ public class EnumDependencySupport implements DependencyListener {
private volatile DependencyStack enumConstantsStack; private volatile DependencyStack enumConstantsStack;
@Override @Override
public void started(DependencyChecker dependencyChecker) { public void started(DependencyAgent agent) {
allEnums = dependencyChecker.createNode(); allEnums = agent.createNode();
} }
@Override @Override
public void classAchieved(DependencyChecker dependencyChecker, String className) { public void classAchieved(DependencyAgent agent, String className) {
ClassReader cls = dependencyChecker.getClassSource().get(className); ClassReader cls = agent.getClassSource().get(className);
if (cls == null || cls.getParent() == null || !cls.getParent().equals("java.lang.Enum")) { if (cls == null || cls.getParent() == null || !cls.getParent().equals("java.lang.Enum")) {
return; return;
} }
@ -45,25 +45,25 @@ public class EnumDependencySupport implements DependencyListener {
MethodReader method = cls.getMethod(new MethodDescriptor("values", MethodReader method = cls.getMethod(new MethodDescriptor("values",
ValueType.arrayOf(ValueType.object(cls.getName())))); ValueType.arrayOf(ValueType.object(cls.getName()))));
if (method != null) { if (method != null) {
dependencyChecker.linkMethod(method.getReference(), enumConstantsStack).use(); agent.linkMethod(method.getReference(), enumConstantsStack).use();
} }
} }
} }
@Override @Override
public void methodAchieved(DependencyChecker dependencyChecker, MethodDependency method) { public void methodAchieved(DependencyAgent agent, MethodDependency method) {
if (method.getReference().getClassName().equals("java.lang.Class") && if (method.getReference().getClassName().equals("java.lang.Class") &&
method.getReference().getName().equals("getEnumConstantsImpl")) { method.getReference().getName().equals("getEnumConstantsImpl")) {
allEnums.connect(method.getResult().getArrayItem()); allEnums.connect(method.getResult().getArrayItem());
method.getResult().propagate("[java.lang.Enum"); method.getResult().propagate("[java.lang.Enum");
enumConstantsStack = method.getStack(); enumConstantsStack = method.getStack();
for (String cls : dependencyChecker.getAchievableClasses()) { for (String cls : agent.getAchievableClasses()) {
classAchieved(dependencyChecker, cls); classAchieved(agent, cls);
} }
} }
} }
@Override @Override
public void fieldAchieved(DependencyChecker dependencyChecker, FieldDependency field) { public void fieldAchieved(DependencyAgent agent, FieldDependency field) {
} }
} }

View File

@ -27,13 +27,13 @@ public class NewInstanceDependencySupport implements DependencyListener {
private DependencyStack newInstanceStack; private DependencyStack newInstanceStack;
@Override @Override
public void started(DependencyChecker dependencyChecker) { public void started(DependencyAgent agent) {
allClassesNode = dependencyChecker.createNode(); allClassesNode = agent.createNode();
} }
@Override @Override
public void classAchieved(DependencyChecker dependencyChecker, String className) { public void classAchieved(DependencyAgent agent, String className) {
ClassReader cls = dependencyChecker.getClassSource().get(className); ClassReader cls = agent.getClassSource().get(className);
if (cls == null) { if (cls == null) {
return; return;
} }
@ -47,25 +47,25 @@ public class NewInstanceDependencySupport implements DependencyListener {
} }
@Override @Override
public void methodAchieved(final DependencyChecker dependencyChecker, MethodDependency method) { public void methodAchieved(final DependencyAgent agent, MethodDependency method) {
MethodReader reader = method.getMethod(); MethodReader reader = method.getMethod();
if (reader.getOwnerName().equals("java.lang.Class") && reader.getName().equals("newInstance")) { if (reader.getOwnerName().equals("java.lang.Class") && reader.getName().equals("newInstance")) {
newInstanceStack = method.getStack(); newInstanceStack = method.getStack();
allClassesNode.connect(method.getResult()); allClassesNode.connect(method.getResult());
method.getResult().addConsumer(new DependencyConsumer() { method.getResult().addConsumer(new DependencyConsumer() {
@Override public void consume(String type) { @Override public void consume(String type) {
attachConstructor(dependencyChecker, type); attachConstructor(agent, type);
} }
}); });
} }
} }
private void attachConstructor(DependencyChecker checker, String type) { private void attachConstructor(DependencyAgent checker, String type) {
MethodReference ref = new MethodReference(type, new MethodDescriptor("<init>", ValueType.VOID)); MethodReference ref = new MethodReference(type, new MethodDescriptor("<init>", ValueType.VOID));
checker.linkMethod(ref, newInstanceStack).use(); checker.linkMethod(ref, newInstanceStack).use();
} }
@Override @Override
public void fieldAchieved(DependencyChecker dependencyChecker, FieldDependency field) { public void fieldAchieved(DependencyAgent dependencyAgent, FieldDependency field) {
} }
} }

View File

@ -78,12 +78,12 @@ public class ServiceLoaderSupport implements Generator, DependencyListener {
} }
@Override @Override
public void started(DependencyChecker dependencyChecker) { public void started(DependencyAgent agent) {
allClassesNode = dependencyChecker.createNode(); allClassesNode = agent.createNode();
} }
@Override @Override
public void classAchieved(DependencyChecker dependencyChecker, String className) { public void classAchieved(DependencyAgent agent, String className) {
try { try {
Enumeration<URL> resources = classLoader.getResources("META-INF/services/" + className); Enumeration<URL> resources = classLoader.getResources("META-INF/services/" + className);
while (resources.hasMoreElements()) { while (resources.hasMoreElements()) {
@ -119,7 +119,7 @@ public class ServiceLoaderSupport implements Generator, DependencyListener {
} }
@Override @Override
public void methodAchieved(final DependencyChecker dependencyChecker, MethodDependency method) { public void methodAchieved(final DependencyAgent agent, MethodDependency method) {
MethodReference ref = method.getReference(); MethodReference ref = method.getReference();
if (ref.getClassName().equals("java.util.ServiceLoader") && ref.getName().equals("loadServices")) { if (ref.getClassName().equals("java.util.ServiceLoader") && ref.getName().equals("loadServices")) {
method.getResult().propagate("[java.lang.Object"); method.getResult().propagate("[java.lang.Object");
@ -127,18 +127,18 @@ public class ServiceLoaderSupport implements Generator, DependencyListener {
allClassesNode.connect(method.getResult().getArrayItem()); allClassesNode.connect(method.getResult().getArrayItem());
method.getResult().getArrayItem().addConsumer(new DependencyConsumer() { method.getResult().getArrayItem().addConsumer(new DependencyConsumer() {
@Override public void consume(String type) { @Override public void consume(String type) {
initConstructor(dependencyChecker, type); initConstructor(agent, type);
} }
}); });
} }
} }
private void initConstructor(DependencyChecker dependencyChecker, String type) { private void initConstructor(DependencyAgent agent, String type) {
MethodReference ctor = new MethodReference(type, new MethodDescriptor("<init>", ValueType.VOID)); MethodReference ctor = new MethodReference(type, new MethodDescriptor("<init>", ValueType.VOID));
dependencyChecker.linkMethod(ctor, stack).use(); agent.linkMethod(ctor, stack).use();
} }
@Override @Override
public void fieldAchieved(DependencyChecker dependencyChecker, FieldDependency field) { public void fieldAchieved(DependencyAgent agent, FieldDependency field) {
} }
} }

View File

@ -0,0 +1,26 @@
package org.teavm.dependency;
import org.teavm.model.ClassHolder;
import org.teavm.model.ClassReaderSource;
import org.teavm.model.FieldReference;
import org.teavm.model.MethodReference;
/**
*
* @author Alexey Andreev
*/
public interface DependencyAgent extends DependencyInfo {
DependencyNode createNode();
ClassReaderSource getClassSource();
String generateClassName();
void submitClass(ClassHolder cls);
MethodDependency linkMethod(MethodReference methodRef, DependencyStack stack);
void initClass(String className, final DependencyStack stack);
FieldDependency linkField(FieldReference fieldRef, DependencyStack stack);
}

View File

@ -22,15 +22,17 @@ import java.util.concurrent.ConcurrentMap;
import org.teavm.common.*; import org.teavm.common.*;
import org.teavm.common.ConcurrentCachedMapper.KeyListener; import org.teavm.common.ConcurrentCachedMapper.KeyListener;
import org.teavm.model.*; import org.teavm.model.*;
import org.teavm.model.util.ModelUtils;
/** /**
* *
* @author Alexey Andreev * @author Alexey Andreev
*/ */
public class DependencyChecker implements DependencyInfo { public class DependencyChecker implements DependencyInfo, DependencyAgent {
private static Object dummyValue = new Object(); private static Object dummyValue = new Object();
static final boolean shouldLog = System.getProperty("org.teavm.logDependencies", "false").equals("true"); static final boolean shouldLog = System.getProperty("org.teavm.logDependencies", "false").equals("true");
private ClassReaderSource classSource; private int classNameSuffix;
private DependencyClassSource classSource;
private ClassLoader classLoader; private ClassLoader classLoader;
private FiniteExecutor executor; private FiniteExecutor executor;
private Mapper<MethodReference, MethodReader> methodReaderCache; private Mapper<MethodReference, MethodReader> methodReaderCache;
@ -47,12 +49,12 @@ public class DependencyChecker implements DependencyInfo {
ConcurrentMap<String, DependencyStack> missingClasses = new ConcurrentHashMap<>(); ConcurrentMap<String, DependencyStack> missingClasses = new ConcurrentHashMap<>();
ConcurrentMap<FieldReference, DependencyStack> missingFields = new ConcurrentHashMap<>(); ConcurrentMap<FieldReference, DependencyStack> missingFields = new ConcurrentHashMap<>();
public DependencyChecker(ClassReaderSource classSource, ClassLoader classLoader) { public DependencyChecker(ClassHolderSource classSource, ClassLoader classLoader) {
this(classSource, classLoader, new SimpleFiniteExecutor()); this(classSource, classLoader, new SimpleFiniteExecutor());
} }
public DependencyChecker(ClassReaderSource classSource, ClassLoader classLoader, FiniteExecutor executor) { public DependencyChecker(ClassHolderSource classSource, ClassLoader classLoader, FiniteExecutor executor) {
this.classSource = classSource; this.classSource = new DependencyClassSource(classSource);
this.classLoader = classLoader; this.classLoader = classLoader;
this.executor = executor; this.executor = executor;
methodReaderCache = new ConcurrentCachedMapper<>(new Mapper<MethodReference, MethodReader>() { methodReaderCache = new ConcurrentCachedMapper<>(new Mapper<MethodReference, MethodReader>() {
@ -108,14 +110,26 @@ public class DependencyChecker implements DependencyInfo {
}); });
} }
@Override
public DependencyNode createNode() { public DependencyNode createNode() {
return new DependencyNode(this); return new DependencyNode(this);
} }
@Override
public ClassReaderSource getClassSource() { public ClassReaderSource getClassSource() {
return classSource; return classSource;
} }
@Override
public String generateClassName() {
return "$$tmp$$.TempClass" + classNameSuffix++;
}
@Override
public void submitClass(ClassHolder cls) {
classSource.submit(ModelUtils.copyClass(cls));
}
public void addDependencyListener(DependencyListener listener) { public void addDependencyListener(DependencyListener listener) {
listeners.add(listener); listeners.add(listener);
listener.started(this); listener.started(this);
@ -135,7 +149,7 @@ public class DependencyChecker implements DependencyInfo {
} }
} }
public void schedulePropagation(final DependencyConsumer consumer, final String type) { void schedulePropagation(final DependencyConsumer consumer, final String type) {
executor.executeFast(new Runnable() { executor.executeFast(new Runnable() {
@Override public void run() { @Override public void run() {
consumer.consume(type); consumer.consume(type);
@ -158,6 +172,7 @@ public class DependencyChecker implements DependencyInfo {
return result; return result;
} }
@Override
public MethodDependency linkMethod(MethodReference methodRef, DependencyStack stack) { public MethodDependency linkMethod(MethodReference methodRef, DependencyStack stack) {
if (methodRef == null) { if (methodRef == null) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
@ -166,6 +181,7 @@ public class DependencyChecker implements DependencyInfo {
return methodCache.map(methodRef); return methodCache.map(methodRef);
} }
@Override
public void initClass(String className, final DependencyStack stack) { public void initClass(String className, final DependencyStack stack) {
classStacks.putIfAbsent(className, stack); classStacks.putIfAbsent(className, stack);
MethodDescriptor clinitDesc = new MethodDescriptor("<clinit>", ValueType.VOID); MethodDescriptor clinitDesc = new MethodDescriptor("<clinit>", ValueType.VOID);
@ -302,6 +318,7 @@ public class DependencyChecker implements DependencyInfo {
return dep; return dep;
} }
@Override
public boolean isMethodAchievable(MethodReference methodRef) { public boolean isMethodAchievable(MethodReference methodRef) {
return methodCache.caches(methodRef); return methodCache.caches(methodRef);
} }
@ -321,6 +338,7 @@ public class DependencyChecker implements DependencyInfo {
return new HashSet<>(achievableClasses.keySet()); return new HashSet<>(achievableClasses.keySet());
} }
@Override
public FieldDependency linkField(FieldReference fieldRef, DependencyStack stack) { public FieldDependency linkField(FieldReference fieldRef, DependencyStack stack) {
fieldStacks.putIfAbsent(fieldRef, stack); fieldStacks.putIfAbsent(fieldRef, stack);
return fieldCache.map(fieldRef); return fieldCache.map(fieldRef);
@ -420,4 +438,14 @@ public class DependencyChecker implements DependencyInfo {
sb.append('\n'); sb.append('\n');
} }
} }
@Override
public Collection<ClassHolder> getGeneratedClasses() {
Collection<ClassHolder> classes = classSource.getGeneratedClasses();
List<ClassHolder> copies = new ArrayList<>(classes.size());
for (ClassHolder cls : classes) {
copies.add(ModelUtils.copyClass(cls));
}
return classes;
}
} }

View File

@ -0,0 +1,70 @@
/*
* Copyright 2014 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 java.util.Collection;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.teavm.common.ConcurrentCachedMapper;
import org.teavm.common.Mapper;
import org.teavm.model.ClassHolder;
import org.teavm.model.ClassReader;
import org.teavm.model.ClassReaderSource;
/**
*
* @author Alexey Andreev
*/
class DependencyClassSource implements ClassReaderSource {
private ClassReaderSource innerSource;
private ConcurrentMap<String, ClassHolder> generatedClasses = new ConcurrentHashMap<>();
private ConcurrentCachedMapper<String, ClassReader> cache = new ConcurrentCachedMapper<>(
new Mapper<String, ClassReader>() {
@Override public ClassReader map(String preimage) {
return findClass(preimage);
}
});
public DependencyClassSource(ClassReaderSource innerSource) {
this.innerSource = innerSource;
}
@Override
public ClassReader get(String name) {
return cache.map(name);
}
public void submit(ClassHolder cls) {
if (innerSource.get(cls.getName()) != null) {
throw new IllegalArgumentException("Class " + cls.getName() + " is already defined");
}
if (generatedClasses.putIfAbsent(cls.getName(), cls) != null) {
throw new IllegalArgumentException("Class " + cls.getName() + " is already defined");
}
}
private ClassReader findClass(String name) {
ClassReader cls = innerSource.get(name);
if (cls == null) {
cls = generatedClasses.get(name);
}
return cls;
}
public Collection<ClassHolder> getGeneratedClasses() {
return generatedClasses.values();
}
}

View File

@ -16,6 +16,7 @@
package org.teavm.dependency; package org.teavm.dependency;
import java.util.Collection; import java.util.Collection;
import org.teavm.model.ClassHolder;
import org.teavm.model.FieldReference; import org.teavm.model.FieldReference;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
@ -24,6 +25,8 @@ import org.teavm.model.MethodReference;
* @author Alexey Andreev <konsoletyper@gmail.com> * @author Alexey Andreev <konsoletyper@gmail.com>
*/ */
public interface DependencyInfo { public interface DependencyInfo {
boolean isMethodAchievable(MethodReference methodRef);
Collection<MethodReference> getAchievableMethods(); Collection<MethodReference> getAchievableMethods();
Collection<FieldReference> getAchievableFields(); Collection<FieldReference> getAchievableFields();
@ -33,4 +36,6 @@ public interface DependencyInfo {
FieldDependencyInfo getField(FieldReference fieldRef); FieldDependencyInfo getField(FieldReference fieldRef);
MethodDependencyInfo getMethod(MethodReference methodRef); MethodDependencyInfo getMethod(MethodReference methodRef);
Collection<ClassHolder> getGeneratedClasses();
} }

View File

@ -20,11 +20,11 @@ package org.teavm.dependency;
* @author Alexey Andreev * @author Alexey Andreev
*/ */
public interface DependencyListener { public interface DependencyListener {
void started(DependencyChecker dependencyChecker); void started(DependencyAgent agent);
void classAchieved(DependencyChecker dependencyChecker, String className); void classAchieved(DependencyAgent agent, String className);
void methodAchieved(DependencyChecker dependencyChecker, MethodDependency method); void methodAchieved(DependencyAgent agent, MethodDependency method);
void fieldAchieved(DependencyChecker dependencyChecker, FieldDependency field); void fieldAchieved(DependencyAgent agent, FieldDependency field);
} }

View File

@ -36,30 +36,38 @@ public class Linker {
for (String className : dependency.getAchievableClasses()) { for (String className : dependency.getAchievableClasses()) {
ClassHolder classHolder = classes.get(className); ClassHolder classHolder = classes.get(className);
cutClasses.putClassHolder(classHolder); cutClasses.putClassHolder(classHolder);
for (MethodHolder method : classHolder.getMethods().toArray(new MethodHolder[0])) { link(classHolder);
MethodReference methodRef = new MethodReference(className, method.getDescriptor()); }
MethodDependencyInfo methodDep = dependency.getMethod(methodRef); for (ClassHolder generatedClass : dependency.getGeneratedClasses()) {
if (methodDep == null) { cutClasses.putClassHolder(generatedClass);
classHolder.removeMethod(method); link(generatedClass);
} else if (!methodDep.isUsed()) {
method.getModifiers().add(ElementModifier.ABSTRACT);
method.setProgram(null);
} else if (method.getProgram() != null) {
link(method);
}
}
for (FieldHolder field : classHolder.getFields().toArray(new FieldHolder[0])) {
FieldReference fieldRef = new FieldReference(className, field.getName());
if (dependency.getField(fieldRef) == null) {
classHolder.removeField(field);
}
}
} }
return cutClasses; return cutClasses;
} }
public void link(MethodHolder cls) { public void link(ClassHolder cls) {
Program program = cls.getProgram(); for (MethodHolder method : cls.getMethods().toArray(new MethodHolder[0])) {
MethodReference methodRef = new MethodReference(cls.getName(), method.getDescriptor());
MethodDependencyInfo methodDep = dependency.getMethod(methodRef);
if (methodDep == null) {
cls.removeMethod(method);
} else if (!methodDep.isUsed()) {
method.getModifiers().add(ElementModifier.ABSTRACT);
method.setProgram(null);
} else if (method.getProgram() != null) {
link(method);
}
}
for (FieldHolder field : cls.getFields().toArray(new FieldHolder[0])) {
FieldReference fieldRef = new FieldReference(cls.getName(), field.getName());
if (dependency.getField(fieldRef) == null) {
cls.removeField(field);
}
}
}
public void link(MethodHolder method) {
Program program = method.getProgram();
for (int i = 0; i < program.basicBlockCount(); ++i) { for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i); BasicBlock block = program.basicBlockAt(i);
for (Instruction insn : block.getInstructions()) { for (Instruction insn : block.getInstructions()) {

View File

@ -15,7 +15,6 @@
*/ */
package org.teavm.model; package org.teavm.model;
/** /**
* *
* @author Alexey Andreev * @author Alexey Andreev

View File

@ -15,11 +15,8 @@
*/ */
package org.teavm.model; package org.teavm.model;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.teavm.common.Mapper; import org.teavm.common.Mapper;
import org.teavm.model.util.ProgramUtils; import org.teavm.model.util.ModelUtils;
import org.teavm.resource.MapperClassHolderSource; import org.teavm.resource.MapperClassHolderSource;
/** /**
@ -48,68 +45,6 @@ public class CopyClassHolderSource implements ClassHolderSource {
if (original == null) { if (original == null) {
return null; return null;
} }
ClassHolder copy = new ClassHolder(className); return ModelUtils.copyClass(original);
copy.setLevel(original.getLevel());
copy.getModifiers().addAll(original.getModifiers());
copy.setParent(original.getParent());
copy.getInterfaces().addAll(original.getInterfaces());
for (MethodHolder method : original.getMethods()) {
copy.addMethod(copyMethod(method));
}
for (FieldHolder field : original.getFields()) {
copy.addField(copyField(field));
}
copy.setOwnerName(original.getOwnerName());
copyAnnotations(original.getAnnotations(), copy.getAnnotations());
return copy;
}
private MethodHolder copyMethod(MethodHolder method) {
MethodHolder copy = new MethodHolder(method.getDescriptor());
copy.setLevel(method.getLevel());
copy.getModifiers().addAll(method.getModifiers());
copy.setProgram(ProgramUtils.copy(method.getProgram()));
copyAnnotations(method.getAnnotations(), copy.getAnnotations());
return copy;
}
private FieldHolder copyField(FieldHolder field) {
FieldHolder copy = new FieldHolder(field.getName());
copy.setLevel(field.getLevel());
copy.getModifiers().addAll(field.getModifiers());
copy.setType(field.getType());
copy.setInitialValue(field.getInitialValue());
copyAnnotations(field.getAnnotations(), copy.getAnnotations());
return copy;
}
private void copyAnnotations(AnnotationContainer src, AnnotationContainer dst) {
for (AnnotationHolder annot : src.all()) {
dst.add(copyAnnotation(annot));
}
}
private AnnotationHolder copyAnnotation(AnnotationHolder annot) {
AnnotationHolder copy = new AnnotationHolder(annot.getType());
for (Map.Entry<String, AnnotationValue> entry : annot.getValues().entrySet()) {
copy.getValues().put(entry.getKey(), copyAnnotationValue(entry.getValue()));
}
return copy;
}
private AnnotationValue copyAnnotationValue(AnnotationValue value) {
switch (value.getType()) {
case AnnotationValue.LIST: {
List<AnnotationValue> listCopy = new ArrayList<>();
for (AnnotationValue item : value.getList()) {
listCopy.add(copyAnnotationValue(item));
}
return new AnnotationValue(listCopy);
}
case AnnotationValue.ANNOTATION:
return new AnnotationValue(copyAnnotation(value.getAnnotation()));
default:
return value;
}
} }
} }

View File

@ -0,0 +1,81 @@
package org.teavm.model.util;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.teavm.model.*;
/**
*
* @author Alexey Andreev
*/
public final class ModelUtils {
private ModelUtils() {
}
public static ClassHolder copyClass(ClassHolder original) {
ClassHolder copy = new ClassHolder(original.getName());
copy.setLevel(original.getLevel());
copy.getModifiers().addAll(original.getModifiers());
copy.setParent(original.getParent());
copy.getInterfaces().addAll(original.getInterfaces());
for (MethodHolder method : original.getMethods()) {
copy.addMethod(copyMethod(method));
}
for (FieldHolder field : original.getFields()) {
copy.addField(copyField(field));
}
copy.setOwnerName(original.getOwnerName());
copyAnnotations(original.getAnnotations(), copy.getAnnotations());
return copy;
}
public static MethodHolder copyMethod(MethodHolder method) {
MethodHolder copy = new MethodHolder(method.getDescriptor());
copy.setLevel(method.getLevel());
copy.getModifiers().addAll(method.getModifiers());
copy.setProgram(ProgramUtils.copy(method.getProgram()));
copyAnnotations(method.getAnnotations(), copy.getAnnotations());
return copy;
}
public static FieldHolder copyField(FieldHolder field) {
FieldHolder copy = new FieldHolder(field.getName());
copy.setLevel(field.getLevel());
copy.getModifiers().addAll(field.getModifiers());
copy.setType(field.getType());
copy.setInitialValue(field.getInitialValue());
copyAnnotations(field.getAnnotations(), copy.getAnnotations());
return copy;
}
private static void copyAnnotations(AnnotationContainer src, AnnotationContainer dst) {
for (AnnotationHolder annot : src.all()) {
dst.add(copyAnnotation(annot));
}
}
private static AnnotationHolder copyAnnotation(AnnotationHolder annot) {
AnnotationHolder copy = new AnnotationHolder(annot.getType());
for (Map.Entry<String, AnnotationValue> entry : annot.getValues().entrySet()) {
copy.getValues().put(entry.getKey(), copyAnnotationValue(entry.getValue()));
}
return copy;
}
private static AnnotationValue copyAnnotationValue(AnnotationValue value) {
switch (value.getType()) {
case AnnotationValue.LIST: {
List<AnnotationValue> listCopy = new ArrayList<>();
for (AnnotationValue item : value.getList()) {
listCopy.add(copyAnnotationValue(item));
}
return new AnnotationValue(listCopy);
}
case AnnotationValue.ANNOTATION:
return new AnnotationValue(copyAnnotation(value.getAnnotation()));
default:
return value;
}
}
}

View File

@ -15,6 +15,7 @@
*/ */
package org.teavm.model.util; package org.teavm.model.util;
import java.util.List;
import org.teavm.common.Graph; import org.teavm.common.Graph;
import org.teavm.common.GraphBuilder; import org.teavm.common.GraphBuilder;
import org.teavm.model.*; import org.teavm.model.*;
@ -67,9 +68,9 @@ public final class ProgramUtils {
return graphBuilder.build(); return graphBuilder.build();
} }
public static Program copy(Program program) { public static Program copy(ProgramReader program) {
Program copy = new Program(); Program copy = new Program();
CopyVisitor insnCopier = new CopyVisitor(); InstructionCopyReader insnCopier = new InstructionCopyReader();
insnCopier.programCopy = copy; insnCopier.programCopy = copy;
for (int i = 0; i < program.variableCount(); ++i) { for (int i = 0; i < program.variableCount(); ++i) {
copy.createVariable(); copy.createVariable();
@ -78,16 +79,16 @@ public final class ProgramUtils {
copy.createBasicBlock(); copy.createBasicBlock();
} }
for (int i = 0; i < program.basicBlockCount(); ++i) { for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i); BasicBlockReader block = program.basicBlockAt(i);
BasicBlock blockCopy = copy.basicBlockAt(i); BasicBlock blockCopy = copy.basicBlockAt(i);
for (Instruction insn : block.getInstructions()) { for (int j = 0; j < block.instructionCount(); ++j) {
insn.acceptVisitor(insnCopier); block.readInstruction(j, insnCopier);
blockCopy.getInstructions().add(insnCopier.copy); blockCopy.getInstructions().add(insnCopier.copy);
} }
for (Phi phi : block.getPhis()) { for (PhiReader phi : block.readPhis()) {
Phi phiCopy = new Phi(); Phi phiCopy = new Phi();
phiCopy.setReceiver(copy.variableAt(phi.getReceiver().getIndex())); phiCopy.setReceiver(copy.variableAt(phi.getReceiver().getIndex()));
for (Incoming incoming : phi.getIncomings()) { for (IncomingReader incoming : phi.readIncomings()) {
Incoming incomingCopy = new Incoming(); Incoming incomingCopy = new Incoming();
incomingCopy.setSource(copy.basicBlockAt(incoming.getSource().getIndex())); incomingCopy.setSource(copy.basicBlockAt(incoming.getSource().getIndex()));
incomingCopy.setValue(copy.variableAt(incoming.getValue().getIndex())); incomingCopy.setValue(copy.variableAt(incoming.getValue().getIndex()));
@ -95,7 +96,7 @@ public final class ProgramUtils {
} }
blockCopy.getPhis().add(phiCopy); blockCopy.getPhis().add(phiCopy);
} }
for (TryCatchBlock tryCatch : block.getTryCatchBlocks()) { for (TryCatchBlockReader tryCatch : block.readTryCatchBlocks()) {
TryCatchBlock tryCatchCopy = new TryCatchBlock(); TryCatchBlock tryCatchCopy = new TryCatchBlock();
tryCatchCopy.setExceptionType(tryCatch.getExceptionType()); tryCatchCopy.setExceptionType(tryCatch.getExceptionType());
tryCatchCopy.setExceptionVariable(copy.variableAt(tryCatch.getExceptionVariable().getIndex())); tryCatchCopy.setExceptionVariable(copy.variableAt(tryCatch.getExceptionVariable().getIndex()));
@ -106,160 +107,166 @@ public final class ProgramUtils {
return copy; return copy;
} }
private static class CopyVisitor implements InstructionVisitor { private static class InstructionCopyReader implements InstructionReader {
Instruction copy; Instruction copy;
Program programCopy; Program programCopy;
@Override private Variable copyVar(VariableReader var) {
public void visit(EmptyInstruction insn) {
copy = new EmptyInstruction();
}
private Variable copyVar(Variable var) {
return programCopy.variableAt(var.getIndex()); return programCopy.variableAt(var.getIndex());
} }
private BasicBlock copyBlock(BasicBlock block) { private BasicBlock copyBlock(BasicBlockReader block) {
return programCopy.basicBlockAt(block.getIndex()); return programCopy.basicBlockAt(block.getIndex());
} }
@Override @Override
public void visit(ClassConstantInstruction insn) { public void nop() {
copy = new EmptyInstruction();
}
@Override
public void classConstant(VariableReader receiver, ValueType cst) {
ClassConstantInstruction insnCopy = new ClassConstantInstruction(); ClassConstantInstruction insnCopy = new ClassConstantInstruction();
insnCopy.setConstant(insn.getConstant()); insnCopy.setConstant(cst);
insnCopy.setReceiver(copyVar(insn.getReceiver())); insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy; copy = insnCopy;
} }
@Override @Override
public void visit(NullConstantInstruction insn) { public void nullConstant(VariableReader receiver) {
NullConstantInstruction insnCopy = new NullConstantInstruction(); NullConstantInstruction insnCopy = new NullConstantInstruction();
insnCopy.setReceiver(copyVar(insn.getReceiver())); insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy; copy = insnCopy;
} }
@Override @Override
public void visit(IntegerConstantInstruction insn) { public void integerConstant(VariableReader receiver, int cst) {
IntegerConstantInstruction insnCopy = new IntegerConstantInstruction(); IntegerConstantInstruction insnCopy = new IntegerConstantInstruction();
insnCopy.setConstant(insn.getConstant()); insnCopy.setConstant(cst);
insnCopy.setReceiver(copyVar(insn.getReceiver())); insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy; copy = insnCopy;
} }
@Override @Override
public void visit(LongConstantInstruction insn) { public void longConstant(VariableReader receiver, long cst) {
LongConstantInstruction insnCopy = new LongConstantInstruction(); LongConstantInstruction insnCopy = new LongConstantInstruction();
insnCopy.setConstant(insn.getConstant()); insnCopy.setConstant(cst);
insnCopy.setReceiver(copyVar(insn.getReceiver())); insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy; copy = insnCopy;
} }
@Override @Override
public void visit(FloatConstantInstruction insn) { public void floatConstant(VariableReader receiver, float cst) {
FloatConstantInstruction insnCopy = new FloatConstantInstruction(); FloatConstantInstruction insnCopy = new FloatConstantInstruction();
insnCopy.setConstant(insn.getConstant()); insnCopy.setConstant(cst);
insnCopy.setReceiver(copyVar(insn.getReceiver())); insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy; copy = insnCopy;
} }
@Override @Override
public void visit(DoubleConstantInstruction insn) { public void doubleConstant(VariableReader receiver, double cst) {
DoubleConstantInstruction insnCopy = new DoubleConstantInstruction(); DoubleConstantInstruction insnCopy = new DoubleConstantInstruction();
insnCopy.setConstant(insn.getConstant()); insnCopy.setConstant(cst);
insnCopy.setReceiver(copyVar(insn.getReceiver())); insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy; copy = insnCopy;
} }
@Override @Override
public void visit(StringConstantInstruction insn) { public void stringConstant(VariableReader receiver, String cst) {
StringConstantInstruction insnCopy = new StringConstantInstruction(); StringConstantInstruction insnCopy = new StringConstantInstruction();
insnCopy.setConstant(insn.getConstant()); insnCopy.setConstant(cst);
insnCopy.setReceiver(copyVar(insn.getReceiver())); insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy; copy = insnCopy;
} }
@Override @Override
public void visit(BinaryInstruction insn) { public void binary(BinaryOperation op, VariableReader receiver, VariableReader first, VariableReader second,
BinaryInstruction insnCopy = new BinaryInstruction(insn.getOperation(), insn.getOperandType()); NumericOperandType type) {
insnCopy.setFirstOperand(copyVar(insn.getFirstOperand())); BinaryInstruction insnCopy = new BinaryInstruction(op, type);
insnCopy.setSecondOperand(copyVar(insn.getSecondOperand())); insnCopy.setFirstOperand(copyVar(first));
insnCopy.setReceiver(copyVar(insn.getReceiver())); insnCopy.setSecondOperand(copyVar(second));
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy; copy = insnCopy;
} }
@Override @Override
public void visit(NegateInstruction insn) { public void negate(VariableReader receiver, VariableReader operand, NumericOperandType type) {
NegateInstruction insnCopy = new NegateInstruction(insn.getOperandType()); NegateInstruction insnCopy = new NegateInstruction(type);
insnCopy.setOperand(copyVar(insn.getOperand())); insnCopy.setOperand(copyVar(operand));
insnCopy.setReceiver(copyVar(insn.getReceiver())); insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy; copy = insnCopy;
} }
@Override @Override
public void visit(AssignInstruction insn) { public void assign(VariableReader receiver, VariableReader assignee) {
AssignInstruction insnCopy = new AssignInstruction(); AssignInstruction insnCopy = new AssignInstruction();
insnCopy.setAssignee(copyVar(insn.getAssignee())); insnCopy.setAssignee(copyVar(assignee));
insnCopy.setReceiver(copyVar(insn.getReceiver())); insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy; copy = insnCopy;
} }
@Override @Override
public void visit(CastInstruction insn) { public void cast(VariableReader receiver, VariableReader value, ValueType targetType) {
CastInstruction insnCopy = new CastInstruction(); CastInstruction insnCopy = new CastInstruction();
insnCopy.setValue(copyVar(insn.getValue())); insnCopy.setValue(copyVar(value));
insnCopy.setReceiver(copyVar(insn.getReceiver())); insnCopy.setReceiver(copyVar(receiver));
insnCopy.setTargetType(insn.getTargetType()); insnCopy.setTargetType(targetType);
copy = insnCopy; copy = insnCopy;
} }
@Override @Override
public void visit(CastNumberInstruction insn) { public void cast(VariableReader receiver, VariableReader value, NumericOperandType sourceType,
CastNumberInstruction insnCopy = new CastNumberInstruction(insn.getSourceType(), insn.getTargetType()); NumericOperandType targetType) {
insnCopy.setValue(copyVar(insn.getValue())); CastNumberInstruction insnCopy = new CastNumberInstruction(sourceType, targetType);
insnCopy.setReceiver(copyVar(insn.getReceiver())); insnCopy.setValue(copyVar(value));
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy; copy = insnCopy;
} }
@Override @Override
public void visit(CastIntegerInstruction insn) { public void cast(VariableReader receiver, VariableReader value, IntegerSubtype type,
CastIntegerInstruction insnCopy = new CastIntegerInstruction(insn.getTargetType(), insn.getDirection()); CastIntegerDirection dir) {
insnCopy.setValue(copyVar(insn.getValue())); CastIntegerInstruction insnCopy = new CastIntegerInstruction(type, dir);
insnCopy.setReceiver(copyVar(insn.getReceiver())); insnCopy.setValue(copyVar(value));
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy; copy = insnCopy;
} }
@Override @Override
public void visit(BranchingInstruction insn) { public void jumpIf(BranchingCondition cond, VariableReader operand, BasicBlockReader consequent,
BranchingInstruction insnCopy = new BranchingInstruction(insn.getCondition()); BasicBlockReader alternative) {
insnCopy.setOperand(copyVar(insn.getOperand())); BranchingInstruction insnCopy = new BranchingInstruction(cond);
insnCopy.setConsequent(copyBlock(insn.getConsequent())); insnCopy.setOperand(copyVar(operand));
insnCopy.setAlternative(copyBlock(insn.getAlternative())); insnCopy.setConsequent(copyBlock(consequent));
insnCopy.setAlternative(copyBlock(alternative));
copy = insnCopy; copy = insnCopy;
} }
@Override @Override
public void visit(BinaryBranchingInstruction insn) { public void jumpIf(BinaryBranchingCondition cond, VariableReader first, VariableReader second,
BinaryBranchingInstruction insnCopy = new BinaryBranchingInstruction(insn.getCondition()); BasicBlockReader consequent, BasicBlockReader alternative) {
insnCopy.setFirstOperand(copyVar(insn.getFirstOperand())); BinaryBranchingInstruction insnCopy = new BinaryBranchingInstruction(cond);
insnCopy.setSecondOperand(copyVar(insn.getSecondOperand())); insnCopy.setFirstOperand(copyVar(first));
insnCopy.setConsequent(copyBlock(insn.getConsequent())); insnCopy.setSecondOperand(copyVar(second));
insnCopy.setAlternative(copyBlock(insn.getAlternative())); insnCopy.setConsequent(copyBlock(consequent));
insnCopy.setAlternative(copyBlock(alternative));
copy = insnCopy; copy = insnCopy;
} }
@Override @Override
public void visit(JumpInstruction insn) { public void jump(BasicBlockReader target) {
JumpInstruction insnCopy = new JumpInstruction(); JumpInstruction insnCopy = new JumpInstruction();
insnCopy.setTarget(copyBlock(insn.getTarget())); insnCopy.setTarget(copyBlock(target));
copy = insnCopy; copy = insnCopy;
} }
@Override @Override
public void visit(SwitchInstruction insn) { public void choose(VariableReader condition, List<? extends SwitchTableEntryReader> table,
BasicBlockReader defaultTarget) {
SwitchInstruction insnCopy = new SwitchInstruction(); SwitchInstruction insnCopy = new SwitchInstruction();
insnCopy.setCondition(copyVar(insn.getCondition())); insnCopy.setCondition(copyVar(condition));
insnCopy.setDefaultTarget(copyBlock(insn.getDefaultTarget())); insnCopy.setDefaultTarget(copyBlock(defaultTarget));
for (SwitchTableEntry entry : insn.getEntries()) { for (SwitchTableEntryReader entry : table) {
SwitchTableEntry entryCopy = new SwitchTableEntry(); SwitchTableEntry entryCopy = new SwitchTableEntry();
entryCopy.setCondition(entry.getCondition()); entryCopy.setCondition(entry.getCondition());
entryCopy.setTarget(copyBlock(entry.getTarget())); entryCopy.setTarget(copyBlock(entry.getTarget()));
@ -269,143 +276,147 @@ public final class ProgramUtils {
} }
@Override @Override
public void visit(ExitInstruction insn) { public void exit(VariableReader valueToReturn) {
ExitInstruction insnCopy = new ExitInstruction(); ExitInstruction insnCopy = new ExitInstruction();
insnCopy.setValueToReturn(insn.getValueToReturn() != null ? copyVar(insn.getValueToReturn()) : null); insnCopy.setValueToReturn(valueToReturn != null ? copyVar(valueToReturn) : null);
copy = insnCopy; copy = insnCopy;
} }
@Override @Override
public void visit(RaiseInstruction insn) { public void raise(VariableReader exception) {
RaiseInstruction insnCopy = new RaiseInstruction(); RaiseInstruction insnCopy = new RaiseInstruction();
insnCopy.setException(copyVar(insn.getException())); insnCopy.setException(copyVar(exception));
copy = insnCopy; copy = insnCopy;
} }
@Override @Override
public void visit(ConstructArrayInstruction insn) { public void createArray(VariableReader receiver, ValueType itemType, VariableReader size) {
ConstructArrayInstruction insnCopy = new ConstructArrayInstruction(); ConstructArrayInstruction insnCopy = new ConstructArrayInstruction();
insnCopy.setItemType(insn.getItemType()); insnCopy.setItemType(itemType);
insnCopy.setSize(copyVar(insn.getSize())); insnCopy.setSize(copyVar(size));
insnCopy.setReceiver(copyVar(insn.getReceiver())); insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy; copy = insnCopy;
} }
@Override @Override
public void visit(ConstructInstruction insn) { public void createArray(VariableReader receiver, ValueType itemType,
ConstructInstruction insnCopy = new ConstructInstruction(); List<? extends VariableReader> dimensions) {
insnCopy.setType(insn.getType());
insnCopy.setReceiver(copyVar(insn.getReceiver()));
copy = insnCopy;
}
@Override
public void visit(ConstructMultiArrayInstruction insn) {
ConstructMultiArrayInstruction insnCopy = new ConstructMultiArrayInstruction(); ConstructMultiArrayInstruction insnCopy = new ConstructMultiArrayInstruction();
insnCopy.setItemType(insn.getItemType()); insnCopy.setItemType(itemType);
insnCopy.setReceiver(copyVar(insn.getReceiver())); insnCopy.setReceiver(copyVar(receiver));
for (Variable dim : insn.getDimensions()) { for (VariableReader dim : dimensions) {
insnCopy.getDimensions().add(copyVar(dim)); insnCopy.getDimensions().add(copyVar(dim));
} }
copy = insnCopy; copy = insnCopy;
} }
@Override @Override
public void visit(GetFieldInstruction insn) { public void create(VariableReader receiver, String type) {
ConstructInstruction insnCopy = new ConstructInstruction();
insnCopy.setType(type);
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
}
@Override
public void getField(VariableReader receiver, VariableReader instance, FieldReference field,
ValueType fieldType) {
GetFieldInstruction insnCopy = new GetFieldInstruction(); GetFieldInstruction insnCopy = new GetFieldInstruction();
insnCopy.setField(insn.getField()); insnCopy.setField(field);
insnCopy.setFieldType(insn.getFieldType()); insnCopy.setFieldType(fieldType);
insnCopy.setInstance(insn.getInstance() != null ? copyVar(insn.getInstance()) : null); insnCopy.setInstance(instance != null ? copyVar(instance) : null);
insnCopy.setReceiver(copyVar(insn.getReceiver())); insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy; copy = insnCopy;
} }
@Override @Override
public void visit(PutFieldInstruction insn) { public void putField(VariableReader instance, FieldReference field, VariableReader value) {
PutFieldInstruction insnCopy = new PutFieldInstruction(); PutFieldInstruction insnCopy = new PutFieldInstruction();
insnCopy.setField(insn.getField()); insnCopy.setField(field);
insnCopy.setInstance(insn.getInstance() != null ? copyVar(insn.getInstance()) : null); insnCopy.setInstance(instance != null ? copyVar(instance) : null);
insnCopy.setValue(copyVar(insn.getValue())); insnCopy.setValue(copyVar(value));
copy = insnCopy; copy = insnCopy;
} }
@Override @Override
public void visit(ArrayLengthInstruction insn) { public void arrayLength(VariableReader receiver, VariableReader array) {
ArrayLengthInstruction insnCopy = new ArrayLengthInstruction(); ArrayLengthInstruction insnCopy = new ArrayLengthInstruction();
insnCopy.setArray(copyVar(insn.getArray())); insnCopy.setArray(copyVar(array));
insnCopy.setReceiver(copyVar(insn.getReceiver())); insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy; copy = insnCopy;
} }
@Override @Override
public void visit(CloneArrayInstruction insn) { public void cloneArray(VariableReader receiver, VariableReader array) {
CloneArrayInstruction insnCopy = new CloneArrayInstruction(); CloneArrayInstruction insnCopy = new CloneArrayInstruction();
insnCopy.setArray(copyVar(insn.getArray())); insnCopy.setArray(copyVar(array));
insnCopy.setReceiver(copyVar(insn.getReceiver())); insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy; copy = insnCopy;
} }
@Override @Override
public void visit(UnwrapArrayInstruction insn) { public void unwrapArray(VariableReader receiver, VariableReader array, ArrayElementType elementType) {
UnwrapArrayInstruction insnCopy = new UnwrapArrayInstruction(insn.getElementType()); UnwrapArrayInstruction insnCopy = new UnwrapArrayInstruction(elementType);
insnCopy.setArray(copyVar(insn.getArray())); insnCopy.setArray(copyVar(array));
insnCopy.setReceiver(copyVar(insn.getReceiver())); insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy; copy = insnCopy;
} }
@Override @Override
public void visit(GetElementInstruction insn) { public void getElement(VariableReader receiver, VariableReader array, VariableReader index) {
GetElementInstruction insnCopy = new GetElementInstruction(); GetElementInstruction insnCopy = new GetElementInstruction();
insnCopy.setArray(copyVar(insn.getArray())); insnCopy.setArray(copyVar(array));
insnCopy.setReceiver(copyVar(insn.getReceiver())); insnCopy.setReceiver(copyVar(receiver));
insnCopy.setIndex(copyVar(insn.getIndex())); insnCopy.setIndex(copyVar(index));
copy = insnCopy; copy = insnCopy;
} }
@Override @Override
public void visit(PutElementInstruction insn) { public void putElement(VariableReader array, VariableReader index, VariableReader value) {
PutElementInstruction insnCopy = new PutElementInstruction(); PutElementInstruction insnCopy = new PutElementInstruction();
insnCopy.setArray(copyVar(insn.getArray())); insnCopy.setArray(copyVar(array));
insnCopy.setValue(copyVar(insn.getValue())); insnCopy.setValue(copyVar(value));
insnCopy.setIndex(copyVar(insn.getIndex())); insnCopy.setIndex(copyVar(index));
copy = insnCopy; copy = insnCopy;
} }
@Override @Override
public void visit(InvokeInstruction insn) { public void invoke(VariableReader receiver, VariableReader instance, MethodReference method,
List<? extends VariableReader> arguments, InvocationType type) {
InvokeInstruction insnCopy = new InvokeInstruction(); InvokeInstruction insnCopy = new InvokeInstruction();
insnCopy.setMethod(insn.getMethod()); insnCopy.setMethod(method);
insnCopy.setType(insn.getType()); insnCopy.setType(type);
insnCopy.setInstance(insn.getInstance() != null ? copyVar(insn.getInstance()) : null); insnCopy.setInstance(instance != null ? copyVar(instance) : null);
insnCopy.setReceiver(insn.getReceiver() != null ? copyVar(insn.getReceiver()) : null); insnCopy.setReceiver(receiver != null ? copyVar(receiver) : null);
for (Variable arg : insn.getArguments()) { for (VariableReader arg : arguments) {
insnCopy.getArguments().add(copyVar(arg)); insnCopy.getArguments().add(copyVar(arg));
} }
copy = insnCopy; copy = insnCopy;
} }
@Override @Override
public void visit(IsInstanceInstruction insn) { public void isInstance(VariableReader receiver, VariableReader value, ValueType type) {
IsInstanceInstruction insnCopy = new IsInstanceInstruction(); IsInstanceInstruction insnCopy = new IsInstanceInstruction();
insnCopy.setValue(copyVar(insn.getValue())); insnCopy.setValue(copyVar(value));
insnCopy.setReceiver(copyVar(insn.getReceiver())); insnCopy.setReceiver(copyVar(receiver));
insnCopy.setType(insn.getType()); insnCopy.setType(type);
copy = insnCopy; copy = insnCopy;
} }
@Override @Override
public void visit(InitClassInstruction insn) { public void initClass(String className) {
InitClassInstruction insnCopy = new InitClassInstruction(); InitClassInstruction insnCopy = new InitClassInstruction();
insnCopy.setClassName(insn.getClassName()); insnCopy.setClassName(className);
copy = insnCopy; copy = insnCopy;
} }
@Override @Override
public void visit(NullCheckInstruction insn) { public void nullCheck(VariableReader receiver, VariableReader value) {
NullCheckInstruction insnCopy = new NullCheckInstruction(); NullCheckInstruction insnCopy = new NullCheckInstruction();
insnCopy.setReceiver(copyVar(insn.getReceiver())); insnCopy.setReceiver(copyVar(receiver));
insnCopy.setValue(copyVar(insn.getValue())); insnCopy.setValue(copyVar(value));
copy = insnCopy; copy = insnCopy;
} }
} }
} }

View File

@ -17,6 +17,7 @@ package org.teavm.vm;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import org.teavm.common.ConcurrentCachedMapper; import org.teavm.common.ConcurrentCachedMapper;
import org.teavm.common.Mapper; import org.teavm.common.Mapper;
import org.teavm.model.ClassHolder; import org.teavm.model.ClassHolder;

View File

@ -93,7 +93,6 @@ public class TeaVM implements TeaVMHost {
classSource.addTransformer(transformer); classSource.addTransformer(transformer);
} }
@Override @Override
public void add(MethodReference methodRef, Generator generator) { public void add(MethodReference methodRef, Generator generator) {
methodGenerators.put(methodRef, generator); methodGenerators.put(methodRef, generator);

View File

@ -67,21 +67,21 @@ public class EntryPointGenerator extends AbstractRendererListener implements Dep
} }
@Override @Override
public void started(DependencyChecker dependencyChecker) { public void started(DependencyAgent agent) {
for (String className : classesToLoad) { for (String className : classesToLoad) {
dependencyChecker.initClass(className, DependencyStack.ROOT); agent.initClass(className, DependencyStack.ROOT);
} }
} }
@Override @Override
public void classAchieved(DependencyChecker dependencyChecker, String className) { public void classAchieved(DependencyAgent agent, String className) {
} }
@Override @Override
public void methodAchieved(DependencyChecker dependencyChecker, MethodDependency method) { public void methodAchieved(DependencyAgent agent, MethodDependency method) {
} }
@Override @Override
public void fieldAchieved(DependencyChecker dependencyChecker, FieldDependency field) { public void fieldAchieved(DependencyAgent agent, FieldDependency field) {
} }
} }

View File

@ -27,8 +27,8 @@ public class JavaScriptBodyDependency implements DependencyListener {
private DependencyNode allClassesNode; private DependencyNode allClassesNode;
@Override @Override
public void started(DependencyChecker dependencyChecker) { public void started(DependencyAgent agent) {
allClassesNode = dependencyChecker.createNode(); allClassesNode = agent.createNode();
allClassesNode.setTag("JavaScriptBody:global"); allClassesNode.setTag("JavaScriptBody:global");
} }
@ -43,8 +43,8 @@ public class JavaScriptBodyDependency implements DependencyListener {
} }
@Override @Override
public void classAchieved(DependencyChecker dependencyChecker, String className) { public void classAchieved(DependencyAgent agent, String className) {
ClassReader cls = dependencyChecker.getClassSource().get(className); ClassReader cls = agent.getClassSource().get(className);
if (cls != null && !cls.hasModifier(ElementModifier.ABSTRACT) && if (cls != null && !cls.hasModifier(ElementModifier.ABSTRACT) &&
!cls.hasModifier(ElementModifier.INTERFACE)) { !cls.hasModifier(ElementModifier.INTERFACE)) {
allClassesNode.propagate(className); allClassesNode.propagate(className);
@ -52,13 +52,13 @@ public class JavaScriptBodyDependency implements DependencyListener {
} }
@Override @Override
public void methodAchieved(DependencyChecker dependencyChecker, MethodDependency method) { public void methodAchieved(DependencyAgent agent, MethodDependency method) {
if (method.isMissing()) { if (method.isMissing()) {
return; return;
} }
AnnotationReader annot = method.getMethod().getAnnotations().get(JavaScriptBody.class.getName()); AnnotationReader annot = method.getMethod().getAnnotations().get(JavaScriptBody.class.getName());
if (annot != null) { if (annot != null) {
includeDefaultDependencies(dependencyChecker); includeDefaultDependencies(agent);
AnnotationValue javacall = annot.getValue("javacall"); AnnotationValue javacall = annot.getValue("javacall");
if (method.getResult() != null) { if (method.getResult() != null) {
allClassesNode.connect(method.getResult()); allClassesNode.connect(method.getResult());
@ -74,26 +74,26 @@ public class JavaScriptBodyDependency implements DependencyListener {
} }
if (javacall != null && javacall.getBoolean()) { if (javacall != null && javacall.getBoolean()) {
String body = annot.getValue("body").getString(); String body = annot.getValue("body").getString();
new GeneratorJsCallback(dependencyChecker, method).parse(body); new GeneratorJsCallback(agent, method).parse(body);
} }
} }
} }
private void includeDefaultDependencies(DependencyChecker dependencyChecker) { private void includeDefaultDependencies(DependencyAgent agent) {
dependencyChecker.linkMethod(JavaScriptConvGenerator.fromJsMethod, DependencyStack.ROOT).use(); agent.linkMethod(JavaScriptConvGenerator.fromJsMethod, DependencyStack.ROOT).use();
dependencyChecker.linkMethod(JavaScriptConvGenerator.toJsMethod, DependencyStack.ROOT).use(); agent.linkMethod(JavaScriptConvGenerator.toJsMethod, DependencyStack.ROOT).use();
dependencyChecker.linkMethod(JavaScriptConvGenerator.intValueMethod, DependencyStack.ROOT).use(); agent.linkMethod(JavaScriptConvGenerator.intValueMethod, DependencyStack.ROOT).use();
dependencyChecker.linkMethod(JavaScriptConvGenerator.valueOfIntMethod, DependencyStack.ROOT).use(); agent.linkMethod(JavaScriptConvGenerator.valueOfIntMethod, DependencyStack.ROOT).use();
dependencyChecker.linkMethod(JavaScriptConvGenerator.booleanValueMethod, DependencyStack.ROOT).use(); agent.linkMethod(JavaScriptConvGenerator.booleanValueMethod, DependencyStack.ROOT).use();
dependencyChecker.linkMethod(JavaScriptConvGenerator.valueOfBooleanMethod, DependencyStack.ROOT).use(); agent.linkMethod(JavaScriptConvGenerator.valueOfBooleanMethod, DependencyStack.ROOT).use();
dependencyChecker.linkMethod(JavaScriptConvGenerator.doubleValueMethod, DependencyStack.ROOT).use(); agent.linkMethod(JavaScriptConvGenerator.doubleValueMethod, DependencyStack.ROOT).use();
dependencyChecker.linkMethod(JavaScriptConvGenerator.valueOfDoubleMethod, DependencyStack.ROOT).use(); agent.linkMethod(JavaScriptConvGenerator.valueOfDoubleMethod, DependencyStack.ROOT).use();
dependencyChecker.linkMethod(JavaScriptConvGenerator.charValueMethod, DependencyStack.ROOT).use(); agent.linkMethod(JavaScriptConvGenerator.charValueMethod, DependencyStack.ROOT).use();
dependencyChecker.linkMethod(JavaScriptConvGenerator.valueOfCharMethod, DependencyStack.ROOT).use(); agent.linkMethod(JavaScriptConvGenerator.valueOfCharMethod, DependencyStack.ROOT).use();
} }
@Override @Override
public void fieldAchieved(DependencyChecker dependencyChecker, FieldDependency fieldDep) { public void fieldAchieved(DependencyAgent agent, FieldDependency fieldDep) {
} }
private static MethodReader findMethod(ClassReaderSource classSource, String clsName, MethodDescriptor desc) { private static MethodReader findMethod(ClassReaderSource classSource, String clsName, MethodDescriptor desc) {
@ -124,17 +124,17 @@ public class JavaScriptBodyDependency implements DependencyListener {
} }
private class GeneratorJsCallback extends JsCallback { private class GeneratorJsCallback extends JsCallback {
private DependencyChecker dependencyChecker; private DependencyAgent agent;
private MethodDependency caller; private MethodDependency caller;
public GeneratorJsCallback(DependencyChecker dependencyChecker, MethodDependency caller) { public GeneratorJsCallback(DependencyAgent agent, MethodDependency caller) {
this.dependencyChecker = dependencyChecker; this.agent = agent;
this.caller = caller; this.caller = caller;
} }
@Override protected CharSequence callMethod(String ident, String fqn, String method, String params) { @Override protected CharSequence callMethod(String ident, String fqn, String method, String params) {
MethodDescriptor desc = MethodDescriptor.parse(method + params + "V"); MethodDescriptor desc = MethodDescriptor.parse(method + params + "V");
MethodReader reader = findMethod(dependencyChecker.getClassSource(), fqn, desc); MethodReader reader = findMethod(agent.getClassSource(), fqn, desc);
MethodReference ref = reader != null ? reader.getReference() : new MethodReference(fqn, desc); MethodReference ref = reader != null ? reader.getReference() : new MethodReference(fqn, desc);
MethodDependency methodDep = dependencyChecker.linkMethod(ref, caller.getStack()); MethodDependency methodDep = agent.linkMethod(ref, caller.getStack());
if (!methodDep.isMissing()) { if (!methodDep.isMissing()) {
if (reader.hasModifier(ElementModifier.STATIC) || reader.hasModifier(ElementModifier.FINAL)) { if (reader.hasModifier(ElementModifier.STATIC) || reader.hasModifier(ElementModifier.FINAL)) {
methodDep.use(); methodDep.use();
@ -142,7 +142,7 @@ public class JavaScriptBodyDependency implements DependencyListener {
allClassesNode.connect(methodDep.getVariable(i)); allClassesNode.connect(methodDep.getVariable(i));
} }
} else { } else {
allClassesNode.addConsumer(new VirtualCallbackConsumer(dependencyChecker, reader, caller)); allClassesNode.addConsumer(new VirtualCallbackConsumer(agent, reader, caller));
} }
} }
return ""; return "";
@ -150,30 +150,30 @@ public class JavaScriptBodyDependency implements DependencyListener {
} }
private class VirtualCallbackConsumer implements DependencyConsumer { private class VirtualCallbackConsumer implements DependencyConsumer {
private DependencyChecker dependencyChecker; private DependencyAgent agent;
private MethodReader superMethod; private MethodReader superMethod;
private ClassReader superClass; private ClassReader superClass;
private MethodDependency caller; private MethodDependency caller;
public VirtualCallbackConsumer(DependencyChecker dependencyChecker, MethodReader superMethod, public VirtualCallbackConsumer(DependencyAgent agent, MethodReader superMethod,
MethodDependency caller) { MethodDependency caller) {
this.dependencyChecker = dependencyChecker; this.agent = agent;
this.superMethod = superMethod; this.superMethod = superMethod;
this.caller = caller; this.caller = caller;
this.superClass = dependencyChecker.getClassSource().get(superMethod.getOwnerName()); this.superClass = agent.getClassSource().get(superMethod.getOwnerName());
} }
@Override public void consume(String type) { @Override public void consume(String type) {
if (!isAssignableFrom(superClass, type)) { if (!isAssignableFrom(superClass, type)) {
return; return;
} }
MethodReference methodRef = new MethodReference(type, superMethod.getDescriptor()); MethodReference methodRef = new MethodReference(type, superMethod.getDescriptor());
MethodDependency method = dependencyChecker.linkMethod(methodRef, caller.getStack()); MethodDependency method = agent.linkMethod(methodRef, caller.getStack());
method.use(); method.use();
for (int i = 0; i < method.getParameterCount(); ++i) { for (int i = 0; i < method.getParameterCount(); ++i) {
allClassesNode.connect(method.getVariable(i)); allClassesNode.connect(method.getVariable(i));
} }
} }
private boolean isAssignableFrom(ClassReader supertype, String subtypeName) { private boolean isAssignableFrom(ClassReader supertype, String subtypeName) {
ClassReaderSource classSource = dependencyChecker.getClassSource(); ClassReaderSource classSource = agent.getClassSource();
if (supertype.getName().equals(subtypeName)) { if (supertype.getName().equals(subtypeName)) {
return true; return true;
} }

View File

@ -31,13 +31,13 @@ class TestExceptionDependency implements DependencyListener {
private DependencyNode allClasses; private DependencyNode allClasses;
@Override @Override
public void started(DependencyChecker dependencyChecker) { public void started(DependencyAgent agent) {
allClasses = dependencyChecker.createNode(); allClasses = agent.createNode();
} }
@Override @Override
public void classAchieved(DependencyChecker dependencyChecker, String className) { public void classAchieved(DependencyAgent agent, String className) {
if (isException(dependencyChecker.getClassSource(), className)) { if (isException(agent.getClassSource(), className)) {
allClasses.propagate(className); allClasses.propagate(className);
} }
} }
@ -57,13 +57,13 @@ class TestExceptionDependency implements DependencyListener {
} }
@Override @Override
public void methodAchieved(DependencyChecker dependencyChecker, MethodDependency method) { public void methodAchieved(DependencyAgent agent, MethodDependency method) {
if (method.getReference().equals(getMessageRef)) { if (method.getReference().equals(getMessageRef)) {
allClasses.connect(method.getVariable(0)); allClasses.connect(method.getVariable(0));
} }
} }
@Override @Override
public void fieldAchieved(DependencyChecker dependencyChecker, FieldDependency field) { public void fieldAchieved(DependencyAgent agent, FieldDependency field) {
} }
} }