mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2025-01-07 07:24:11 -08:00
Refactor dependency checker
This commit is contained in:
parent
e60be5d518
commit
4f941e0a0a
|
@ -32,7 +32,7 @@ public class ClassLookupDependencySupport implements DependencyListener {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void classAchieved(DependencyAgent agent, String className) {
|
public void classAchieved(DependencyAgent agent, String className) {
|
||||||
allClasses.propagate(className);
|
allClasses.propagate(agent.getType(className));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -41,8 +41,8 @@ public class ClassLookupDependencySupport implements DependencyListener {
|
||||||
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(DependencyAgentType type) {
|
||||||
ClassReader cls = agent.getClassSource().get(type);
|
ClassReader cls = agent.getClassSource().get(type.getName());
|
||||||
if (cls == null) {
|
if (cls == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ public class EnumDependencySupport implements DependencyListener {
|
||||||
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;
|
||||||
}
|
}
|
||||||
allEnums.propagate(className);
|
allEnums.propagate(agent.getType(className));
|
||||||
if (enumConstantsStack != null) {
|
if (enumConstantsStack != null) {
|
||||||
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()))));
|
||||||
|
@ -55,7 +55,7 @@ public class EnumDependencySupport implements DependencyListener {
|
||||||
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(agent.getType("[java.lang.Enum"));
|
||||||
enumConstantsStack = method.getStack();
|
enumConstantsStack = method.getStack();
|
||||||
for (String cls : agent.getAchievableClasses()) {
|
for (String cls : agent.getAchievableClasses()) {
|
||||||
classAchieved(agent, cls);
|
classAchieved(agent, cls);
|
||||||
|
|
|
@ -42,7 +42,7 @@ public class NewInstanceDependencySupport implements DependencyListener {
|
||||||
}
|
}
|
||||||
MethodReader method = cls.getMethod(new MethodDescriptor("<init>", ValueType.VOID));
|
MethodReader method = cls.getMethod(new MethodDescriptor("<init>", ValueType.VOID));
|
||||||
if (method != null) {
|
if (method != null) {
|
||||||
allClassesNode.propagate(className);
|
allClassesNode.propagate(agent.getType(className));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,8 +53,8 @@ public class NewInstanceDependencySupport implements DependencyListener {
|
||||||
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(DependencyAgentType type) {
|
||||||
attachConstructor(agent, type);
|
attachConstructor(agent, type.getName());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,7 +89,7 @@ public class ServiceLoaderSupport implements Generator, DependencyListener {
|
||||||
while (resources.hasMoreElements()) {
|
while (resources.hasMoreElements()) {
|
||||||
URL resource = resources.nextElement();
|
URL resource = resources.nextElement();
|
||||||
try (InputStream stream = resource.openStream()) {
|
try (InputStream stream = resource.openStream()) {
|
||||||
parseServiceFile(className, stream);
|
parseServiceFile(agent, className, stream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
@ -97,7 +97,7 @@ public class ServiceLoaderSupport implements Generator, DependencyListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void parseServiceFile(String service, InputStream input) throws IOException {
|
private void parseServiceFile(DependencyAgent agent, String service, InputStream input) throws IOException {
|
||||||
BufferedReader reader = new BufferedReader(new InputStreamReader(input, "UTF-8"));
|
BufferedReader reader = new BufferedReader(new InputStreamReader(input, "UTF-8"));
|
||||||
while (true) {
|
while (true) {
|
||||||
String line = reader.readLine();
|
String line = reader.readLine();
|
||||||
|
@ -114,7 +114,7 @@ public class ServiceLoaderSupport implements Generator, DependencyListener {
|
||||||
serviceMap.put(service, implementors);
|
serviceMap.put(service, implementors);
|
||||||
}
|
}
|
||||||
implementors.add(line);
|
implementors.add(line);
|
||||||
allClassesNode.propagate(line);
|
allClassesNode.propagate(agent.getType(line));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,12 +122,12 @@ public class ServiceLoaderSupport implements Generator, DependencyListener {
|
||||||
public void methodAchieved(final DependencyAgent agent, 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(agent.getType("[java.lang.Object"));
|
||||||
stack = method.getStack();
|
stack = method.getStack();
|
||||||
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(DependencyAgentType type) {
|
||||||
initConstructor(agent, type);
|
initConstructor(agent, type.getName());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@ public class CharacterNativeGenerator implements Generator, DependencyPlugin {
|
||||||
switch (method.getReference().getName()) {
|
switch (method.getReference().getName()) {
|
||||||
case "obtainDigitMapping":
|
case "obtainDigitMapping":
|
||||||
case "obtainClasses":
|
case "obtainClasses":
|
||||||
method.getResult().propagate("java.lang.String");
|
method.getResult().propagate(agent.getType("java.lang.String"));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -202,7 +202,7 @@ public class ClassNativeGenerator implements Generator, Injector, DependencyPlug
|
||||||
case "getComponentType0":
|
case "getComponentType0":
|
||||||
case "forNameImpl":
|
case "forNameImpl":
|
||||||
case "getDeclaringClass":
|
case "getDeclaringClass":
|
||||||
graph.getResult().propagate("java.lang.Class");
|
graph.getResult().propagate(agent.getType("java.lang.Class"));
|
||||||
break;
|
break;
|
||||||
case "newInstance":
|
case "newInstance":
|
||||||
agent.linkMethod(new MethodReference(InstantiationException.class.getName(), "<init>",
|
agent.linkMethod(new MethodReference(InstantiationException.class.getName(), "<init>",
|
||||||
|
|
|
@ -86,7 +86,7 @@ public class ObjectNativeGenerator implements Generator, Injector, DependencyPlu
|
||||||
private void achieveGetClass(DependencyAgent agent, MethodDependency method) {
|
private void achieveGetClass(DependencyAgent agent, MethodDependency method) {
|
||||||
MethodReference initMethod = new MethodReference(Class.class, "createNew", Class.class);
|
MethodReference initMethod = new MethodReference(Class.class, "createNew", Class.class);
|
||||||
agent.linkMethod(initMethod, method.getStack()).use();
|
agent.linkMethod(initMethod, method.getStack()).use();
|
||||||
method.getResult().propagate("java.lang.Class");
|
method.getResult().propagate(agent.getType("java.lang.Class"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void generateHashCode(GeneratorContext context, SourceWriter writer) throws IOException {
|
private void generateHashCode(GeneratorContext context, SourceWriter writer) throws IOException {
|
||||||
|
|
|
@ -44,7 +44,7 @@ public class ArrayNativeGenerator implements Generator, DependencyPlugin {
|
||||||
achieveGetLength(agent, method);
|
achieveGetLength(agent, method);
|
||||||
break;
|
break;
|
||||||
case "newInstanceImpl":
|
case "newInstanceImpl":
|
||||||
method.getResult().propagate("[java.lang.Object");
|
method.getResult().propagate(agent.getType("[java.lang.Object"));
|
||||||
break;
|
break;
|
||||||
case "getImpl":
|
case "getImpl":
|
||||||
achieveGet(agent, method);
|
achieveGet(agent, method);
|
||||||
|
@ -80,8 +80,8 @@ public class ArrayNativeGenerator implements Generator, DependencyPlugin {
|
||||||
|
|
||||||
private void achieveGetLength(final DependencyAgent agent, final MethodDependency method) {
|
private void achieveGetLength(final DependencyAgent agent, final MethodDependency method) {
|
||||||
method.getVariable(1).addConsumer(new DependencyConsumer() {
|
method.getVariable(1).addConsumer(new DependencyConsumer() {
|
||||||
@Override public void consume(String type) {
|
@Override public void consume(DependencyAgentType type) {
|
||||||
if (!type.startsWith("[")) {
|
if (!type.getName().startsWith("[")) {
|
||||||
MethodReference cons = new MethodReference(IllegalArgumentException.class, "<init>", void.class);
|
MethodReference cons = new MethodReference(IllegalArgumentException.class, "<init>", void.class);
|
||||||
agent.linkMethod(cons, method.getStack()).use();
|
agent.linkMethod(cons, method.getStack()).use();
|
||||||
}
|
}
|
||||||
|
@ -128,16 +128,16 @@ public class ArrayNativeGenerator implements Generator, DependencyPlugin {
|
||||||
private void achieveGet(final DependencyAgent agent, final MethodDependency method) {
|
private void achieveGet(final DependencyAgent agent, final MethodDependency method) {
|
||||||
method.getVariable(1).getArrayItem().connect(method.getResult());
|
method.getVariable(1).getArrayItem().connect(method.getResult());
|
||||||
method.getVariable(1).addConsumer(new DependencyConsumer() {
|
method.getVariable(1).addConsumer(new DependencyConsumer() {
|
||||||
@Override public void consume(String type) {
|
@Override public void consume(DependencyAgentType type) {
|
||||||
if (type.startsWith("[")) {
|
if (type.getName().startsWith("[")) {
|
||||||
type = type.substring(1);
|
String typeName = type.getName().substring(1);
|
||||||
for (int i = 0; i < primitiveTypes.length; ++i) {
|
for (int i = 0; i < primitiveTypes.length; ++i) {
|
||||||
if (primitiveTypes[i].toString().equals(type)) {
|
if (primitiveTypes[i].toString().equals(typeName)) {
|
||||||
String wrapper = "java.lang." + primitiveWrappers[i];
|
String wrapper = "java.lang." + primitiveWrappers[i];
|
||||||
MethodReference methodRef = new MethodReference(wrapper, "valueOf",
|
MethodReference methodRef = new MethodReference(wrapper, "valueOf",
|
||||||
primitiveTypes[i], ValueType.object(wrapper));
|
primitiveTypes[i], ValueType.object(wrapper));
|
||||||
agent.linkMethod(methodRef, method.getStack()).use();
|
agent.linkMethod(methodRef, method.getStack()).use();
|
||||||
method.getResult().propagate("java.lang." + primitiveWrappers[i]);
|
method.getResult().propagate(agent.getType("java.lang." + primitiveWrappers[i]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,7 +75,7 @@ public class DateNativeGenerator implements Generator, DependencyPlugin {
|
||||||
case "toString":
|
case "toString":
|
||||||
case "toLocaleFormat":
|
case "toLocaleFormat":
|
||||||
case "toGMTString":
|
case "toGMTString":
|
||||||
method.getResult().propagate("java.lang.String");
|
method.getResult().propagate(agent.getType("java.lang.String"));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,8 @@ import org.teavm.model.MethodReference;
|
||||||
public interface DependencyAgent extends DependencyInfo, ServiceRepository {
|
public interface DependencyAgent extends DependencyInfo, ServiceRepository {
|
||||||
DependencyNode createNode();
|
DependencyNode createNode();
|
||||||
|
|
||||||
|
DependencyAgentType getType(String name);
|
||||||
|
|
||||||
String generateClassName();
|
String generateClassName();
|
||||||
|
|
||||||
void submitClass(ClassHolder cls);
|
void submitClass(ClassHolder cls);
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||||
|
*/
|
||||||
|
public interface DependencyAgentType {
|
||||||
|
String getName();
|
||||||
|
|
||||||
|
DependencyAgent getDependencyAgent();
|
||||||
|
}
|
|
@ -17,8 +17,6 @@ package org.teavm.dependency;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
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.*;
|
||||||
|
@ -29,7 +27,6 @@ import org.teavm.model.util.ModelUtils;
|
||||||
* @author Alexey Andreev
|
* @author Alexey Andreev
|
||||||
*/
|
*/
|
||||||
public class DependencyChecker implements DependencyInfo, DependencyAgent {
|
public class DependencyChecker implements DependencyInfo, DependencyAgent {
|
||||||
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 int classNameSuffix;
|
private int classNameSuffix;
|
||||||
private DependencyClassSource classSource;
|
private DependencyClassSource classSource;
|
||||||
|
@ -37,18 +34,20 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
|
||||||
private FiniteExecutor executor;
|
private FiniteExecutor executor;
|
||||||
private Mapper<MethodReference, MethodReader> methodReaderCache;
|
private Mapper<MethodReference, MethodReader> methodReaderCache;
|
||||||
private Mapper<FieldReference, FieldReader> fieldReaderCache;
|
private Mapper<FieldReference, FieldReader> fieldReaderCache;
|
||||||
private ConcurrentMap<MethodReference, DependencyStack> stacks = new ConcurrentHashMap<>();
|
private Map<MethodReference, DependencyStack> stacks = new HashMap<>();
|
||||||
private ConcurrentMap<FieldReference, DependencyStack> fieldStacks = new ConcurrentHashMap<>();
|
private Map<FieldReference, DependencyStack> fieldStacks = new HashMap<>();
|
||||||
private ConcurrentMap<String, DependencyStack> classStacks = new ConcurrentHashMap<>();
|
private Map<String, DependencyStack> classStacks = new HashMap<>();
|
||||||
private ConcurrentCachedMapper<MethodReference, MethodDependency> methodCache;
|
private ConcurrentCachedMapper<MethodReference, MethodDependency> methodCache;
|
||||||
private ConcurrentCachedMapper<FieldReference, FieldDependency> fieldCache;
|
private ConcurrentCachedMapper<FieldReference, FieldDependency> fieldCache;
|
||||||
private ConcurrentMap<String, Object> achievableClasses = new ConcurrentHashMap<>();
|
private Set<String> achievableClasses = new HashSet<>();
|
||||||
private ConcurrentMap<String, Object> initializedClasses = new ConcurrentHashMap<>();
|
private Set<String> initializedClasses = new HashSet<>();
|
||||||
private List<DependencyListener> listeners = new ArrayList<>();
|
private List<DependencyListener> listeners = new ArrayList<>();
|
||||||
private ServiceRepository services;
|
private ServiceRepository services;
|
||||||
ConcurrentMap<MethodReference, DependencyStack> missingMethods = new ConcurrentHashMap<>();
|
Map<MethodReference, DependencyStack> missingMethods = new HashMap<>();
|
||||||
ConcurrentMap<String, DependencyStack> missingClasses = new ConcurrentHashMap<>();
|
Map<String, DependencyStack> missingClasses = new HashMap<>();
|
||||||
ConcurrentMap<FieldReference, DependencyStack> missingFields = new ConcurrentHashMap<>();
|
Map<FieldReference, DependencyStack> missingFields = new HashMap<>();
|
||||||
|
List<DependencyType> types = new ArrayList<>();
|
||||||
|
Map<String, DependencyType> typeMap = new HashMap<>();
|
||||||
|
|
||||||
public DependencyChecker(ClassReaderSource classSource, ClassLoader classLoader, ServiceRepository services) {
|
public DependencyChecker(ClassReaderSource classSource, ClassLoader classLoader, ServiceRepository services) {
|
||||||
this(classSource, classLoader, services, new SimpleFiniteExecutor());
|
this(classSource, classLoader, services, new SimpleFiniteExecutor());
|
||||||
|
@ -113,6 +112,17 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DependencyType getType(String name) {
|
||||||
|
DependencyType type = typeMap.get(name);
|
||||||
|
if (type == null) {
|
||||||
|
type = new DependencyType(this, name, types.size());
|
||||||
|
types.add(type);
|
||||||
|
typeMap.put(name, type);
|
||||||
|
}
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DependencyNode createNode() {
|
public DependencyNode createNode() {
|
||||||
return new DependencyNode(this);
|
return new DependencyNode(this);
|
||||||
|
@ -155,13 +165,13 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
|
||||||
MethodDependency method = linkMethod(methodRef, DependencyStack.ROOT);
|
MethodDependency method = linkMethod(methodRef, DependencyStack.ROOT);
|
||||||
method.use();
|
method.use();
|
||||||
DependencyNode[] varNodes = method.getVariables();
|
DependencyNode[] varNodes = method.getVariables();
|
||||||
varNodes[0].propagate(methodRef.getClassName());
|
varNodes[0].propagate(getType(methodRef.getClassName()));
|
||||||
for (int i = 0; i < argumentTypes.length; ++i) {
|
for (int i = 0; i < argumentTypes.length; ++i) {
|
||||||
varNodes[i + 1].propagate(argumentTypes[i]);
|
varNodes[i + 1].propagate(getType(argumentTypes[i]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void schedulePropagation(final DependencyConsumer consumer, final String type) {
|
void schedulePropagation(final DependencyConsumer consumer, final DependencyType type) {
|
||||||
executor.executeFast(new Runnable() {
|
executor.executeFast(new Runnable() {
|
||||||
@Override public void run() {
|
@Override public void run() {
|
||||||
consumer.consume(type);
|
consumer.consume(type);
|
||||||
|
@ -174,14 +184,14 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean achieveClass(String className, DependencyStack stack) {
|
boolean achieveClass(String className, DependencyStack stack) {
|
||||||
classStacks.putIfAbsent(className, stack);
|
classStacks.put(className, stack);
|
||||||
boolean result = achievableClasses.putIfAbsent(className, dummyValue) == null;
|
if (!achievableClasses.add(className)) {
|
||||||
if (result) {
|
return false;
|
||||||
for (DependencyListener listener : listeners) {
|
|
||||||
listener.classAchieved(this, className);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return result;
|
for (DependencyListener listener : listeners) {
|
||||||
|
listener.classAchieved(this, className);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -189,16 +199,16 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
|
||||||
if (methodRef == null) {
|
if (methodRef == null) {
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
}
|
}
|
||||||
stacks.putIfAbsent(methodRef, stack);
|
stacks.put(methodRef, stack);
|
||||||
return methodCache.map(methodRef);
|
return methodCache.map(methodRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initClass(String className, final DependencyStack stack) {
|
public void initClass(String className, final DependencyStack stack) {
|
||||||
classStacks.putIfAbsent(className, stack);
|
classStacks.put(className, stack);
|
||||||
MethodDescriptor clinitDesc = new MethodDescriptor("<clinit>", ValueType.VOID);
|
MethodDescriptor clinitDesc = new MethodDescriptor("<clinit>", ValueType.VOID);
|
||||||
while (className != null) {
|
while (className != null) {
|
||||||
if (initializedClasses.putIfAbsent(className, clinitDesc) != null) {
|
if (!initializedClasses.add(className)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
achieveClass(className, stack);
|
achieveClass(className, stack);
|
||||||
|
@ -221,7 +231,7 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void achieveInterfaces(String className, DependencyStack stack) {
|
private void achieveInterfaces(String className, DependencyStack stack) {
|
||||||
classStacks.putIfAbsent(className, stack);
|
classStacks.put(className, stack);
|
||||||
ClassReader cls = classSource.get(className);
|
ClassReader cls = classSource.get(className);
|
||||||
if (cls == null) {
|
if (cls == null) {
|
||||||
missingClasses.put(className, stack);
|
missingClasses.put(className, stack);
|
||||||
|
@ -306,7 +316,7 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
|
||||||
thrown.setTag(methodRef + ":THROWN");
|
thrown.setTag(methodRef + ":THROWN");
|
||||||
}
|
}
|
||||||
stack = new DependencyStack(methodRef, stack);
|
stack = new DependencyStack(methodRef, stack);
|
||||||
final MethodDependency dep = new MethodDependency(parameterNodes, paramCount, resultNode, thrown,
|
final MethodDependency dep = new MethodDependency(this, parameterNodes, paramCount, resultNode, thrown,
|
||||||
stack, method, methodRef);
|
stack, method, methodRef);
|
||||||
if (method != null) {
|
if (method != null) {
|
||||||
executor.execute(new Runnable() {
|
executor.execute(new Runnable() {
|
||||||
|
@ -316,7 +326,7 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
missingMethods.putIfAbsent(methodRef, stack);
|
missingMethods.put(methodRef, stack);
|
||||||
}
|
}
|
||||||
if (method != null) {
|
if (method != null) {
|
||||||
final DependencyStack callerStack = stack;
|
final DependencyStack callerStack = stack;
|
||||||
|
@ -347,12 +357,12 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<String> getAchievableClasses() {
|
public Collection<String> getAchievableClasses() {
|
||||||
return new HashSet<>(achievableClasses.keySet());
|
return new HashSet<>(achievableClasses);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FieldDependency linkField(FieldReference fieldRef, DependencyStack stack) {
|
public FieldDependency linkField(FieldReference fieldRef, DependencyStack stack) {
|
||||||
fieldStacks.putIfAbsent(fieldRef, stack);
|
fieldStacks.put(fieldRef, stack);
|
||||||
return fieldCache.map(fieldRef);
|
return fieldCache.map(fieldRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -364,7 +374,7 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
|
||||||
private FieldDependency createFieldNode(FieldReference fieldRef, FieldReader field, DependencyStack stack) {
|
private FieldDependency createFieldNode(FieldReference fieldRef, FieldReader field, DependencyStack stack) {
|
||||||
DependencyNode node = new DependencyNode(this);
|
DependencyNode node = new DependencyNode(this);
|
||||||
if (field == null) {
|
if (field == null) {
|
||||||
missingFields.putIfAbsent(fieldRef, stack);
|
missingFields.put(fieldRef, stack);
|
||||||
}
|
}
|
||||||
if (shouldLog) {
|
if (shouldLog) {
|
||||||
node.setTag(fieldRef.getClassName() + "#" + fieldRef.getFieldName());
|
node.setTag(fieldRef.getClassName() + "#" + fieldRef.getFieldName());
|
||||||
|
|
|
@ -20,5 +20,5 @@ package org.teavm.dependency;
|
||||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||||
*/
|
*/
|
||||||
public interface DependencyConsumer {
|
public interface DependencyConsumer {
|
||||||
void consume(String type);
|
void consume(DependencyAgentType type);
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,9 +104,10 @@ class DependencyGraphBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void consume(String type) {
|
public void consume(DependencyAgentType type) {
|
||||||
for (int i = 0; i < exceptions.length; ++i) {
|
for (int i = 0; i < exceptions.length; ++i) {
|
||||||
if (exceptions[i] == null || isAssignableFrom(checker.getClassSource(), exceptions[i], type)) {
|
if (exceptions[i] == null || isAssignableFrom(checker.getClassSource(), exceptions[i],
|
||||||
|
type.getName())) {
|
||||||
vars[i].propagate(type);
|
vars[i].propagate(type);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -140,7 +141,8 @@ class DependencyGraphBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void consume(String className) {
|
public void consume(DependencyAgentType type) {
|
||||||
|
String className = type.getName();
|
||||||
if (DependencyChecker.shouldLog) {
|
if (DependencyChecker.shouldLog) {
|
||||||
System.out.println("Virtual call of " + methodDesc + " detected on " + node.getTag() + ". " +
|
System.out.println("Virtual call of " + methodDesc + " detected on " + node.getTag() + ". " +
|
||||||
"Target class is " + className);
|
"Target class is " + className);
|
||||||
|
@ -201,8 +203,8 @@ class DependencyGraphBuilder {
|
||||||
|
|
||||||
private static class TypePropagationRunner implements Runnable {
|
private static class TypePropagationRunner implements Runnable {
|
||||||
private DependencyNode node;
|
private DependencyNode node;
|
||||||
private String type;
|
private DependencyType type;
|
||||||
public TypePropagationRunner(DependencyNode node, String type) {
|
public TypePropagationRunner(DependencyNode node, DependencyType type) {
|
||||||
this.node = node;
|
this.node = node;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
@ -222,7 +224,8 @@ class DependencyGraphBuilder {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void classConstant(VariableReader receiver, ValueType cst) {
|
public void classConstant(VariableReader receiver, ValueType cst) {
|
||||||
useRunners.add(new TypePropagationRunner(nodes[receiver.getIndex()], "java.lang.Class"));
|
useRunners.add(new TypePropagationRunner(nodes[receiver.getIndex()],
|
||||||
|
dependencyChecker.getType("java.lang.Class")));
|
||||||
while (cst instanceof ValueType.Array) {
|
while (cst instanceof ValueType.Array) {
|
||||||
cst = ((ValueType.Array)cst).getItemType();
|
cst = ((ValueType.Array)cst).getItemType();
|
||||||
}
|
}
|
||||||
|
@ -258,9 +261,10 @@ class DependencyGraphBuilder {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stringConstant(VariableReader receiver, String cst) {
|
public void stringConstant(VariableReader receiver, String cst) {
|
||||||
useRunners.add(new TypePropagationRunner(nodes[receiver.getIndex()], "java.lang.String"));
|
useRunners.add(new TypePropagationRunner(nodes[receiver.getIndex()],
|
||||||
|
dependencyChecker.getType("java.lang.String")));
|
||||||
MethodDependency method = dependencyChecker.linkMethod(new MethodReference(String.class,
|
MethodDependency method = dependencyChecker.linkMethod(new MethodReference(String.class,
|
||||||
"<init>", char.class, void.class), callerStack);
|
"<init>", char[].class, void.class), callerStack);
|
||||||
method.use();
|
method.use();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,11 +293,11 @@ class DependencyGraphBuilder {
|
||||||
final ClassReader targetClass = dependencyChecker.getClassSource().get(targetClsName);
|
final ClassReader targetClass = dependencyChecker.getClassSource().get(targetClsName);
|
||||||
if (targetClass != null) {
|
if (targetClass != null) {
|
||||||
valueNode.connect(receiverNode, new DependencyTypeFilter() {
|
valueNode.connect(receiverNode, new DependencyTypeFilter() {
|
||||||
@Override public boolean match(String type) {
|
@Override public boolean match(DependencyAgentType type) {
|
||||||
if (targetClass.getName().equals("java.lang.Object")) {
|
if (targetClass.getName().equals("java.lang.Object")) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return isAssignableFrom(dependencyChecker.getClassSource(), targetClass, type);
|
return isAssignableFrom(dependencyChecker.getClassSource(), targetClass, type.getName());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
|
@ -345,7 +349,8 @@ class DependencyGraphBuilder {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void createArray(VariableReader receiver, ValueType itemType, VariableReader size) {
|
public void createArray(VariableReader receiver, ValueType itemType, VariableReader size) {
|
||||||
useRunners.add(new TypePropagationRunner(nodes[receiver.getIndex()], "[" + itemType));
|
useRunners.add(new TypePropagationRunner(nodes[receiver.getIndex()],
|
||||||
|
dependencyChecker.getType("[" + itemType)));
|
||||||
final String className = extractClassName(itemType);
|
final String className = extractClassName(itemType);
|
||||||
if (className != null) {
|
if (className != null) {
|
||||||
useRunners.add(new Runnable() {
|
useRunners.add(new Runnable() {
|
||||||
|
@ -371,12 +376,13 @@ class DependencyGraphBuilder {
|
||||||
sb.append('[');
|
sb.append('[');
|
||||||
}
|
}
|
||||||
sb.append(itemType);
|
sb.append(itemType);
|
||||||
useRunners.add(new TypePropagationRunner(nodes[receiver.getIndex()], sb.toString()));
|
useRunners.add(new TypePropagationRunner(nodes[receiver.getIndex()],
|
||||||
|
dependencyChecker.getType(sb.toString())));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void create(VariableReader receiver, String type) {
|
public void create(VariableReader receiver, String type) {
|
||||||
useRunners.add(new TypePropagationRunner(nodes[receiver.getIndex()], type));
|
useRunners.add(new TypePropagationRunner(nodes[receiver.getIndex()], dependencyChecker.getType(type)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -405,7 +411,7 @@ class DependencyGraphBuilder {
|
||||||
DependencyNode arrayNode = nodes[array.getIndex()];
|
DependencyNode arrayNode = nodes[array.getIndex()];
|
||||||
final DependencyNode receiverNode = nodes[receiver.getIndex()];
|
final DependencyNode receiverNode = nodes[receiver.getIndex()];
|
||||||
arrayNode.addConsumer(new DependencyConsumer() {
|
arrayNode.addConsumer(new DependencyConsumer() {
|
||||||
@Override public void consume(String type) {
|
@Override public void consume(DependencyAgentType type) {
|
||||||
receiverNode.propagate(type);
|
receiverNode.propagate(type);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -522,7 +528,7 @@ class DependencyGraphBuilder {
|
||||||
"<init>", ValueType.VOID), callerStack);
|
"<init>", ValueType.VOID), callerStack);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
currentExceptionConsumer.consume("java.lang.NullPointerException");
|
currentExceptionConsumer.consume(dependencyChecker.getType("java.lang.NullPointerException"));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,10 +15,12 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.dependency;
|
package org.teavm.dependency;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.ConcurrentMap;
|
import java.util.concurrent.ConcurrentMap;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
import org.teavm.common.IntegerArray;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -26,9 +28,8 @@ import java.util.concurrent.atomic.AtomicReference;
|
||||||
*/
|
*/
|
||||||
public class DependencyNode implements ValueDependencyInfo {
|
public class DependencyNode implements ValueDependencyInfo {
|
||||||
private DependencyChecker dependencyChecker;
|
private DependencyChecker dependencyChecker;
|
||||||
private static final Object mapValue = new Object();
|
private Set<DependencyConsumer> followers = new HashSet<>();
|
||||||
private ConcurrentMap<DependencyConsumer, Object> followers = new ConcurrentHashMap<>();
|
private BitSet types = new BitSet();
|
||||||
private ConcurrentMap<String, Object> types = new ConcurrentHashMap<>();
|
|
||||||
private ConcurrentMap<DependencyNode, DependencyNodeToNodeTransition> transitions = new ConcurrentHashMap<>();
|
private ConcurrentMap<DependencyNode, DependencyNodeToNodeTransition> transitions = new ConcurrentHashMap<>();
|
||||||
private volatile String tag;
|
private volatile String tag;
|
||||||
private final AtomicReference<DependencyNode> arrayItemNode = new AtomicReference<>();
|
private final AtomicReference<DependencyNode> arrayItemNode = new AtomicReference<>();
|
||||||
|
@ -44,24 +45,36 @@ public class DependencyNode implements ValueDependencyInfo {
|
||||||
this.degree = degree;
|
this.degree = degree;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void propagate(String type) {
|
public void propagate(DependencyAgentType agentType) {
|
||||||
|
if (!(agentType instanceof DependencyType)) {
|
||||||
|
throw new IllegalArgumentException("The given type does not belong to the same dependency checker");
|
||||||
|
}
|
||||||
|
DependencyType type = (DependencyType)agentType;
|
||||||
|
if (type.getDependencyChecker() != dependencyChecker) {
|
||||||
|
throw new IllegalArgumentException("The given type does not belong to the same dependency checker");
|
||||||
|
}
|
||||||
if (degree > 2) {
|
if (degree > 2) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (types.putIfAbsent(type, mapValue) == null) {
|
if (!types.get(type.index)) {
|
||||||
|
types.set(type.index);
|
||||||
if (DependencyChecker.shouldLog) {
|
if (DependencyChecker.shouldLog) {
|
||||||
System.out.println(tag + " -> " + type);
|
System.out.println(tag + " -> " + type.getName());
|
||||||
}
|
}
|
||||||
for (DependencyConsumer consumer : followers.keySet().toArray(new DependencyConsumer[0])) {
|
for (DependencyConsumer consumer : followers.toArray(new DependencyConsumer[followers.size()])) {
|
||||||
dependencyChecker.schedulePropagation(consumer, type);
|
dependencyChecker.schedulePropagation(consumer, type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addConsumer(DependencyConsumer consumer) {
|
public void addConsumer(DependencyConsumer consumer) {
|
||||||
if (followers.putIfAbsent(consumer, mapValue) == null) {
|
if (followers.add(consumer)) {
|
||||||
for (String type : types.keySet().toArray(new String[0])) {
|
IntegerArray indexes = new IntegerArray(8);
|
||||||
dependencyChecker.schedulePropagation(consumer, type);
|
for (int index = types.nextSetBit(0); index >= 0; index = types.nextSetBit(index + 1)) {
|
||||||
|
indexes.add(index);
|
||||||
|
}
|
||||||
|
for (int index : indexes.getAll()) {
|
||||||
|
dependencyChecker.schedulePropagation(consumer, dependencyChecker.types.get(index));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -112,14 +125,26 @@ public class DependencyNode implements ValueDependencyInfo {
|
||||||
return arrayItemNode.get() != null && !arrayItemNode.get().types.isEmpty();
|
return arrayItemNode.get() != null && !arrayItemNode.get().types.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasType(DependencyAgentType type) {
|
||||||
|
if (!(type instanceof DependencyType)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
DependencyType typeImpl = (DependencyType)type;
|
||||||
|
return typeImpl.getDependencyChecker() == dependencyChecker && types.get(typeImpl.index);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasType(String type) {
|
public boolean hasType(String type) {
|
||||||
return types.containsKey(type);
|
return hasType(dependencyChecker.getType(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String[] getTypes() {
|
public String[] getTypes() {
|
||||||
return types != null ? types.keySet().toArray(new String[types.size()]) : new String[0];
|
List<String> result = new ArrayList<>();
|
||||||
|
for (int index = types.nextSetBit(0); index >= 0; index = types.nextSetBit(index + 1)) {
|
||||||
|
result.add(dependencyChecker.types.get(index).getName());
|
||||||
|
}
|
||||||
|
return result.toArray(new String[result.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getTag() {
|
public String getTag() {
|
||||||
|
|
|
@ -32,11 +32,11 @@ class DependencyNodeToNodeTransition implements DependencyConsumer {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void consume(String type) {
|
public void consume(DependencyAgentType type) {
|
||||||
if (filter != null && !filter.match(type)) {
|
if (filter != null && !filter.match(type)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (type.startsWith("[")) {
|
if (type.getName().startsWith("[")) {
|
||||||
source.getArrayItem().connect(destination.getArrayItem());
|
source.getArrayItem().connect(destination.getArrayItem());
|
||||||
destination.getArrayItem().connect(source.getArrayItem());
|
destination.getArrayItem().connect(source.getArrayItem());
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||||
|
*/
|
||||||
|
public class DependencyType implements DependencyAgentType {
|
||||||
|
private DependencyChecker dependencyChecker;
|
||||||
|
private String name;
|
||||||
|
int index;
|
||||||
|
|
||||||
|
public DependencyType(DependencyChecker dependencyChecker, String name, int index) {
|
||||||
|
this.dependencyChecker = dependencyChecker;
|
||||||
|
this.name = name;
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DependencyChecker getDependencyChecker() {
|
||||||
|
return dependencyChecker;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DependencyAgent getDependencyAgent() {
|
||||||
|
return dependencyChecker;
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,5 +20,5 @@ package org.teavm.dependency;
|
||||||
* @author Alexey Andreev
|
* @author Alexey Andreev
|
||||||
*/
|
*/
|
||||||
public interface DependencyTypeFilter {
|
public interface DependencyTypeFilter {
|
||||||
boolean match(String type);
|
boolean match(DependencyAgentType type);
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ import org.teavm.model.MethodReference;
|
||||||
* @author Alexey Andreev
|
* @author Alexey Andreev
|
||||||
*/
|
*/
|
||||||
public class MethodDependency implements MethodDependencyInfo {
|
public class MethodDependency implements MethodDependencyInfo {
|
||||||
|
private DependencyChecker dependencyChecker;
|
||||||
private DependencyNode[] variableNodes;
|
private DependencyNode[] variableNodes;
|
||||||
private int parameterCount;
|
private int parameterCount;
|
||||||
private DependencyNode resultNode;
|
private DependencyNode resultNode;
|
||||||
|
@ -35,8 +36,10 @@ public class MethodDependency implements MethodDependencyInfo {
|
||||||
private AtomicBoolean used = new AtomicBoolean();
|
private AtomicBoolean used = new AtomicBoolean();
|
||||||
private volatile Runnable useRunner;
|
private volatile Runnable useRunner;
|
||||||
|
|
||||||
MethodDependency(DependencyNode[] variableNodes, int parameterCount, DependencyNode resultNode,
|
MethodDependency(DependencyChecker dependencyChecker, DependencyNode[] variableNodes, int parameterCount,
|
||||||
DependencyNode thrown, DependencyStack stack, MethodReader method, MethodReference reference) {
|
DependencyNode resultNode, DependencyNode thrown, DependencyStack stack, MethodReader method,
|
||||||
|
MethodReference reference) {
|
||||||
|
this.dependencyChecker = dependencyChecker;
|
||||||
this.variableNodes = Arrays.copyOf(variableNodes, variableNodes.length);
|
this.variableNodes = Arrays.copyOf(variableNodes, variableNodes.length);
|
||||||
this.parameterCount = parameterCount;
|
this.parameterCount = parameterCount;
|
||||||
this.thrown = thrown;
|
this.thrown = thrown;
|
||||||
|
@ -46,6 +49,10 @@ public class MethodDependency implements MethodDependencyInfo {
|
||||||
this.reference = reference;
|
this.reference = reference;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DependencyAgent getDependencyAgent() {
|
||||||
|
return dependencyChecker;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DependencyNode[] getVariables() {
|
public DependencyNode[] getVariables() {
|
||||||
return Arrays.copyOf(variableNodes, variableNodes.length);
|
return Arrays.copyOf(variableNodes, variableNodes.length);
|
||||||
|
|
|
@ -48,7 +48,7 @@ class ProgrammableDependencyGraphCreator implements DependencyGraphCreator {
|
||||||
checker.getClassSource().get(conn.superclass)));
|
checker.getClassSource().get(conn.superclass)));
|
||||||
}
|
}
|
||||||
for (TypePropagation propagation : typePropagations) {
|
for (TypePropagation propagation : typePropagations) {
|
||||||
nodes[propagation.var].propagate(propagation.type);
|
nodes[propagation.var].propagate(checker.getType(propagation.type));
|
||||||
}
|
}
|
||||||
for (String className : initializedClasses) {
|
for (String className : initializedClasses) {
|
||||||
checker.initClass(className, stack);
|
checker.initClass(className, stack);
|
||||||
|
@ -79,11 +79,11 @@ class ProgrammableDependencyGraphCreator implements DependencyGraphCreator {
|
||||||
this.classSource = classSource;
|
this.classSource = classSource;
|
||||||
this.superClass = superClass;
|
this.superClass = superClass;
|
||||||
}
|
}
|
||||||
@Override public boolean match(String type) {
|
@Override public boolean match(DependencyAgentType type) {
|
||||||
if (superClass.getName().equals("java.lang.Object")) {
|
if (superClass.getName().equals("java.lang.Object")) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return isAssignableFrom(classSource, superClass, type);
|
return isAssignableFrom(classSource, superClass, type.getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ class TestExceptionDependency implements DependencyListener {
|
||||||
@Override
|
@Override
|
||||||
public void classAchieved(DependencyAgent agent, String className) {
|
public void classAchieved(DependencyAgent agent, String className) {
|
||||||
if (isException(agent.getClassSource(), className)) {
|
if (isException(agent.getClassSource(), className)) {
|
||||||
allClasses.propagate(className);
|
allClasses.propagate(agent.getType(className));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -301,7 +301,7 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
||||||
ValueType.VOID), DependencyStack.ROOT).use();
|
ValueType.VOID), DependencyStack.ROOT).use();
|
||||||
MethodDependency internDep = dependencyChecker.linkMethod(new MethodReference("java.lang.String", "intern",
|
MethodDependency internDep = dependencyChecker.linkMethod(new MethodReference("java.lang.String", "intern",
|
||||||
ValueType.object("java.lang.String")), DependencyStack.ROOT);
|
ValueType.object("java.lang.String")), DependencyStack.ROOT);
|
||||||
internDep.getVariable(0).propagate("java.lang.String");
|
internDep.getVariable(0).propagate(dependencyChecker.getType("java.lang.String"));
|
||||||
internDep.use();
|
internDep.use();
|
||||||
dependencyChecker.linkMethod(new MethodReference("java.lang.String", "length", ValueType.INTEGER),
|
dependencyChecker.linkMethod(new MethodReference("java.lang.String", "length", ValueType.INTEGER),
|
||||||
DependencyStack.ROOT).use();
|
DependencyStack.ROOT).use();
|
||||||
|
|
|
@ -88,7 +88,7 @@ public class TeaVMEntryPoint {
|
||||||
if (argument > reference.parameterCount()) {
|
if (argument > reference.parameterCount()) {
|
||||||
throw new IllegalArgumentException("Illegal argument #" + argument + " of " + reference.parameterCount());
|
throw new IllegalArgumentException("Illegal argument #" + argument + " of " + reference.parameterCount());
|
||||||
}
|
}
|
||||||
method.getVariable(argument).propagate(type);
|
method.getVariable(argument).propagate(method.getDependencyAgent().getType(type));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ public class JavaScriptBodyDependency implements DependencyListener {
|
||||||
public OneDirectionalConnection( DependencyNode target) {
|
public OneDirectionalConnection( DependencyNode target) {
|
||||||
this.target = target;
|
this.target = target;
|
||||||
}
|
}
|
||||||
@Override public void consume(String type) {
|
@Override public void consume(DependencyAgentType type) {
|
||||||
target.propagate(type);
|
target.propagate(type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ public class JavaScriptBodyDependency implements DependencyListener {
|
||||||
ClassReader cls = agent.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(agent.getType(className));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,11 +161,11 @@ public class JavaScriptBodyDependency implements DependencyListener {
|
||||||
this.caller = caller;
|
this.caller = caller;
|
||||||
this.superClass = agent.getClassSource().get(superMethod.getOwnerName());
|
this.superClass = agent.getClassSource().get(superMethod.getOwnerName());
|
||||||
}
|
}
|
||||||
@Override public void consume(String type) {
|
@Override public void consume(DependencyAgentType type) {
|
||||||
if (!isAssignableFrom(superClass, type)) {
|
if (!isAssignableFrom(superClass, type.getName())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
MethodReference methodRef = new MethodReference(type, superMethod.getDescriptor());
|
MethodReference methodRef = new MethodReference(type.getName(), superMethod.getDescriptor());
|
||||||
MethodDependency method = agent.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) {
|
||||||
|
|
|
@ -118,8 +118,8 @@ public class JSNativeGenerator implements Generator, Injector, DependencyPlugin
|
||||||
public void methodAchieved(final DependencyAgent agent, final MethodDependency method) {
|
public void methodAchieved(final DependencyAgent agent, final MethodDependency method) {
|
||||||
for (int i = 0; i < method.getReference().parameterCount(); ++i) {
|
for (int i = 0; i < method.getReference().parameterCount(); ++i) {
|
||||||
method.getVariable(i).addConsumer(new DependencyConsumer() {
|
method.getVariable(i).addConsumer(new DependencyConsumer() {
|
||||||
@Override public void consume(String type) {
|
@Override public void consume(DependencyAgentType type) {
|
||||||
achieveFunctorMethods(agent, type, method);
|
achieveFunctorMethods(agent, type.getName(), method);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ class TestExceptionDependency implements DependencyListener {
|
||||||
@Override
|
@Override
|
||||||
public void classAchieved(DependencyAgent agent, String className) {
|
public void classAchieved(DependencyAgent agent, String className) {
|
||||||
if (isException(agent.getClassSource(), className)) {
|
if (isException(agent.getClassSource(), className)) {
|
||||||
allClasses.propagate(className);
|
allClasses.propagate(agent.getType(className));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ class ResourceAccessorDependencyListener implements DependencyListener {
|
||||||
public void methodAchieved(DependencyAgent agent, MethodDependency method) {
|
public void methodAchieved(DependencyAgent agent, MethodDependency method) {
|
||||||
switch (method.getReference().getName()) {
|
switch (method.getReference().getName()) {
|
||||||
case "castToString":
|
case "castToString":
|
||||||
method.getResult().propagate("java.lang.String");
|
method.getResult().propagate(agent.getType("java.lang.String"));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user