mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
First attempt to refactor dependency checker
This commit is contained in:
parent
8286ad9289
commit
00d160e92b
|
@ -26,29 +26,29 @@ public class ClassLookupDependencySupport implements DependencyListener {
|
|||
private DependencyNode allClasses;
|
||||
|
||||
@Override
|
||||
public void started(DependencyChecker dependencyChecker) {
|
||||
allClasses = dependencyChecker.createNode();
|
||||
public void started(DependencyAgent agent) {
|
||||
allClasses = agent.createNode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void classAchieved(DependencyChecker dependencyChecker, String className) {
|
||||
public void classAchieved(DependencyAgent agent, String className) {
|
||||
allClasses.propagate(className);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void methodAchieved(final DependencyChecker dependencyChecker, MethodDependency method) {
|
||||
public void methodAchieved(final DependencyAgent agent, MethodDependency method) {
|
||||
MethodReference ref = method.getReference();
|
||||
if (ref.getClassName().equals("java.lang.Class") && ref.getName().equals("forNameImpl")) {
|
||||
final DependencyStack stack = method.getStack();
|
||||
allClasses.addConsumer(new DependencyConsumer() {
|
||||
@Override public void consume(String type) {
|
||||
ClassReader cls = dependencyChecker.getClassSource().get(type);
|
||||
ClassReader cls = agent.getClassSource().get(type);
|
||||
if (cls == null) {
|
||||
return;
|
||||
}
|
||||
MethodReader initMethod = cls.getMethod(new MethodDescriptor("<clinit>", ValueType.VOID));
|
||||
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
|
||||
public void fieldAchieved(DependencyChecker dependencyChecker, FieldDependency field) {
|
||||
public void fieldAchieved(DependencyAgent dependencyChecker, FieldDependency field) {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,13 +30,13 @@ public class EnumDependencySupport implements DependencyListener {
|
|||
private volatile DependencyStack enumConstantsStack;
|
||||
|
||||
@Override
|
||||
public void started(DependencyChecker dependencyChecker) {
|
||||
allEnums = dependencyChecker.createNode();
|
||||
public void started(DependencyAgent agent) {
|
||||
allEnums = agent.createNode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void classAchieved(DependencyChecker dependencyChecker, String className) {
|
||||
ClassReader cls = dependencyChecker.getClassSource().get(className);
|
||||
public void classAchieved(DependencyAgent agent, String className) {
|
||||
ClassReader cls = agent.getClassSource().get(className);
|
||||
if (cls == null || cls.getParent() == null || !cls.getParent().equals("java.lang.Enum")) {
|
||||
return;
|
||||
}
|
||||
|
@ -45,25 +45,25 @@ public class EnumDependencySupport implements DependencyListener {
|
|||
MethodReader method = cls.getMethod(new MethodDescriptor("values",
|
||||
ValueType.arrayOf(ValueType.object(cls.getName()))));
|
||||
if (method != null) {
|
||||
dependencyChecker.linkMethod(method.getReference(), enumConstantsStack).use();
|
||||
agent.linkMethod(method.getReference(), enumConstantsStack).use();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void methodAchieved(DependencyChecker dependencyChecker, MethodDependency method) {
|
||||
public void methodAchieved(DependencyAgent agent, MethodDependency method) {
|
||||
if (method.getReference().getClassName().equals("java.lang.Class") &&
|
||||
method.getReference().getName().equals("getEnumConstantsImpl")) {
|
||||
allEnums.connect(method.getResult().getArrayItem());
|
||||
method.getResult().propagate("[java.lang.Enum");
|
||||
enumConstantsStack = method.getStack();
|
||||
for (String cls : dependencyChecker.getAchievableClasses()) {
|
||||
classAchieved(dependencyChecker, cls);
|
||||
for (String cls : agent.getAchievableClasses()) {
|
||||
classAchieved(agent, cls);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fieldAchieved(DependencyChecker dependencyChecker, FieldDependency field) {
|
||||
public void fieldAchieved(DependencyAgent agent, FieldDependency field) {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,13 +27,13 @@ public class NewInstanceDependencySupport implements DependencyListener {
|
|||
private DependencyStack newInstanceStack;
|
||||
|
||||
@Override
|
||||
public void started(DependencyChecker dependencyChecker) {
|
||||
allClassesNode = dependencyChecker.createNode();
|
||||
public void started(DependencyAgent agent) {
|
||||
allClassesNode = agent.createNode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void classAchieved(DependencyChecker dependencyChecker, String className) {
|
||||
ClassReader cls = dependencyChecker.getClassSource().get(className);
|
||||
public void classAchieved(DependencyAgent agent, String className) {
|
||||
ClassReader cls = agent.getClassSource().get(className);
|
||||
if (cls == null) {
|
||||
return;
|
||||
}
|
||||
|
@ -47,25 +47,25 @@ public class NewInstanceDependencySupport implements DependencyListener {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void methodAchieved(final DependencyChecker dependencyChecker, MethodDependency method) {
|
||||
public void methodAchieved(final DependencyAgent agent, MethodDependency method) {
|
||||
MethodReader reader = method.getMethod();
|
||||
if (reader.getOwnerName().equals("java.lang.Class") && reader.getName().equals("newInstance")) {
|
||||
newInstanceStack = method.getStack();
|
||||
allClassesNode.connect(method.getResult());
|
||||
method.getResult().addConsumer(new DependencyConsumer() {
|
||||
@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));
|
||||
checker.linkMethod(ref, newInstanceStack).use();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fieldAchieved(DependencyChecker dependencyChecker, FieldDependency field) {
|
||||
public void fieldAchieved(DependencyAgent dependencyAgent, FieldDependency field) {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,12 +78,12 @@ public class ServiceLoaderSupport implements Generator, DependencyListener {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void started(DependencyChecker dependencyChecker) {
|
||||
allClassesNode = dependencyChecker.createNode();
|
||||
public void started(DependencyAgent agent) {
|
||||
allClassesNode = agent.createNode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void classAchieved(DependencyChecker dependencyChecker, String className) {
|
||||
public void classAchieved(DependencyAgent agent, String className) {
|
||||
try {
|
||||
Enumeration<URL> resources = classLoader.getResources("META-INF/services/" + className);
|
||||
while (resources.hasMoreElements()) {
|
||||
|
@ -119,7 +119,7 @@ public class ServiceLoaderSupport implements Generator, DependencyListener {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void methodAchieved(final DependencyChecker dependencyChecker, MethodDependency method) {
|
||||
public void methodAchieved(final DependencyAgent agent, MethodDependency method) {
|
||||
MethodReference ref = method.getReference();
|
||||
if (ref.getClassName().equals("java.util.ServiceLoader") && ref.getName().equals("loadServices")) {
|
||||
method.getResult().propagate("[java.lang.Object");
|
||||
|
@ -127,18 +127,18 @@ public class ServiceLoaderSupport implements Generator, DependencyListener {
|
|||
allClassesNode.connect(method.getResult().getArrayItem());
|
||||
method.getResult().getArrayItem().addConsumer(new DependencyConsumer() {
|
||||
@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));
|
||||
dependencyChecker.linkMethod(ctor, stack).use();
|
||||
agent.linkMethod(ctor, stack).use();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fieldAchieved(DependencyChecker dependencyChecker, FieldDependency field) {
|
||||
public void fieldAchieved(DependencyAgent agent, FieldDependency field) {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -22,15 +22,17 @@ import java.util.concurrent.ConcurrentMap;
|
|||
import org.teavm.common.*;
|
||||
import org.teavm.common.ConcurrentCachedMapper.KeyListener;
|
||||
import org.teavm.model.*;
|
||||
import org.teavm.model.util.ModelUtils;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public class DependencyChecker implements DependencyInfo {
|
||||
public class DependencyChecker implements DependencyInfo, DependencyAgent {
|
||||
private static Object dummyValue = new Object();
|
||||
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 FiniteExecutor executor;
|
||||
private Mapper<MethodReference, MethodReader> methodReaderCache;
|
||||
|
@ -47,12 +49,12 @@ public class DependencyChecker implements DependencyInfo {
|
|||
ConcurrentMap<String, DependencyStack> missingClasses = 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());
|
||||
}
|
||||
|
||||
public DependencyChecker(ClassReaderSource classSource, ClassLoader classLoader, FiniteExecutor executor) {
|
||||
this.classSource = classSource;
|
||||
public DependencyChecker(ClassHolderSource classSource, ClassLoader classLoader, FiniteExecutor executor) {
|
||||
this.classSource = new DependencyClassSource(classSource);
|
||||
this.classLoader = classLoader;
|
||||
this.executor = executor;
|
||||
methodReaderCache = new ConcurrentCachedMapper<>(new Mapper<MethodReference, MethodReader>() {
|
||||
|
@ -108,14 +110,26 @@ public class DependencyChecker implements DependencyInfo {
|
|||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public DependencyNode createNode() {
|
||||
return new DependencyNode(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassReaderSource getClassSource() {
|
||||
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) {
|
||||
listeners.add(listener);
|
||||
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() {
|
||||
@Override public void run() {
|
||||
consumer.consume(type);
|
||||
|
@ -158,6 +172,7 @@ public class DependencyChecker implements DependencyInfo {
|
|||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodDependency linkMethod(MethodReference methodRef, DependencyStack stack) {
|
||||
if (methodRef == null) {
|
||||
throw new IllegalArgumentException();
|
||||
|
@ -166,6 +181,7 @@ public class DependencyChecker implements DependencyInfo {
|
|||
return methodCache.map(methodRef);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initClass(String className, final DependencyStack stack) {
|
||||
classStacks.putIfAbsent(className, stack);
|
||||
MethodDescriptor clinitDesc = new MethodDescriptor("<clinit>", ValueType.VOID);
|
||||
|
@ -302,6 +318,7 @@ public class DependencyChecker implements DependencyInfo {
|
|||
return dep;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMethodAchievable(MethodReference methodRef) {
|
||||
return methodCache.caches(methodRef);
|
||||
}
|
||||
|
@ -321,6 +338,7 @@ public class DependencyChecker implements DependencyInfo {
|
|||
return new HashSet<>(achievableClasses.keySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldDependency linkField(FieldReference fieldRef, DependencyStack stack) {
|
||||
fieldStacks.putIfAbsent(fieldRef, stack);
|
||||
return fieldCache.map(fieldRef);
|
||||
|
@ -420,4 +438,14 @@ public class DependencyChecker implements DependencyInfo {
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -16,6 +16,7 @@
|
|||
package org.teavm.dependency;
|
||||
|
||||
import java.util.Collection;
|
||||
import org.teavm.model.ClassHolder;
|
||||
import org.teavm.model.FieldReference;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
|
@ -24,6 +25,8 @@ import org.teavm.model.MethodReference;
|
|||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||
*/
|
||||
public interface DependencyInfo {
|
||||
boolean isMethodAchievable(MethodReference methodRef);
|
||||
|
||||
Collection<MethodReference> getAchievableMethods();
|
||||
|
||||
Collection<FieldReference> getAchievableFields();
|
||||
|
@ -33,4 +36,6 @@ public interface DependencyInfo {
|
|||
FieldDependencyInfo getField(FieldReference fieldRef);
|
||||
|
||||
MethodDependencyInfo getMethod(MethodReference methodRef);
|
||||
|
||||
Collection<ClassHolder> getGeneratedClasses();
|
||||
}
|
||||
|
|
|
@ -20,11 +20,11 @@ package org.teavm.dependency;
|
|||
* @author Alexey Andreev
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -36,30 +36,38 @@ public class Linker {
|
|||
for (String className : dependency.getAchievableClasses()) {
|
||||
ClassHolder classHolder = classes.get(className);
|
||||
cutClasses.putClassHolder(classHolder);
|
||||
for (MethodHolder method : classHolder.getMethods().toArray(new MethodHolder[0])) {
|
||||
MethodReference methodRef = new MethodReference(className, method.getDescriptor());
|
||||
MethodDependencyInfo methodDep = dependency.getMethod(methodRef);
|
||||
if (methodDep == null) {
|
||||
classHolder.removeMethod(method);
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
link(classHolder);
|
||||
}
|
||||
for (ClassHolder generatedClass : dependency.getGeneratedClasses()) {
|
||||
cutClasses.putClassHolder(generatedClass);
|
||||
link(generatedClass);
|
||||
}
|
||||
return cutClasses;
|
||||
}
|
||||
|
||||
public void link(MethodHolder cls) {
|
||||
Program program = cls.getProgram();
|
||||
public void link(ClassHolder cls) {
|
||||
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) {
|
||||
BasicBlock block = program.basicBlockAt(i);
|
||||
for (Instruction insn : block.getInstructions()) {
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
*/
|
||||
package org.teavm.model;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
|
|
|
@ -15,11 +15,8 @@
|
|||
*/
|
||||
package org.teavm.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.teavm.common.Mapper;
|
||||
import org.teavm.model.util.ProgramUtils;
|
||||
import org.teavm.model.util.ModelUtils;
|
||||
import org.teavm.resource.MapperClassHolderSource;
|
||||
|
||||
/**
|
||||
|
@ -48,68 +45,6 @@ public class CopyClassHolderSource implements ClassHolderSource {
|
|||
if (original == null) {
|
||||
return null;
|
||||
}
|
||||
ClassHolder copy = new ClassHolder(className);
|
||||
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;
|
||||
}
|
||||
return ModelUtils.copyClass(original);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
package org.teavm.model.util;
|
||||
|
||||
import java.util.List;
|
||||
import org.teavm.common.Graph;
|
||||
import org.teavm.common.GraphBuilder;
|
||||
import org.teavm.model.*;
|
||||
|
@ -67,9 +68,9 @@ public final class ProgramUtils {
|
|||
return graphBuilder.build();
|
||||
}
|
||||
|
||||
public static Program copy(Program program) {
|
||||
public static Program copy(ProgramReader program) {
|
||||
Program copy = new Program();
|
||||
CopyVisitor insnCopier = new CopyVisitor();
|
||||
InstructionCopyReader insnCopier = new InstructionCopyReader();
|
||||
insnCopier.programCopy = copy;
|
||||
for (int i = 0; i < program.variableCount(); ++i) {
|
||||
copy.createVariable();
|
||||
|
@ -78,16 +79,16 @@ public final class ProgramUtils {
|
|||
copy.createBasicBlock();
|
||||
}
|
||||
for (int i = 0; i < program.basicBlockCount(); ++i) {
|
||||
BasicBlock block = program.basicBlockAt(i);
|
||||
BasicBlockReader block = program.basicBlockAt(i);
|
||||
BasicBlock blockCopy = copy.basicBlockAt(i);
|
||||
for (Instruction insn : block.getInstructions()) {
|
||||
insn.acceptVisitor(insnCopier);
|
||||
for (int j = 0; j < block.instructionCount(); ++j) {
|
||||
block.readInstruction(j, insnCopier);
|
||||
blockCopy.getInstructions().add(insnCopier.copy);
|
||||
}
|
||||
for (Phi phi : block.getPhis()) {
|
||||
for (PhiReader phi : block.readPhis()) {
|
||||
Phi phiCopy = new Phi();
|
||||
phiCopy.setReceiver(copy.variableAt(phi.getReceiver().getIndex()));
|
||||
for (Incoming incoming : phi.getIncomings()) {
|
||||
for (IncomingReader incoming : phi.readIncomings()) {
|
||||
Incoming incomingCopy = new Incoming();
|
||||
incomingCopy.setSource(copy.basicBlockAt(incoming.getSource().getIndex()));
|
||||
incomingCopy.setValue(copy.variableAt(incoming.getValue().getIndex()));
|
||||
|
@ -95,7 +96,7 @@ public final class ProgramUtils {
|
|||
}
|
||||
blockCopy.getPhis().add(phiCopy);
|
||||
}
|
||||
for (TryCatchBlock tryCatch : block.getTryCatchBlocks()) {
|
||||
for (TryCatchBlockReader tryCatch : block.readTryCatchBlocks()) {
|
||||
TryCatchBlock tryCatchCopy = new TryCatchBlock();
|
||||
tryCatchCopy.setExceptionType(tryCatch.getExceptionType());
|
||||
tryCatchCopy.setExceptionVariable(copy.variableAt(tryCatch.getExceptionVariable().getIndex()));
|
||||
|
@ -106,160 +107,166 @@ public final class ProgramUtils {
|
|||
return copy;
|
||||
}
|
||||
|
||||
private static class CopyVisitor implements InstructionVisitor {
|
||||
private static class InstructionCopyReader implements InstructionReader {
|
||||
Instruction copy;
|
||||
Program programCopy;
|
||||
|
||||
@Override
|
||||
public void visit(EmptyInstruction insn) {
|
||||
copy = new EmptyInstruction();
|
||||
}
|
||||
|
||||
private Variable copyVar(Variable var) {
|
||||
private Variable copyVar(VariableReader var) {
|
||||
return programCopy.variableAt(var.getIndex());
|
||||
}
|
||||
|
||||
private BasicBlock copyBlock(BasicBlock block) {
|
||||
private BasicBlock copyBlock(BasicBlockReader block) {
|
||||
return programCopy.basicBlockAt(block.getIndex());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ClassConstantInstruction insn) {
|
||||
public void nop() {
|
||||
copy = new EmptyInstruction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void classConstant(VariableReader receiver, ValueType cst) {
|
||||
ClassConstantInstruction insnCopy = new ClassConstantInstruction();
|
||||
insnCopy.setConstant(insn.getConstant());
|
||||
insnCopy.setReceiver(copyVar(insn.getReceiver()));
|
||||
insnCopy.setConstant(cst);
|
||||
insnCopy.setReceiver(copyVar(receiver));
|
||||
copy = insnCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(NullConstantInstruction insn) {
|
||||
public void nullConstant(VariableReader receiver) {
|
||||
NullConstantInstruction insnCopy = new NullConstantInstruction();
|
||||
insnCopy.setReceiver(copyVar(insn.getReceiver()));
|
||||
insnCopy.setReceiver(copyVar(receiver));
|
||||
copy = insnCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(IntegerConstantInstruction insn) {
|
||||
public void integerConstant(VariableReader receiver, int cst) {
|
||||
IntegerConstantInstruction insnCopy = new IntegerConstantInstruction();
|
||||
insnCopy.setConstant(insn.getConstant());
|
||||
insnCopy.setReceiver(copyVar(insn.getReceiver()));
|
||||
insnCopy.setConstant(cst);
|
||||
insnCopy.setReceiver(copyVar(receiver));
|
||||
copy = insnCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(LongConstantInstruction insn) {
|
||||
public void longConstant(VariableReader receiver, long cst) {
|
||||
LongConstantInstruction insnCopy = new LongConstantInstruction();
|
||||
insnCopy.setConstant(insn.getConstant());
|
||||
insnCopy.setReceiver(copyVar(insn.getReceiver()));
|
||||
insnCopy.setConstant(cst);
|
||||
insnCopy.setReceiver(copyVar(receiver));
|
||||
copy = insnCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(FloatConstantInstruction insn) {
|
||||
public void floatConstant(VariableReader receiver, float cst) {
|
||||
FloatConstantInstruction insnCopy = new FloatConstantInstruction();
|
||||
insnCopy.setConstant(insn.getConstant());
|
||||
insnCopy.setReceiver(copyVar(insn.getReceiver()));
|
||||
insnCopy.setConstant(cst);
|
||||
insnCopy.setReceiver(copyVar(receiver));
|
||||
copy = insnCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(DoubleConstantInstruction insn) {
|
||||
public void doubleConstant(VariableReader receiver, double cst) {
|
||||
DoubleConstantInstruction insnCopy = new DoubleConstantInstruction();
|
||||
insnCopy.setConstant(insn.getConstant());
|
||||
insnCopy.setReceiver(copyVar(insn.getReceiver()));
|
||||
insnCopy.setConstant(cst);
|
||||
insnCopy.setReceiver(copyVar(receiver));
|
||||
copy = insnCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(StringConstantInstruction insn) {
|
||||
public void stringConstant(VariableReader receiver, String cst) {
|
||||
StringConstantInstruction insnCopy = new StringConstantInstruction();
|
||||
insnCopy.setConstant(insn.getConstant());
|
||||
insnCopy.setReceiver(copyVar(insn.getReceiver()));
|
||||
insnCopy.setConstant(cst);
|
||||
insnCopy.setReceiver(copyVar(receiver));
|
||||
copy = insnCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(BinaryInstruction insn) {
|
||||
BinaryInstruction insnCopy = new BinaryInstruction(insn.getOperation(), insn.getOperandType());
|
||||
insnCopy.setFirstOperand(copyVar(insn.getFirstOperand()));
|
||||
insnCopy.setSecondOperand(copyVar(insn.getSecondOperand()));
|
||||
insnCopy.setReceiver(copyVar(insn.getReceiver()));
|
||||
public void binary(BinaryOperation op, VariableReader receiver, VariableReader first, VariableReader second,
|
||||
NumericOperandType type) {
|
||||
BinaryInstruction insnCopy = new BinaryInstruction(op, type);
|
||||
insnCopy.setFirstOperand(copyVar(first));
|
||||
insnCopy.setSecondOperand(copyVar(second));
|
||||
insnCopy.setReceiver(copyVar(receiver));
|
||||
copy = insnCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(NegateInstruction insn) {
|
||||
NegateInstruction insnCopy = new NegateInstruction(insn.getOperandType());
|
||||
insnCopy.setOperand(copyVar(insn.getOperand()));
|
||||
insnCopy.setReceiver(copyVar(insn.getReceiver()));
|
||||
public void negate(VariableReader receiver, VariableReader operand, NumericOperandType type) {
|
||||
NegateInstruction insnCopy = new NegateInstruction(type);
|
||||
insnCopy.setOperand(copyVar(operand));
|
||||
insnCopy.setReceiver(copyVar(receiver));
|
||||
copy = insnCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(AssignInstruction insn) {
|
||||
public void assign(VariableReader receiver, VariableReader assignee) {
|
||||
AssignInstruction insnCopy = new AssignInstruction();
|
||||
insnCopy.setAssignee(copyVar(insn.getAssignee()));
|
||||
insnCopy.setReceiver(copyVar(insn.getReceiver()));
|
||||
insnCopy.setAssignee(copyVar(assignee));
|
||||
insnCopy.setReceiver(copyVar(receiver));
|
||||
copy = insnCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(CastInstruction insn) {
|
||||
public void cast(VariableReader receiver, VariableReader value, ValueType targetType) {
|
||||
CastInstruction insnCopy = new CastInstruction();
|
||||
insnCopy.setValue(copyVar(insn.getValue()));
|
||||
insnCopy.setReceiver(copyVar(insn.getReceiver()));
|
||||
insnCopy.setTargetType(insn.getTargetType());
|
||||
insnCopy.setValue(copyVar(value));
|
||||
insnCopy.setReceiver(copyVar(receiver));
|
||||
insnCopy.setTargetType(targetType);
|
||||
copy = insnCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(CastNumberInstruction insn) {
|
||||
CastNumberInstruction insnCopy = new CastNumberInstruction(insn.getSourceType(), insn.getTargetType());
|
||||
insnCopy.setValue(copyVar(insn.getValue()));
|
||||
insnCopy.setReceiver(copyVar(insn.getReceiver()));
|
||||
public void cast(VariableReader receiver, VariableReader value, NumericOperandType sourceType,
|
||||
NumericOperandType targetType) {
|
||||
CastNumberInstruction insnCopy = new CastNumberInstruction(sourceType, targetType);
|
||||
insnCopy.setValue(copyVar(value));
|
||||
insnCopy.setReceiver(copyVar(receiver));
|
||||
copy = insnCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(CastIntegerInstruction insn) {
|
||||
CastIntegerInstruction insnCopy = new CastIntegerInstruction(insn.getTargetType(), insn.getDirection());
|
||||
insnCopy.setValue(copyVar(insn.getValue()));
|
||||
insnCopy.setReceiver(copyVar(insn.getReceiver()));
|
||||
public void cast(VariableReader receiver, VariableReader value, IntegerSubtype type,
|
||||
CastIntegerDirection dir) {
|
||||
CastIntegerInstruction insnCopy = new CastIntegerInstruction(type, dir);
|
||||
insnCopy.setValue(copyVar(value));
|
||||
insnCopy.setReceiver(copyVar(receiver));
|
||||
copy = insnCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(BranchingInstruction insn) {
|
||||
BranchingInstruction insnCopy = new BranchingInstruction(insn.getCondition());
|
||||
insnCopy.setOperand(copyVar(insn.getOperand()));
|
||||
insnCopy.setConsequent(copyBlock(insn.getConsequent()));
|
||||
insnCopy.setAlternative(copyBlock(insn.getAlternative()));
|
||||
public void jumpIf(BranchingCondition cond, VariableReader operand, BasicBlockReader consequent,
|
||||
BasicBlockReader alternative) {
|
||||
BranchingInstruction insnCopy = new BranchingInstruction(cond);
|
||||
insnCopy.setOperand(copyVar(operand));
|
||||
insnCopy.setConsequent(copyBlock(consequent));
|
||||
insnCopy.setAlternative(copyBlock(alternative));
|
||||
copy = insnCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(BinaryBranchingInstruction insn) {
|
||||
BinaryBranchingInstruction insnCopy = new BinaryBranchingInstruction(insn.getCondition());
|
||||
insnCopy.setFirstOperand(copyVar(insn.getFirstOperand()));
|
||||
insnCopy.setSecondOperand(copyVar(insn.getSecondOperand()));
|
||||
insnCopy.setConsequent(copyBlock(insn.getConsequent()));
|
||||
insnCopy.setAlternative(copyBlock(insn.getAlternative()));
|
||||
public void jumpIf(BinaryBranchingCondition cond, VariableReader first, VariableReader second,
|
||||
BasicBlockReader consequent, BasicBlockReader alternative) {
|
||||
BinaryBranchingInstruction insnCopy = new BinaryBranchingInstruction(cond);
|
||||
insnCopy.setFirstOperand(copyVar(first));
|
||||
insnCopy.setSecondOperand(copyVar(second));
|
||||
insnCopy.setConsequent(copyBlock(consequent));
|
||||
insnCopy.setAlternative(copyBlock(alternative));
|
||||
copy = insnCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(JumpInstruction insn) {
|
||||
public void jump(BasicBlockReader target) {
|
||||
JumpInstruction insnCopy = new JumpInstruction();
|
||||
insnCopy.setTarget(copyBlock(insn.getTarget()));
|
||||
insnCopy.setTarget(copyBlock(target));
|
||||
copy = insnCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(SwitchInstruction insn) {
|
||||
public void choose(VariableReader condition, List<? extends SwitchTableEntryReader> table,
|
||||
BasicBlockReader defaultTarget) {
|
||||
SwitchInstruction insnCopy = new SwitchInstruction();
|
||||
insnCopy.setCondition(copyVar(insn.getCondition()));
|
||||
insnCopy.setDefaultTarget(copyBlock(insn.getDefaultTarget()));
|
||||
for (SwitchTableEntry entry : insn.getEntries()) {
|
||||
insnCopy.setCondition(copyVar(condition));
|
||||
insnCopy.setDefaultTarget(copyBlock(defaultTarget));
|
||||
for (SwitchTableEntryReader entry : table) {
|
||||
SwitchTableEntry entryCopy = new SwitchTableEntry();
|
||||
entryCopy.setCondition(entry.getCondition());
|
||||
entryCopy.setTarget(copyBlock(entry.getTarget()));
|
||||
|
@ -269,143 +276,147 @@ public final class ProgramUtils {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void visit(ExitInstruction insn) {
|
||||
public void exit(VariableReader valueToReturn) {
|
||||
ExitInstruction insnCopy = new ExitInstruction();
|
||||
insnCopy.setValueToReturn(insn.getValueToReturn() != null ? copyVar(insn.getValueToReturn()) : null);
|
||||
insnCopy.setValueToReturn(valueToReturn != null ? copyVar(valueToReturn) : null);
|
||||
copy = insnCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(RaiseInstruction insn) {
|
||||
public void raise(VariableReader exception) {
|
||||
RaiseInstruction insnCopy = new RaiseInstruction();
|
||||
insnCopy.setException(copyVar(insn.getException()));
|
||||
insnCopy.setException(copyVar(exception));
|
||||
copy = insnCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ConstructArrayInstruction insn) {
|
||||
public void createArray(VariableReader receiver, ValueType itemType, VariableReader size) {
|
||||
ConstructArrayInstruction insnCopy = new ConstructArrayInstruction();
|
||||
insnCopy.setItemType(insn.getItemType());
|
||||
insnCopy.setSize(copyVar(insn.getSize()));
|
||||
insnCopy.setReceiver(copyVar(insn.getReceiver()));
|
||||
insnCopy.setItemType(itemType);
|
||||
insnCopy.setSize(copyVar(size));
|
||||
insnCopy.setReceiver(copyVar(receiver));
|
||||
copy = insnCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ConstructInstruction insn) {
|
||||
ConstructInstruction insnCopy = new ConstructInstruction();
|
||||
insnCopy.setType(insn.getType());
|
||||
insnCopy.setReceiver(copyVar(insn.getReceiver()));
|
||||
copy = insnCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ConstructMultiArrayInstruction insn) {
|
||||
public void createArray(VariableReader receiver, ValueType itemType,
|
||||
List<? extends VariableReader> dimensions) {
|
||||
ConstructMultiArrayInstruction insnCopy = new ConstructMultiArrayInstruction();
|
||||
insnCopy.setItemType(insn.getItemType());
|
||||
insnCopy.setReceiver(copyVar(insn.getReceiver()));
|
||||
for (Variable dim : insn.getDimensions()) {
|
||||
insnCopy.setItemType(itemType);
|
||||
insnCopy.setReceiver(copyVar(receiver));
|
||||
for (VariableReader dim : dimensions) {
|
||||
insnCopy.getDimensions().add(copyVar(dim));
|
||||
}
|
||||
copy = insnCopy;
|
||||
}
|
||||
|
||||
@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();
|
||||
insnCopy.setField(insn.getField());
|
||||
insnCopy.setFieldType(insn.getFieldType());
|
||||
insnCopy.setInstance(insn.getInstance() != null ? copyVar(insn.getInstance()) : null);
|
||||
insnCopy.setReceiver(copyVar(insn.getReceiver()));
|
||||
insnCopy.setField(field);
|
||||
insnCopy.setFieldType(fieldType);
|
||||
insnCopy.setInstance(instance != null ? copyVar(instance) : null);
|
||||
insnCopy.setReceiver(copyVar(receiver));
|
||||
copy = insnCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(PutFieldInstruction insn) {
|
||||
public void putField(VariableReader instance, FieldReference field, VariableReader value) {
|
||||
PutFieldInstruction insnCopy = new PutFieldInstruction();
|
||||
insnCopy.setField(insn.getField());
|
||||
insnCopy.setInstance(insn.getInstance() != null ? copyVar(insn.getInstance()) : null);
|
||||
insnCopy.setValue(copyVar(insn.getValue()));
|
||||
insnCopy.setField(field);
|
||||
insnCopy.setInstance(instance != null ? copyVar(instance) : null);
|
||||
insnCopy.setValue(copyVar(value));
|
||||
copy = insnCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ArrayLengthInstruction insn) {
|
||||
public void arrayLength(VariableReader receiver, VariableReader array) {
|
||||
ArrayLengthInstruction insnCopy = new ArrayLengthInstruction();
|
||||
insnCopy.setArray(copyVar(insn.getArray()));
|
||||
insnCopy.setReceiver(copyVar(insn.getReceiver()));
|
||||
insnCopy.setArray(copyVar(array));
|
||||
insnCopy.setReceiver(copyVar(receiver));
|
||||
copy = insnCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(CloneArrayInstruction insn) {
|
||||
public void cloneArray(VariableReader receiver, VariableReader array) {
|
||||
CloneArrayInstruction insnCopy = new CloneArrayInstruction();
|
||||
insnCopy.setArray(copyVar(insn.getArray()));
|
||||
insnCopy.setReceiver(copyVar(insn.getReceiver()));
|
||||
insnCopy.setArray(copyVar(array));
|
||||
insnCopy.setReceiver(copyVar(receiver));
|
||||
copy = insnCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UnwrapArrayInstruction insn) {
|
||||
UnwrapArrayInstruction insnCopy = new UnwrapArrayInstruction(insn.getElementType());
|
||||
insnCopy.setArray(copyVar(insn.getArray()));
|
||||
insnCopy.setReceiver(copyVar(insn.getReceiver()));
|
||||
public void unwrapArray(VariableReader receiver, VariableReader array, ArrayElementType elementType) {
|
||||
UnwrapArrayInstruction insnCopy = new UnwrapArrayInstruction(elementType);
|
||||
insnCopy.setArray(copyVar(array));
|
||||
insnCopy.setReceiver(copyVar(receiver));
|
||||
copy = insnCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(GetElementInstruction insn) {
|
||||
public void getElement(VariableReader receiver, VariableReader array, VariableReader index) {
|
||||
GetElementInstruction insnCopy = new GetElementInstruction();
|
||||
insnCopy.setArray(copyVar(insn.getArray()));
|
||||
insnCopy.setReceiver(copyVar(insn.getReceiver()));
|
||||
insnCopy.setIndex(copyVar(insn.getIndex()));
|
||||
insnCopy.setArray(copyVar(array));
|
||||
insnCopy.setReceiver(copyVar(receiver));
|
||||
insnCopy.setIndex(copyVar(index));
|
||||
copy = insnCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(PutElementInstruction insn) {
|
||||
public void putElement(VariableReader array, VariableReader index, VariableReader value) {
|
||||
PutElementInstruction insnCopy = new PutElementInstruction();
|
||||
insnCopy.setArray(copyVar(insn.getArray()));
|
||||
insnCopy.setValue(copyVar(insn.getValue()));
|
||||
insnCopy.setIndex(copyVar(insn.getIndex()));
|
||||
insnCopy.setArray(copyVar(array));
|
||||
insnCopy.setValue(copyVar(value));
|
||||
insnCopy.setIndex(copyVar(index));
|
||||
copy = insnCopy;
|
||||
}
|
||||
|
||||
@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();
|
||||
insnCopy.setMethod(insn.getMethod());
|
||||
insnCopy.setType(insn.getType());
|
||||
insnCopy.setInstance(insn.getInstance() != null ? copyVar(insn.getInstance()) : null);
|
||||
insnCopy.setReceiver(insn.getReceiver() != null ? copyVar(insn.getReceiver()) : null);
|
||||
for (Variable arg : insn.getArguments()) {
|
||||
insnCopy.setMethod(method);
|
||||
insnCopy.setType(type);
|
||||
insnCopy.setInstance(instance != null ? copyVar(instance) : null);
|
||||
insnCopy.setReceiver(receiver != null ? copyVar(receiver) : null);
|
||||
for (VariableReader arg : arguments) {
|
||||
insnCopy.getArguments().add(copyVar(arg));
|
||||
}
|
||||
copy = insnCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(IsInstanceInstruction insn) {
|
||||
public void isInstance(VariableReader receiver, VariableReader value, ValueType type) {
|
||||
IsInstanceInstruction insnCopy = new IsInstanceInstruction();
|
||||
insnCopy.setValue(copyVar(insn.getValue()));
|
||||
insnCopy.setReceiver(copyVar(insn.getReceiver()));
|
||||
insnCopy.setType(insn.getType());
|
||||
insnCopy.setValue(copyVar(value));
|
||||
insnCopy.setReceiver(copyVar(receiver));
|
||||
insnCopy.setType(type);
|
||||
copy = insnCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(InitClassInstruction insn) {
|
||||
public void initClass(String className) {
|
||||
InitClassInstruction insnCopy = new InitClassInstruction();
|
||||
insnCopy.setClassName(insn.getClassName());
|
||||
insnCopy.setClassName(className);
|
||||
copy = insnCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(NullCheckInstruction insn) {
|
||||
public void nullCheck(VariableReader receiver, VariableReader value) {
|
||||
NullCheckInstruction insnCopy = new NullCheckInstruction();
|
||||
insnCopy.setReceiver(copyVar(insn.getReceiver()));
|
||||
insnCopy.setValue(copyVar(insn.getValue()));
|
||||
insnCopy.setReceiver(copyVar(receiver));
|
||||
insnCopy.setValue(copyVar(value));
|
||||
copy = insnCopy;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ package org.teavm.vm;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import org.teavm.common.ConcurrentCachedMapper;
|
||||
import org.teavm.common.Mapper;
|
||||
import org.teavm.model.ClassHolder;
|
||||
|
|
|
@ -93,7 +93,6 @@ public class TeaVM implements TeaVMHost {
|
|||
classSource.addTransformer(transformer);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void add(MethodReference methodRef, Generator generator) {
|
||||
methodGenerators.put(methodRef, generator);
|
||||
|
|
|
@ -67,21 +67,21 @@ public class EntryPointGenerator extends AbstractRendererListener implements Dep
|
|||
}
|
||||
|
||||
@Override
|
||||
public void started(DependencyChecker dependencyChecker) {
|
||||
public void started(DependencyAgent agent) {
|
||||
for (String className : classesToLoad) {
|
||||
dependencyChecker.initClass(className, DependencyStack.ROOT);
|
||||
agent.initClass(className, DependencyStack.ROOT);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void classAchieved(DependencyChecker dependencyChecker, String className) {
|
||||
public void classAchieved(DependencyAgent agent, String className) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void methodAchieved(DependencyChecker dependencyChecker, MethodDependency method) {
|
||||
public void methodAchieved(DependencyAgent agent, MethodDependency method) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fieldAchieved(DependencyChecker dependencyChecker, FieldDependency field) {
|
||||
public void fieldAchieved(DependencyAgent agent, FieldDependency field) {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,8 +27,8 @@ public class JavaScriptBodyDependency implements DependencyListener {
|
|||
private DependencyNode allClassesNode;
|
||||
|
||||
@Override
|
||||
public void started(DependencyChecker dependencyChecker) {
|
||||
allClassesNode = dependencyChecker.createNode();
|
||||
public void started(DependencyAgent agent) {
|
||||
allClassesNode = agent.createNode();
|
||||
allClassesNode.setTag("JavaScriptBody:global");
|
||||
}
|
||||
|
||||
|
@ -43,8 +43,8 @@ public class JavaScriptBodyDependency implements DependencyListener {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void classAchieved(DependencyChecker dependencyChecker, String className) {
|
||||
ClassReader cls = dependencyChecker.getClassSource().get(className);
|
||||
public void classAchieved(DependencyAgent agent, String className) {
|
||||
ClassReader cls = agent.getClassSource().get(className);
|
||||
if (cls != null && !cls.hasModifier(ElementModifier.ABSTRACT) &&
|
||||
!cls.hasModifier(ElementModifier.INTERFACE)) {
|
||||
allClassesNode.propagate(className);
|
||||
|
@ -52,13 +52,13 @@ public class JavaScriptBodyDependency implements DependencyListener {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void methodAchieved(DependencyChecker dependencyChecker, MethodDependency method) {
|
||||
public void methodAchieved(DependencyAgent agent, MethodDependency method) {
|
||||
if (method.isMissing()) {
|
||||
return;
|
||||
}
|
||||
AnnotationReader annot = method.getMethod().getAnnotations().get(JavaScriptBody.class.getName());
|
||||
if (annot != null) {
|
||||
includeDefaultDependencies(dependencyChecker);
|
||||
includeDefaultDependencies(agent);
|
||||
AnnotationValue javacall = annot.getValue("javacall");
|
||||
if (method.getResult() != null) {
|
||||
allClassesNode.connect(method.getResult());
|
||||
|
@ -74,26 +74,26 @@ public class JavaScriptBodyDependency implements DependencyListener {
|
|||
}
|
||||
if (javacall != null && javacall.getBoolean()) {
|
||||
String body = annot.getValue("body").getString();
|
||||
new GeneratorJsCallback(dependencyChecker, method).parse(body);
|
||||
new GeneratorJsCallback(agent, method).parse(body);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void includeDefaultDependencies(DependencyChecker dependencyChecker) {
|
||||
dependencyChecker.linkMethod(JavaScriptConvGenerator.fromJsMethod, DependencyStack.ROOT).use();
|
||||
dependencyChecker.linkMethod(JavaScriptConvGenerator.toJsMethod, DependencyStack.ROOT).use();
|
||||
dependencyChecker.linkMethod(JavaScriptConvGenerator.intValueMethod, DependencyStack.ROOT).use();
|
||||
dependencyChecker.linkMethod(JavaScriptConvGenerator.valueOfIntMethod, DependencyStack.ROOT).use();
|
||||
dependencyChecker.linkMethod(JavaScriptConvGenerator.booleanValueMethod, DependencyStack.ROOT).use();
|
||||
dependencyChecker.linkMethod(JavaScriptConvGenerator.valueOfBooleanMethod, DependencyStack.ROOT).use();
|
||||
dependencyChecker.linkMethod(JavaScriptConvGenerator.doubleValueMethod, DependencyStack.ROOT).use();
|
||||
dependencyChecker.linkMethod(JavaScriptConvGenerator.valueOfDoubleMethod, DependencyStack.ROOT).use();
|
||||
dependencyChecker.linkMethod(JavaScriptConvGenerator.charValueMethod, DependencyStack.ROOT).use();
|
||||
dependencyChecker.linkMethod(JavaScriptConvGenerator.valueOfCharMethod, DependencyStack.ROOT).use();
|
||||
private void includeDefaultDependencies(DependencyAgent agent) {
|
||||
agent.linkMethod(JavaScriptConvGenerator.fromJsMethod, DependencyStack.ROOT).use();
|
||||
agent.linkMethod(JavaScriptConvGenerator.toJsMethod, DependencyStack.ROOT).use();
|
||||
agent.linkMethod(JavaScriptConvGenerator.intValueMethod, DependencyStack.ROOT).use();
|
||||
agent.linkMethod(JavaScriptConvGenerator.valueOfIntMethod, DependencyStack.ROOT).use();
|
||||
agent.linkMethod(JavaScriptConvGenerator.booleanValueMethod, DependencyStack.ROOT).use();
|
||||
agent.linkMethod(JavaScriptConvGenerator.valueOfBooleanMethod, DependencyStack.ROOT).use();
|
||||
agent.linkMethod(JavaScriptConvGenerator.doubleValueMethod, DependencyStack.ROOT).use();
|
||||
agent.linkMethod(JavaScriptConvGenerator.valueOfDoubleMethod, DependencyStack.ROOT).use();
|
||||
agent.linkMethod(JavaScriptConvGenerator.charValueMethod, DependencyStack.ROOT).use();
|
||||
agent.linkMethod(JavaScriptConvGenerator.valueOfCharMethod, DependencyStack.ROOT).use();
|
||||
}
|
||||
|
||||
@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) {
|
||||
|
@ -124,17 +124,17 @@ public class JavaScriptBodyDependency implements DependencyListener {
|
|||
}
|
||||
|
||||
private class GeneratorJsCallback extends JsCallback {
|
||||
private DependencyChecker dependencyChecker;
|
||||
private DependencyAgent agent;
|
||||
private MethodDependency caller;
|
||||
public GeneratorJsCallback(DependencyChecker dependencyChecker, MethodDependency caller) {
|
||||
this.dependencyChecker = dependencyChecker;
|
||||
public GeneratorJsCallback(DependencyAgent agent, MethodDependency caller) {
|
||||
this.agent = agent;
|
||||
this.caller = caller;
|
||||
}
|
||||
@Override protected CharSequence callMethod(String ident, String fqn, String method, String params) {
|
||||
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);
|
||||
MethodDependency methodDep = dependencyChecker.linkMethod(ref, caller.getStack());
|
||||
MethodDependency methodDep = agent.linkMethod(ref, caller.getStack());
|
||||
if (!methodDep.isMissing()) {
|
||||
if (reader.hasModifier(ElementModifier.STATIC) || reader.hasModifier(ElementModifier.FINAL)) {
|
||||
methodDep.use();
|
||||
|
@ -142,7 +142,7 @@ public class JavaScriptBodyDependency implements DependencyListener {
|
|||
allClassesNode.connect(methodDep.getVariable(i));
|
||||
}
|
||||
} else {
|
||||
allClassesNode.addConsumer(new VirtualCallbackConsumer(dependencyChecker, reader, caller));
|
||||
allClassesNode.addConsumer(new VirtualCallbackConsumer(agent, reader, caller));
|
||||
}
|
||||
}
|
||||
return "";
|
||||
|
@ -150,30 +150,30 @@ public class JavaScriptBodyDependency implements DependencyListener {
|
|||
}
|
||||
|
||||
private class VirtualCallbackConsumer implements DependencyConsumer {
|
||||
private DependencyChecker dependencyChecker;
|
||||
private DependencyAgent agent;
|
||||
private MethodReader superMethod;
|
||||
private ClassReader superClass;
|
||||
private MethodDependency caller;
|
||||
public VirtualCallbackConsumer(DependencyChecker dependencyChecker, MethodReader superMethod,
|
||||
public VirtualCallbackConsumer(DependencyAgent agent, MethodReader superMethod,
|
||||
MethodDependency caller) {
|
||||
this.dependencyChecker = dependencyChecker;
|
||||
this.agent = agent;
|
||||
this.superMethod = superMethod;
|
||||
this.caller = caller;
|
||||
this.superClass = dependencyChecker.getClassSource().get(superMethod.getOwnerName());
|
||||
this.superClass = agent.getClassSource().get(superMethod.getOwnerName());
|
||||
}
|
||||
@Override public void consume(String type) {
|
||||
if (!isAssignableFrom(superClass, type)) {
|
||||
return;
|
||||
}
|
||||
MethodReference methodRef = new MethodReference(type, superMethod.getDescriptor());
|
||||
MethodDependency method = dependencyChecker.linkMethod(methodRef, caller.getStack());
|
||||
MethodDependency method = agent.linkMethod(methodRef, caller.getStack());
|
||||
method.use();
|
||||
for (int i = 0; i < method.getParameterCount(); ++i) {
|
||||
allClassesNode.connect(method.getVariable(i));
|
||||
}
|
||||
}
|
||||
private boolean isAssignableFrom(ClassReader supertype, String subtypeName) {
|
||||
ClassReaderSource classSource = dependencyChecker.getClassSource();
|
||||
ClassReaderSource classSource = agent.getClassSource();
|
||||
if (supertype.getName().equals(subtypeName)) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -31,13 +31,13 @@ class TestExceptionDependency implements DependencyListener {
|
|||
private DependencyNode allClasses;
|
||||
|
||||
@Override
|
||||
public void started(DependencyChecker dependencyChecker) {
|
||||
allClasses = dependencyChecker.createNode();
|
||||
public void started(DependencyAgent agent) {
|
||||
allClasses = agent.createNode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void classAchieved(DependencyChecker dependencyChecker, String className) {
|
||||
if (isException(dependencyChecker.getClassSource(), className)) {
|
||||
public void classAchieved(DependencyAgent agent, String className) {
|
||||
if (isException(agent.getClassSource(), className)) {
|
||||
allClasses.propagate(className);
|
||||
}
|
||||
}
|
||||
|
@ -57,13 +57,13 @@ class TestExceptionDependency implements DependencyListener {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void methodAchieved(DependencyChecker dependencyChecker, MethodDependency method) {
|
||||
public void methodAchieved(DependencyAgent agent, MethodDependency method) {
|
||||
if (method.getReference().equals(getMessageRef)) {
|
||||
allClasses.connect(method.getVariable(0));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fieldAchieved(DependencyChecker dependencyChecker, FieldDependency field) {
|
||||
public void fieldAchieved(DependencyAgent agent, FieldDependency field) {
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user