private void connectArrayItemNodes(DependencyNode node) { if (degree > DEGREE_THRESHOLD || node.degree > DEGREE_THRESHOLD) { return; } if (!isArray(typeFilter) || !isArray(node.typeFilter)) { return; } if (Objects.equals(typeFilter, node.typeFilter)) { if (arrayItemNode != null && node.arrayItemNode == null) { node.arrayItemNode = arrayItemNode; return; } if (node.arrayItemNode != null && arrayItemNode == null) { arrayItemNode = node.arrayItemNode; return; } if (node.arrayItemNode == null && arrayItemNode == null) { node.arrayItemNode = getArrayItem(); return; } } getArrayItem().connect(node.getArrayItem()); node.getArrayItem().connect(getArrayItem()); }
private void reachArrayCopy(MethodDependency method) { DependencyNode src = method.getVariable(1); DependencyNode dest = method.getVariable(3); src.getArrayItem().connect(dest.getArrayItem()); } }
@Override public void putElement(VariableReader array, VariableReader index, VariableReader value, ArrayElementType type) { if (isPrimitive(type)) { return; } DependencyNode valueNode = nodes[value.getIndex()]; DependencyNode arrayNode = nodes[array.getIndex()]; if (valueNode != null && arrayNode != null && valueNode != arrayNode.getArrayItem()) { valueNode.connect(arrayNode.getArrayItem()); } }
@Override public void getElement(VariableReader receiver, VariableReader array, VariableReader index, ArrayElementType type) { if (isPrimitive(type)) { return; } DependencyNode arrayNode = nodes[array.getIndex()]; DependencyNode receiverNode = nodes[receiver.getIndex()]; if (arrayNode != null && receiverNode != null && receiverNode != arrayNode.getArrayItem()) { arrayNode.getArrayItem().connect(receiverNode); } }
private void reachSet(DependencyAgent agent, MethodDependency method) { method.getVariable(3).connect(method.getVariable(1).getArrayItem()); method.getVariable(1).addConsumer(type -> { if (type.getName().startsWith("[")) { String typeName = type.getName().substring(1); for (int i = 0; i < primitiveTypes.length; ++i) { if (primitiveTypes[i].toString().equals(typeName)) { String wrapper = "java.lang." + primitiveWrappers[i]; MethodReference methodRef = new MethodReference(wrapper, primitives[i].toLowerCase() + "Value", primitiveTypes[i]); agent.linkMethod(methodRef).use(); } } } }); } }
@Override public void cloneArray(VariableReader receiver, VariableReader array) { DependencyNode arrayNode = getNode(array); DependencyNode receiverNode = getNode(receiver); if (arrayNode != null && receiverNode != null) { arrayNode.addConsumer(receiverNode::propagate); arrayNode.getArrayItem().connect(receiverNode.getArrayItem()); } MethodDependency cloneDep = getAnalyzer().linkMethod(CLONE_METHOD); cloneDep.addLocation(getCallLocation()); arrayNode.connect(cloneDep.getVariable(0)); cloneDep.use(); }
private void reachGet(DependencyAgent agent, MethodDependency method) { method.getVariable(1).getArrayItem().connect(method.getResult()); method.getVariable(1).addConsumer(type -> { if (type.getName().startsWith("[")) { String typeName = type.getName().substring(1); for (int i = 0; i < primitiveTypes.length; ++i) { if (primitiveTypes[i].toString().equals(typeName)) { String wrapper = "java.lang." + primitiveWrappers[i]; MethodReference methodRef = new MethodReference(wrapper, "valueOf", primitiveTypes[i], ValueType.object(wrapper)); agent.linkMethod(methodRef).use(); method.getResult().propagate(agent.getType("java.lang." + primitiveWrappers[i])); } } } }); }
@Override public void createArray(VariableReader receiver, ValueType itemType, List<? extends VariableReader> dimensions) { DependencyNode node = getNode(receiver); for (int i = 0; i < dimensions.size(); ++i) { if (node == null) { break; } String itemTypeStr; if (itemType instanceof ValueType.Object) { itemTypeStr = ((ValueType.Object) itemType).getClassName(); } else { itemTypeStr = itemType.toString(); } node.propagate(getAnalyzer().getType(itemTypeStr)); node = node.getArrayItem(); itemType = ((ValueType.Array) itemType).getItemType(); } String className = extractClassName(itemType); if (className != null) { getAnalyzer().linkClass(className); } }
@Override public void methodReached(DependencyAgent agent, MethodDependency method) { MethodReference ref = method.getReference(); if (ref.getClassName().equals("java.util.ServiceLoader") && ref.getName().equals("loadServices")) { List<ServiceLoaderFilter> filters = getFilters(agent); method.getResult().propagate(agent.getType("[Ljava/lang/Object;")); DependencyNode sourceNode = agent.linkMethod(LOAD_METHOD).getVariable(1).getClassValueNode(); sourceNode.connect(method.getResult().getArrayItem()); sourceNode.addConsumer(type -> { CallLocation location = new CallLocation(LOAD_METHOD); for (String implementationType : getImplementations(type.getName())) { if (filters.stream().anyMatch(filter -> !filter.apply(type.getName(), implementationType))) { continue; } serviceMap.computeIfAbsent(type.getName(), k -> new ArrayList<>()).add(implementationType); MethodReference ctor = new MethodReference(implementationType, new MethodDescriptor("<init>", ValueType.VOID)); agent.linkMethod(ctor).addLocation(location).use(); method.getResult().getArrayItem().propagate(agent.getType(implementationType)); } }); } }
if (method.getResult() != null) { allClassesNode.connect(method.getResult()); allClassesNode.addConsumer(new OneDirectionalConnection(method.getResult().getArrayItem())); allClassesNode.addConsumer(new OneDirectionalConnection(method.getResult().getArrayItem() .getArrayItem())); allClassesNode.addConsumer(new OneDirectionalConnection(method.getVariable(i).getArrayItem())); allClassesNode.addConsumer(new OneDirectionalConnection(method.getVariable(i).getArrayItem() .getArrayItem()));
MethodDependency readMethod = agent.linkMethod(new MethodReference(className, "getAnnotations", ValueType.parse(Annotation[].class))); readMethod.getResult().getArrayItem().connect(method.getResult().getArrayItem()); readMethod.use();
public void entryPoint(String className, String name) { if (entryPoints.containsKey(name)) { throw new IllegalArgumentException("Entry point with public name `" + name + "' already defined " + "for class " + className); } ClassReader cls = dependencyAnalyzer.getClassSource().get(className); if (cls == null) { diagnostics.error(null, "There's no main class: '{{c0}}'", className); return; } if (cls.getMethod(MAIN_METHOD_DESC) == null) { diagnostics.error(null, "Specified main class '{{c0}}' does not have method '" + MAIN_METHOD_DESC + "'", cls.getName()); return; } MethodDependency mainMethod = dependencyAnalyzer.linkMethod(new MethodReference(className, "main", ValueType.parse(String[].class), ValueType.VOID)); TeaVMEntryPoint entryPoint = new TeaVMEntryPoint(name, mainMethod); dependencyAnalyzer.defer(() -> { dependencyAnalyzer.linkClass(className).initClass(null); mainMethod.getVariable(1).propagate(dependencyAnalyzer.getType("[Ljava/lang/String;")); mainMethod.getVariable(1).getArrayItem().propagate(dependencyAnalyzer.getType("java.lang.String")); mainMethod.use(); }); entryPoints.put(name, entryPoint); }
public static void includeStackTraceMethods(DependencyAnalyzer dependencyAnalyzer) { MethodDependency dep; DependencyType stringType = dependencyAnalyzer.getType("java.lang.String"); dep = dependencyAnalyzer.linkMethod(new MethodReference( StackTraceElement.class, "<init>", String.class, String.class, String.class, int.class, void.class)); dep.getVariable(0).propagate(dependencyAnalyzer.getType(StackTraceElement.class.getName())); dep.getVariable(1).propagate(stringType); dep.getVariable(2).propagate(stringType); dep.getVariable(3).propagate(stringType); dep.use(); dep = dependencyAnalyzer.linkMethod(new MethodReference( Throwable.class, "setStackTrace", StackTraceElement[].class, void.class)); dep.getVariable(0).propagate(dependencyAnalyzer.getType(Throwable.class.getName())); dep.getVariable(1).propagate(dependencyAnalyzer.getType("[Ljava/lang/StackTraceElement;")); dep.getVariable(1).getArrayItem().propagate(dependencyAnalyzer.getType(StackTraceElement.class.getName())); dep.use(); }
@Override public void methodReached(DependencyAgent agent, MethodDependency method) { if (method.getReference().getClassName().equals(Platform.class.getName()) && method.getReference().getName().equals("getEnumConstants")) { allEnums.connect(method.getResult().getArrayItem()); final MethodReference ref = method.getReference(); allEnums.addConsumer(type -> { ClassReader cls = agent.getClassSource().get(type.getName()); MethodReader valuesMethod = cls.getMethod(new MethodDescriptor("values", ValueType.arrayOf(ValueType.object(cls.getName())))); if (valuesMethod != null) { MethodDependency valuesDep = agent.linkMethod(valuesMethod.getReference()); valuesDep.addLocation(new CallLocation(ref)); valuesDep.use(); } }); method.getResult().propagate(agent.getType("[Ljava/lang/Enum;")); for (String cls : agent.getReachableClasses()) { classReached(agent, cls); } } } }
@Override public void consume(DependencyType type) { if (!agent.getClassHierarchy().isSuperType(superMethod.getClassName(), type.getName(), false)) { return; } MethodReader method = agent.getClassSource().resolveImplementation(new MethodReference( type.getName(), superMethod.getDescriptor())); if (method == null) { return; } virtualMethods.add(method.getReference()); MethodDependency methodDep = agent.linkMethod(method.getReference()); methodDep.use(); for (int i = 0; i < methodDep.getParameterCount(); ++i) { allClassesNode.connect(methodDep.getVariable(i)); allClassesNode.connect(methodDep.getVariable(i).getArrayItem()); } } }
private void handleNewInstance(DependencyAgent agent, MethodDependency method) { CallLocation location = new CallLocation(method.getReference()); DependencyNode classValueNode = agent.linkMethod(getConstructors) .addLocation(location) .getVariable(0).getClassValueNode(); classValueNode.addConsumer(reflectedType -> { if (reflectedType.getName().startsWith("[")) { return; } Set<MethodDescriptor> accessibleMethods = getAccessibleMethods(agent, reflectedType.getName()); ClassReader cls = agent.getClassSource().get(reflectedType.getName()); for (MethodDescriptor methodDescriptor : accessibleMethods) { MethodReader calledMethod = cls.getMethod(methodDescriptor); MethodDependency calledMethodDep = agent.linkMethod(calledMethod.getReference()).addLocation(location); calledMethodDep.use(); for (int i = 0; i < calledMethod.parameterCount(); ++i) { propagateSet(agent, methodDescriptor.parameterType(i), method.getVariable(1).getArrayItem(), calledMethodDep.getVariable(i + 1), location); } calledMethodDep.getVariable(0).propagate(reflectedType); linkClassIfNecessary(agent, calledMethod, location); } }); classValueNode.connect(method.getResult()); }
} else if (method.getReference().equals(methodGetParameterTypes) || method.getReference().equals(constructorGetParameterTypes)) { method.getResult().getArrayItem().propagate(agent.getType("java.lang.Class")); typesInReflectableSignaturesNode.connect(method.getResult().getArrayItem().getClassValueNode());
private void handleInvoke(DependencyAgent agent, MethodDependency method) { CallLocation location = new CallLocation(method.getReference()); DependencyNode classValueNode = agent.linkMethod(getMethods) .addLocation(location) .getVariable(0).getClassValueNode(); classValueNode.addConsumer(reflectedType -> { if (reflectedType.getName().startsWith("[")) { return; } Set<MethodDescriptor> accessibleMethods = getAccessibleMethods(agent, reflectedType.getName()); ClassReader cls = agent.getClassSource().get(reflectedType.getName()); for (MethodDescriptor methodDescriptor : accessibleMethods) { MethodReader calledMethod = cls.getMethod(methodDescriptor); MethodDependency calledMethodDep = agent.linkMethod(calledMethod.getReference()).addLocation(location); calledMethodDep.use(); for (int i = 0; i < calledMethod.parameterCount(); ++i) { propagateSet(agent, methodDescriptor.parameterType(i), method.getVariable(2).getArrayItem(), calledMethodDep.getVariable(i + 1), location); } propagateSet(agent, ValueType.object(reflectedType.getName()), method.getVariable(1), calledMethodDep.getVariable(0), location); propagateGet(agent, calledMethod.getResultType(), calledMethodDep.getResult(), method.getResult(), location); linkClassIfNecessary(agent, calledMethod, location); } }); }
@Override public void putElement(VariableReader array, VariableReader index, VariableReader value, ArrayElementType type) { DependencyNode valueNode = nodes[value.getIndex()]; DependencyNode arrayNode = nodes[array.getIndex()]; if (valueNode != null && arrayNode != null && valueNode != arrayNode.getArrayItem()) { valueNode.connect(arrayNode.getArrayItem()); } }
public TeaVMEntryPoint withArrayValue(int argument, String type) { if (argument > reference.parameterCount()) { throw new IllegalArgumentException("Illegal argument #" + argument + " of " + reference.parameterCount()); } method.getVariable(argument).getArrayItem().propagate(method.getDependencyAgent().getType(type)); return this; }