mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
Properly handle checkcast to array type in dependency analyzer
This commit is contained in:
parent
3653e39bec
commit
4e20a1de18
|
@ -20,6 +20,7 @@ import java.io.IOException;
|
|||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
|
@ -109,7 +110,7 @@ public class ServiceLoaderSupport extends AbstractDependencyListener implements
|
|||
}
|
||||
|
||||
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, StandardCharsets.UTF_8));
|
||||
while (true) {
|
||||
String line = reader.readLine();
|
||||
if (line == null) {
|
||||
|
@ -119,12 +120,7 @@ public class ServiceLoaderSupport extends AbstractDependencyListener implements
|
|||
if (line.startsWith("#") || line.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
List<String> implementors = serviceMap.get(service);
|
||||
if (implementors == null) {
|
||||
implementors = new ArrayList<>();
|
||||
serviceMap.put(service, implementors);
|
||||
}
|
||||
implementors.add(line);
|
||||
serviceMap.computeIfAbsent(service, k -> new ArrayList<>()).add(line);
|
||||
allClassesNode.propagate(agent.getType(line));
|
||||
}
|
||||
}
|
||||
|
@ -133,7 +129,7 @@ public class ServiceLoaderSupport extends AbstractDependencyListener implements
|
|||
public void methodReached(final DependencyAgent agent, MethodDependency method, final CallLocation location) {
|
||||
MethodReference ref = method.getReference();
|
||||
if (ref.getClassName().equals("java.util.ServiceLoader") && ref.getName().equals("loadServices")) {
|
||||
method.getResult().propagate(agent.getType("[java.lang.Object"));
|
||||
method.getResult().propagate(agent.getType("[Ljava/lang/Object;"));
|
||||
allClassesNode.connect(method.getResult().getArrayItem());
|
||||
method.getResult().getArrayItem().addConsumer(type -> initConstructor(agent, type.getName(), location));
|
||||
}
|
||||
|
|
|
@ -76,6 +76,9 @@ public class ClassGenerator implements Generator, Injector, DependencyPlugin {
|
|||
case "getInterfaces":
|
||||
reachGetInterfaces(agent, method);
|
||||
break;
|
||||
case "getComponentType":
|
||||
reachGetComponentType(agent, method);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -109,6 +112,19 @@ public class ClassGenerator implements Generator, Injector, DependencyPlugin {
|
|||
});
|
||||
}
|
||||
|
||||
private void reachGetComponentType(DependencyAgent agent, MethodDependency method) {
|
||||
method.getVariable(0).getClassValueNode().addConsumer(t -> {
|
||||
if (!t.getName().startsWith("[")) {
|
||||
return;
|
||||
}
|
||||
String typeName = t.getName().substring(1);
|
||||
if (typeName.charAt(0) == 'L') {
|
||||
typeName = ((ValueType.Object) ValueType.parse(typeName)).getClassName();
|
||||
}
|
||||
method.getResult().getClassValueNode().propagate(agent.getType(typeName));
|
||||
});
|
||||
}
|
||||
|
||||
private void generateCreateMetadata(GeneratorContext context, SourceWriter writer) throws IOException {
|
||||
ReflectionDependencyListener reflection = context.getService(ReflectionDependencyListener.class);
|
||||
for (String className : reflection.getClassesWithReflectableFields()) {
|
||||
|
|
|
@ -179,6 +179,7 @@ public class TClass<T> extends TObject implements TAnnotatedElement {
|
|||
return (platformClass.getMetadata().getFlags() & Flags.INTERFACE) != 0;
|
||||
}
|
||||
|
||||
@PluggableDependency(ClassGenerator.class)
|
||||
public TClass<?> getComponentType() {
|
||||
return getClass(Platform.getArrayItem(platformClass));
|
||||
}
|
||||
|
|
|
@ -42,11 +42,16 @@ public class ArrayNativeGenerator implements Generator, DependencyPlugin {
|
|||
case "getLength":
|
||||
achieveGetLength(agent, method);
|
||||
break;
|
||||
case "newInstanceImpl":
|
||||
method.getResult().propagate(agent.getType("[java.lang.Object"));
|
||||
case "newInstance":
|
||||
method.getVariable(1).getClassValueNode().addConsumer(t -> {
|
||||
String arrayTypeName = t.getName().startsWith("[")
|
||||
? t.getName()
|
||||
: ValueType.object(t.getName()).toString();
|
||||
method.getResult().propagate(agent.getType("[" + arrayTypeName));
|
||||
});
|
||||
break;
|
||||
case "getImpl":
|
||||
achieveGet(agent, method);
|
||||
reachGet(agent, method);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -121,7 +126,7 @@ public class ArrayNativeGenerator implements Generator, DependencyPlugin {
|
|||
writer.outdent().append("}").softNewLine();
|
||||
}
|
||||
|
||||
private void achieveGet(final DependencyAgent agent, final MethodDependency method) {
|
||||
private void reachGet(DependencyAgent agent, MethodDependency method) {
|
||||
method.getVariable(1).getArrayItem().connect(method.getResult());
|
||||
method.getVariable(1).addConsumer(type -> {
|
||||
if (type.getName().startsWith("[")) {
|
||||
|
|
|
@ -47,6 +47,7 @@ public final class TArray extends TObject {
|
|||
return array.size;
|
||||
}
|
||||
|
||||
@PluggableDependency(ArrayNativeGenerator.class)
|
||||
public static TObject newInstance(TClass<?> componentType, int length) throws TNegativeArraySizeException {
|
||||
if (componentType == null) {
|
||||
throw new TNullPointerException();
|
||||
|
@ -61,7 +62,6 @@ public final class TArray extends TObject {
|
|||
}
|
||||
|
||||
@GeneratedBy(ArrayNativeGenerator.class)
|
||||
@PluggableDependency(ArrayNativeGenerator.class)
|
||||
@DelegateTo("newInstanceLowLevel")
|
||||
private static native TObject newInstanceImpl(PlatformClass componentType, int length);
|
||||
|
||||
|
|
|
@ -88,7 +88,7 @@ public class DependencyAnalyzer implements DependencyInfo {
|
|||
Map<MethodReference, BootstrapMethodSubstitutor> bootstrapMethodSubstitutors = new HashMap<>();
|
||||
Map<MethodReference, DependencyPlugin> dependencyPlugins = new HashMap<>();
|
||||
private boolean completing;
|
||||
private Map<String, SuperClassFilter> superClassFilters = new HashMap<>();
|
||||
private Map<String, DependencyTypeFilter> superClassFilters = new HashMap<>();
|
||||
boolean asyncSupported;
|
||||
|
||||
public DependencyAnalyzer(ClassReaderSource classSource, ClassLoader classLoader, ServiceRepository services,
|
||||
|
@ -591,7 +591,9 @@ public class DependencyAnalyzer implements DependencyInfo {
|
|||
if (tasks.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
tasks.remove().run();
|
||||
while (!tasks.isEmpty()) {
|
||||
tasks.remove().run();
|
||||
}
|
||||
if (++index == 100) {
|
||||
if (interruptor != null && !interruptor.shouldContinue()) {
|
||||
interrupted = true;
|
||||
|
@ -729,7 +731,24 @@ public class DependencyAnalyzer implements DependencyInfo {
|
|||
dependencyPlugins.put(method, dependencyPlugin);
|
||||
}
|
||||
|
||||
SuperClassFilter getSuperClassFilter(String superClass) {
|
||||
return superClassFilters.computeIfAbsent(superClass, s -> new SuperClassFilter(classSource, s));
|
||||
DependencyTypeFilter getSuperClassFilter(String superClass) {
|
||||
DependencyTypeFilter result = superClassFilters.get(superClass);
|
||||
if (result == null) {
|
||||
if (superClass.startsWith("[")) {
|
||||
char second = superClass.charAt(1);
|
||||
if (second == '[') {
|
||||
result = new SuperArrayFilter(this, getSuperClassFilter(superClass.substring(1)));
|
||||
} else if (second == 'L') {
|
||||
ValueType.Object itemType = (ValueType.Object) ValueType.parse(superClass.substring(1));
|
||||
result = new SuperArrayFilter(this, getSuperClassFilter(itemType.getClassName()));
|
||||
} else {
|
||||
result = new ExactTypeFilter(superClass);
|
||||
}
|
||||
} else {
|
||||
result = new SuperClassFilter(classSource, superClass);
|
||||
}
|
||||
superClassFilters.put(superClass, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -321,7 +321,7 @@ class DependencyGraphBuilder {
|
|||
private final Set<MethodReference> knownMethods = new HashSet<>();
|
||||
private final BitSet knownTypes = new BitSet();
|
||||
private ExceptionConsumer exceptionConsumer;
|
||||
private SuperClassFilter filter;
|
||||
private DependencyTypeFilter filter;
|
||||
|
||||
VirtualCallConsumer(DependencyNode node, String filterClass,
|
||||
MethodDescriptor methodDesc, DependencyAnalyzer analyzer, DependencyNode[] parameters,
|
||||
|
@ -441,13 +441,27 @@ class DependencyGraphBuilder {
|
|||
ClassReaderSource classSource = dependencyAnalyzer.getClassSource();
|
||||
if (targetType instanceof ValueType.Object) {
|
||||
String targetClsName = ((ValueType.Object) targetType).getClassName();
|
||||
final ClassReader targetClass = classSource.get(targetClsName);
|
||||
ClassReader targetClass = classSource.get(targetClsName);
|
||||
if (targetClass != null && !(targetClass.getName().equals("java.lang.Object"))) {
|
||||
if (valueNode != null && receiverNode != null) {
|
||||
valueNode.connect(receiverNode, dependencyAnalyzer.getSuperClassFilter(targetClass.getName()));
|
||||
}
|
||||
return;
|
||||
}
|
||||
} else if (targetType instanceof ValueType.Array) {
|
||||
ValueType itemType = targetType;
|
||||
while (itemType instanceof ValueType.Array) {
|
||||
itemType = ((ValueType.Array) itemType).getItemType();
|
||||
}
|
||||
if (itemType instanceof ValueType.Object) {
|
||||
ClassReader targetClass = classSource.get(((ValueType.Object) itemType).getClassName());
|
||||
if (targetClass == null) {
|
||||
valueNode.connect(receiverNode);
|
||||
return;
|
||||
}
|
||||
}
|
||||
valueNode.connect(receiverNode, dependencyAnalyzer.getSuperClassFilter(targetType.toString()));
|
||||
return;
|
||||
}
|
||||
if (valueNode != null && receiverNode != null) {
|
||||
valueNode.connect(receiverNode);
|
||||
|
|
|
@ -33,7 +33,7 @@ public class DependencyNode implements ValueDependencyInfo {
|
|||
boolean locked;
|
||||
MethodReference method;
|
||||
private ValueType typeFilter;
|
||||
private SuperClassFilter cachedTypeFilter;
|
||||
private DependencyTypeFilter cachedTypeFilter;
|
||||
|
||||
DependencyNode(DependencyAnalyzer dependencyAnalyzer, ValueType typeFilter) {
|
||||
this(dependencyAnalyzer, typeFilter, 0);
|
||||
|
|
29
core/src/main/java/org/teavm/dependency/ExactTypeFilter.java
Normal file
29
core/src/main/java/org/teavm/dependency/ExactTypeFilter.java
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright 2018 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;
|
||||
|
||||
class ExactTypeFilter implements DependencyTypeFilter {
|
||||
String typeName;
|
||||
|
||||
ExactTypeFilter(String typeName) {
|
||||
this.typeName = typeName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean match(DependencyType type) {
|
||||
return typeName.equals(type.getName());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright 2018 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 org.teavm.model.ValueType;
|
||||
|
||||
class SuperArrayFilter implements DependencyTypeFilter {
|
||||
private DependencyAnalyzer analyzer;
|
||||
private DependencyTypeFilter itemTypeFilter;
|
||||
|
||||
SuperArrayFilter(DependencyAnalyzer analyzer, DependencyTypeFilter itemTypeFilter) {
|
||||
this.analyzer = analyzer;
|
||||
this.itemTypeFilter = itemTypeFilter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean match(DependencyType type) {
|
||||
if (!type.getName().startsWith("[")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String typeName = type.getName().substring(1);
|
||||
ValueType valueType = ValueType.parseIfPossible(typeName);
|
||||
if (valueType == null || valueType instanceof ValueType.Primitive) {
|
||||
return false;
|
||||
}
|
||||
if (valueType instanceof ValueType.Object) {
|
||||
typeName = ((ValueType.Object) valueType).getClassName();
|
||||
}
|
||||
return itemTypeFilter.match(analyzer.getType(typeName));
|
||||
}
|
||||
}
|
|
@ -43,7 +43,7 @@ public class AnnotationDependencySupport extends AbstractDependencyListener {
|
|||
public void methodReached(DependencyAgent agent, MethodDependency method, CallLocation location) {
|
||||
if (method.getReference().getClassName().equals(Platform.class.getName())
|
||||
&& method.getReference().getName().equals("getAnnotations")) {
|
||||
method.getResult().propagate(agent.getType("[" + Annotation.class.getName()));
|
||||
method.getResult().propagate(agent.getType("[" + ValueType.parse(Annotation.class).toString()));
|
||||
agent.linkMethod(new MethodReference(PlatformAnnotationProvider.class, "getAnnotations",
|
||||
Annotation[].class), location);
|
||||
allClasses.addConsumer(type -> {
|
||||
|
|
|
@ -51,6 +51,9 @@ public class PlatformGenerator implements Generator, Injector, DependencyPlugin
|
|||
case "getCurrentThread":
|
||||
method.getResult().propagate(agent.getType("java.lang.Thread"));
|
||||
break;
|
||||
case "getEnumConstants":
|
||||
method.getResult().propagate(agent.getType("[Ljava/lang/Enum;"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user