C backend: fix bugs

This commit is contained in:
Alexey Andreev 2019-02-26 00:10:07 +03:00
parent 2c40c7d56e
commit ade00cc984
11 changed files with 64 additions and 16 deletions

View File

@ -108,6 +108,9 @@ import org.teavm.vm.TeaVMTargetController;
import org.teavm.vm.spi.TeaVMHostExtension; import org.teavm.vm.spi.TeaVMHostExtension;
public class CTarget implements TeaVMTarget, TeaVMCHost { public class CTarget implements TeaVMTarget, TeaVMCHost {
private static final Set<MethodReference> VIRTUAL_METHODS = new HashSet<>(Arrays.asList(
new MethodReference(Object.class, "clone", Object.class)
));
private TeaVMTargetController controller; private TeaVMTargetController controller;
private ClassInitializerInsertionTransformer clinitInsertionTransformer; private ClassInitializerInsertionTransformer clinitInsertionTransformer;
private ClassInitializerEliminator classInitializerEliminator; private ClassInitializerEliminator classInitializerEliminator;
@ -146,6 +149,8 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
clinitInsertionTransformer = new ClassInitializerInsertionTransformer(controller.getUnprocessedClassSource()); clinitInsertionTransformer = new ClassInitializerInsertionTransformer(controller.getUnprocessedClassSource());
nullCheckInsertion = new NullCheckInsertion(characteristics); nullCheckInsertion = new NullCheckInsertion(characteristics);
nullCheckTransformation = new NullCheckTransformation(); nullCheckTransformation = new NullCheckTransformation();
controller.addVirtualMethods(VIRTUAL_METHODS::contains);
} }
@Override @Override
@ -243,8 +248,9 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
List<Generator> generators = new ArrayList<>(); List<Generator> generators = new ArrayList<>();
generators.add(new ArrayGenerator()); generators.add(new ArrayGenerator());
GenerationContext context = new GenerationContext(vtableProvider, characteristics, stringPool, nameProvider, GenerationContext context = new GenerationContext(vtableProvider, characteristics,
controller.getDiagnostics(), classes, intrinsics, generators); controller.getDependencyInfo(), stringPool, nameProvider, controller.getDiagnostics(), classes,
intrinsics, generators);
BufferedCodeWriter codeWriter = new BufferedCodeWriter(); BufferedCodeWriter codeWriter = new BufferedCodeWriter();
copyResource(codeWriter, "runtime.c"); copyResource(codeWriter, "runtime.c");
@ -362,7 +368,7 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
} }
} }
return new VirtualTableProvider(classes, virtualMethods); return new VirtualTableProvider(classes, virtualMethods, controller::isVirtual);
} }
private void generateSpecialFunctions(GenerationContext context, CodeWriter writer) { private void generateSpecialFunctions(GenerationContext context, CodeWriter writer) {

View File

@ -28,6 +28,7 @@ import org.teavm.ast.decompilation.Decompiler;
import org.teavm.backend.c.generators.Generator; import org.teavm.backend.c.generators.Generator;
import org.teavm.backend.c.generators.GeneratorContext; import org.teavm.backend.c.generators.GeneratorContext;
import org.teavm.backend.lowlevel.generate.ClassGeneratorUtil; import org.teavm.backend.lowlevel.generate.ClassGeneratorUtil;
import org.teavm.dependency.DependencyInfo;
import org.teavm.diagnostics.Diagnostics; import org.teavm.diagnostics.Diagnostics;
import org.teavm.interop.Address; import org.teavm.interop.Address;
import org.teavm.interop.DelegateTo; import org.teavm.interop.DelegateTo;
@ -672,6 +673,11 @@ public class ClassGenerator {
return context.getClassSource(); return context.getClassSource();
} }
@Override
public DependencyInfo getDependencies() {
return context.getDependencies();
}
@Override @Override
public String getParameterName(int index) { public String getParameterName(int index) {
return index == 0 ? "_this_" : "local_" + index; return index == 0 ? "_this_" : "local_" + index;

View File

@ -21,6 +21,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import org.teavm.backend.c.generators.Generator; import org.teavm.backend.c.generators.Generator;
import org.teavm.backend.c.intrinsic.Intrinsic; import org.teavm.backend.c.intrinsic.Intrinsic;
import org.teavm.dependency.DependencyInfo;
import org.teavm.diagnostics.Diagnostics; import org.teavm.diagnostics.Diagnostics;
import org.teavm.model.ClassReaderSource; import org.teavm.model.ClassReaderSource;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
@ -30,6 +31,7 @@ import org.teavm.model.lowlevel.Characteristics;
public class GenerationContext { public class GenerationContext {
private VirtualTableProvider virtualTableProvider; private VirtualTableProvider virtualTableProvider;
private Characteristics characteristics; private Characteristics characteristics;
private DependencyInfo dependencies;
private StringPool stringPool; private StringPool stringPool;
private NameProvider names; private NameProvider names;
private Diagnostics diagnostics; private Diagnostics diagnostics;
@ -39,10 +41,11 @@ public class GenerationContext {
private Map<MethodReference, Intrinsic> intrinsicCache = new HashMap<>(); private Map<MethodReference, Intrinsic> intrinsicCache = new HashMap<>();
public GenerationContext(VirtualTableProvider virtualTableProvider, Characteristics characteristics, public GenerationContext(VirtualTableProvider virtualTableProvider, Characteristics characteristics,
StringPool stringPool, NameProvider names, Diagnostics diagnostics, ClassReaderSource classSource, DependencyInfo dependencies, StringPool stringPool, NameProvider names, Diagnostics diagnostics,
List<Intrinsic> intrinsics, List<Generator> generators) { ClassReaderSource classSource, List<Intrinsic> intrinsics, List<Generator> generators) {
this.virtualTableProvider = virtualTableProvider; this.virtualTableProvider = virtualTableProvider;
this.characteristics = characteristics; this.characteristics = characteristics;
this.dependencies = dependencies;
this.stringPool = stringPool; this.stringPool = stringPool;
this.names = names; this.names = names;
this.diagnostics = diagnostics; this.diagnostics = diagnostics;
@ -63,6 +66,10 @@ public class GenerationContext {
return characteristics; return characteristics;
} }
public DependencyInfo getDependencies() {
return dependencies;
}
public StringPool getStringPool() { public StringPool getStringPool() {
return stringPool; return stringPool;
} }

View File

@ -16,8 +16,12 @@
package org.teavm.backend.c.generators; package org.teavm.backend.c.generators;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import org.teavm.backend.c.generate.CodeWriter; import org.teavm.backend.c.generate.CodeWriter;
import org.teavm.model.ClassReader; import org.teavm.dependency.MethodDependencyInfo;
import org.teavm.dependency.ValueDependencyInfo;
import org.teavm.model.FieldReference; import org.teavm.model.FieldReference;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
import org.teavm.model.ValueType; import org.teavm.model.ValueType;
@ -69,14 +73,19 @@ public class ArrayGenerator implements Generator {
writer.println("switch ((flags >> " + RuntimeClass.PRIMITIVE_SHIFT + ") & " writer.println("switch ((flags >> " + RuntimeClass.PRIMITIVE_SHIFT + ") & "
+ RuntimeClass.PRIMITIVE_MASK + ") {").indent(); + RuntimeClass.PRIMITIVE_MASK + ") {").indent();
MethodDependencyInfo dependency = context.getDependencies().getMethod(new MethodReference(Array.class,
"getImpl", Object.class, int.class, Object.class));
ValueDependencyInfo arrayDependency = dependency.getVariable(1);
Set<String> types = new HashSet<>(Arrays.asList(arrayDependency.getTypes()));
for (int i = 0; i < primitiveWrappers.length; ++i) { for (int i = 0; i < primitiveWrappers.length; ++i) {
String typeName = ValueType.arrayOf(primitiveTypes[i]).toString();
if (!types.contains(typeName)) {
continue;
}
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));
ClassReader cls = context.getClassSource().get(methodRef.getClassName());
if (cls == null || cls.getMethod(methodRef.getDescriptor()) == null) {
continue;
}
String type = CodeWriter.strictTypeAsString(primitiveTypes[i]); String type = CodeWriter.strictTypeAsString(primitiveTypes[i]);
writer.println("case " + primitives[i] + ":").indent(); writer.println("case " + primitives[i] + ":").indent();

View File

@ -16,6 +16,7 @@
package org.teavm.backend.c.generators; package org.teavm.backend.c.generators;
import org.teavm.backend.c.generate.NameProvider; import org.teavm.backend.c.generate.NameProvider;
import org.teavm.dependency.DependencyInfo;
import org.teavm.diagnostics.Diagnostics; import org.teavm.diagnostics.Diagnostics;
import org.teavm.model.ClassReaderSource; import org.teavm.model.ClassReaderSource;
@ -26,5 +27,7 @@ public interface GeneratorContext {
ClassReaderSource getClassSource(); ClassReaderSource getClassSource();
DependencyInfo getDependencies();
String getParameterName(int index); String getParameterName(int index);
} }

View File

@ -794,7 +794,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
} }
} }
return new VirtualTableProvider(classes, virtualMethods); return new VirtualTableProvider(classes, virtualMethods, controller::isVirtual);
} }
@Override @Override

View File

@ -21,6 +21,7 @@ import java.util.LinkedHashMap;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.function.Predicate;
import org.teavm.model.ClassReader; import org.teavm.model.ClassReader;
import org.teavm.model.ClassReaderSource; import org.teavm.model.ClassReaderSource;
import org.teavm.model.ElementModifier; import org.teavm.model.ElementModifier;
@ -35,7 +36,8 @@ public class VirtualTableProvider {
private Map<String, VirtualTable> virtualTables = new LinkedHashMap<>(); private Map<String, VirtualTable> virtualTables = new LinkedHashMap<>();
private InterfaceToClassMapping interfaceMapping; private InterfaceToClassMapping interfaceMapping;
public VirtualTableProvider(ListableClassReaderSource classSource, Set<MethodReference> virtualMethods) { public VirtualTableProvider(ListableClassReaderSource classSource, Set<MethodReference> virtualMethods,
Predicate<MethodReference> methodCalledVirtually) {
this.classSource = classSource; this.classSource = classSource;
interfaceMapping = new InterfaceToClassMapping(classSource); interfaceMapping = new InterfaceToClassMapping(classSource);
@ -50,11 +52,11 @@ public class VirtualTableProvider {
} }
for (String className : classNames) { for (String className : classNames) {
fillClass(className); fillClass(className, methodCalledVirtually);
} }
} }
private void fillClass(String className) { private void fillClass(String className, Predicate<MethodReference> methodCalledVirtually) {
if (virtualTables.containsKey(className)) { if (virtualTables.containsKey(className)) {
return; return;
} }
@ -66,7 +68,7 @@ public class VirtualTableProvider {
return; return;
} }
if (cls.getParent() != null) { if (cls.getParent() != null) {
fillClass(cls.getParent()); fillClass(cls.getParent(), methodCalledVirtually);
VirtualTable parentTable = virtualTables.get(cls.getParent()); VirtualTable parentTable = virtualTables.get(cls.getParent());
for (VirtualTableEntry parentEntry : parentTable.entries.values()) { for (VirtualTableEntry parentEntry : parentTable.entries.values()) {
VirtualTableEntry entry = new VirtualTableEntry(table, parentEntry.getMethod(), VirtualTableEntry entry = new VirtualTableEntry(table, parentEntry.getMethod(),
@ -84,6 +86,9 @@ public class VirtualTableProvider {
MethodReference implementationRef = implementation != null MethodReference implementationRef = implementation != null
? implementation.getReference() ? implementation.getReference()
: null; : null;
if (implementationRef != null && !methodCalledVirtually.test(implementationRef)) {
implementationRef = null;
}
table.entries.put(method, new VirtualTableEntry(table, method, implementationRef, table.entries.put(method, new VirtualTableEntry(table, method, implementationRef,
table.entries.size())); table.entries.size()));
} }
@ -95,7 +100,7 @@ public class VirtualTableProvider {
continue; continue;
} }
VirtualTableEntry entry = table.entries.get(method.getDescriptor()); VirtualTableEntry entry = table.entries.get(method.getDescriptor());
if (entry != null) { if (entry != null && methodCalledVirtually.test(method.getReference())) {
entry.implementor = method.getReference(); entry.implementor = method.getReference();
} }
} }

View File

@ -812,6 +812,11 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
+ compileProgressReportStart; + compileProgressReportStart;
return progressListener.progressReached(progress); return progressListener.progressReached(progress);
} }
@Override
public void addVirtualMethods(Predicate<MethodReference> methods) {
TeaVM.this.addVirtualMethods(methods);
}
}; };
class PostProcessingClassHolderSource implements ListableClassHolderSource { class PostProcessingClassHolderSource implements ListableClassHolderSource {

View File

@ -18,6 +18,7 @@ package org.teavm.vm;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.Set;
import java.util.function.Predicate;
import org.teavm.cache.CacheStatus; import org.teavm.cache.CacheStatus;
import org.teavm.common.ServiceRepository; import org.teavm.common.ServiceRepository;
import org.teavm.dependency.DependencyInfo; import org.teavm.dependency.DependencyInfo;
@ -51,4 +52,6 @@ public interface TeaVMTargetController {
boolean isVirtual(MethodReference method); boolean isVirtual(MethodReference method);
TeaVMProgressFeedback reportProgress(int progress); TeaVMProgressFeedback reportProgress(int progress);
void addVirtualMethods(Predicate<MethodReference> methods);
} }

View File

@ -226,6 +226,7 @@ public final class Platform {
} }
@Unmanaged @Unmanaged
@PluggableDependency(PlatformGenerator.class)
public static String getName(PlatformClass cls) { public static String getName(PlatformClass cls) {
return cls.getMetadata().getName(); return cls.getMetadata().getName();
} }

View File

@ -59,6 +59,9 @@ public class PlatformGenerator implements Generator, Injector, DependencyPlugin
case "getEnumConstants": case "getEnumConstants":
method.getResult().propagate(agent.getType("[Ljava/lang/Enum;")); method.getResult().propagate(agent.getType("[Ljava/lang/Enum;"));
break; break;
case "getName":
method.getResult().propagate(agent.getType("java.lang.String"));
break;
} }
} }