C: fix bugs in RTTI. Support args parameter of main method

This commit is contained in:
Alexey Andreev 2019-04-04 17:20:28 +03:00
parent 56cb14e30c
commit ec8bae1d40
14 changed files with 304 additions and 82 deletions

View File

@ -206,7 +206,11 @@ public class TDouble extends TNumber implements TComparable<TDouble> {
@Override @Override
public int hashCode() { public int hashCode() {
long h = doubleToLongBits(value); return hashCode(value);
}
public static int hashCode(double d) {
long h = doubleToLongBits(d);
return (int) (h >>> 32) ^ (int) h; return (int) (h >>> 32) ^ (int) h;
} }

View File

@ -87,7 +87,11 @@ public class TFloat extends TNumber implements TComparable<TFloat> {
@Override @Override
public int hashCode() { public int hashCode() {
return floatToIntBits(value); return hashCode(value);
}
public static int hashCode(float f) {
return floatToIntBits(f);
} }
@JSBody(params = "v", script = "return isNaN(v);") @JSBody(params = "v", script = "return isNaN(v);")

View File

@ -38,6 +38,7 @@ import org.teavm.ast.decompilation.Decompiler;
import org.teavm.backend.c.analyze.CDependencyListener; import org.teavm.backend.c.analyze.CDependencyListener;
import org.teavm.backend.c.generate.BufferedCodeWriter; import org.teavm.backend.c.generate.BufferedCodeWriter;
import org.teavm.backend.c.generate.ClassGenerator; import org.teavm.backend.c.generate.ClassGenerator;
import org.teavm.backend.c.generate.CodeGenerationVisitor;
import org.teavm.backend.c.generate.CodeGeneratorUtil; import org.teavm.backend.c.generate.CodeGeneratorUtil;
import org.teavm.backend.c.generate.CodeWriter; import org.teavm.backend.c.generate.CodeWriter;
import org.teavm.backend.c.generate.GenerationContext; import org.teavm.backend.c.generate.GenerationContext;
@ -63,6 +64,7 @@ import org.teavm.backend.c.intrinsic.PlatformObjectIntrinsic;
import org.teavm.backend.c.intrinsic.RuntimeClassIntrinsic; import org.teavm.backend.c.intrinsic.RuntimeClassIntrinsic;
import org.teavm.backend.c.intrinsic.ShadowStackIntrinsic; import org.teavm.backend.c.intrinsic.ShadowStackIntrinsic;
import org.teavm.backend.c.intrinsic.StructureIntrinsic; import org.teavm.backend.c.intrinsic.StructureIntrinsic;
import org.teavm.backend.lowlevel.dependency.ExceptionHandlingDependencyListener;
import org.teavm.backend.lowlevel.transform.CoroutineTransformation; import org.teavm.backend.lowlevel.transform.CoroutineTransformation;
import org.teavm.dependency.ClassDependency; import org.teavm.dependency.ClassDependency;
import org.teavm.dependency.DependencyAnalyzer; import org.teavm.dependency.DependencyAnalyzer;
@ -71,6 +73,7 @@ import org.teavm.interop.Address;
import org.teavm.interop.PlatformMarkers; import org.teavm.interop.PlatformMarkers;
import org.teavm.interop.Structure; import org.teavm.interop.Structure;
import org.teavm.model.BasicBlock; import org.teavm.model.BasicBlock;
import org.teavm.model.ClassHierarchy;
import org.teavm.model.ClassHolder; import org.teavm.model.ClassHolder;
import org.teavm.model.ClassHolderTransformer; import org.teavm.model.ClassHolderTransformer;
import org.teavm.model.ClassReader; import org.teavm.model.ClassReader;
@ -116,6 +119,9 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
private static final Set<MethodReference> VIRTUAL_METHODS = new HashSet<>(Arrays.asList( private static final Set<MethodReference> VIRTUAL_METHODS = new HashSet<>(Arrays.asList(
new MethodReference(Object.class, "clone", Object.class) new MethodReference(Object.class, "clone", Object.class)
)); ));
private static final MethodReference STRING_CONSTRUCTOR = new MethodReference(String.class,
"<init>", char[].class, void.class);
private TeaVMTargetController controller; private TeaVMTargetController controller;
private ClassInitializerEliminator classInitializerEliminator; private ClassInitializerEliminator classInitializerEliminator;
private ClassInitializerTransformer classInitializerTransformer; private ClassInitializerTransformer classInitializerTransformer;
@ -196,6 +202,10 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
dependencyAnalyzer.linkClass("java.lang.String"); dependencyAnalyzer.linkClass("java.lang.String");
dependencyAnalyzer.linkClass("java.lang.Class"); dependencyAnalyzer.linkClass("java.lang.Class");
dependencyAnalyzer.linkField(new FieldReference("java.lang.String", "hashCode")); dependencyAnalyzer.linkField(new FieldReference("java.lang.String", "hashCode"));
dependencyAnalyzer.linkMethod(STRING_CONSTRUCTOR)
.propagate(0, "java.lang.String")
.propagate(1, "[C")
.use();
ClassDependency runtimeClassDep = dependencyAnalyzer.linkClass(RuntimeClass.class.getName()); ClassDependency runtimeClassDep = dependencyAnalyzer.linkClass(RuntimeClass.class.getName());
ClassDependency runtimeObjectDep = dependencyAnalyzer.linkClass(RuntimeObject.class.getName()); ClassDependency runtimeObjectDep = dependencyAnalyzer.linkClass(RuntimeObject.class.getName());
@ -209,7 +219,7 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
dependencyAnalyzer.linkMethod(new MethodReference(Fiber.class, "isResuming", boolean.class)).use(); dependencyAnalyzer.linkMethod(new MethodReference(Fiber.class, "isResuming", boolean.class)).use();
dependencyAnalyzer.linkMethod(new MethodReference(Fiber.class, "isSuspending", boolean.class)).use(); dependencyAnalyzer.linkMethod(new MethodReference(Fiber.class, "isSuspending", boolean.class)).use();
dependencyAnalyzer.linkMethod(new MethodReference(Fiber.class, "current", Fiber.class)).use(); dependencyAnalyzer.linkMethod(new MethodReference(Fiber.class, "current", Fiber.class)).use();
dependencyAnalyzer.linkMethod(new MethodReference(Fiber.class, "startMain", void.class)).use(); dependencyAnalyzer.linkMethod(new MethodReference(Fiber.class, "startMain", String[].class, void.class)).use();
dependencyAnalyzer.linkMethod(new MethodReference(EventQueue.class, "process", void.class)).use(); dependencyAnalyzer.linkMethod(new MethodReference(EventQueue.class, "process", void.class)).use();
dependencyAnalyzer.linkMethod(new MethodReference(Thread.class, "setCurrentThread", Thread.class, dependencyAnalyzer.linkMethod(new MethodReference(Thread.class, "setCurrentThread", Thread.class,
void.class)).use(); void.class)).use();
@ -220,6 +230,8 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
dependencyAnalyzer.linkMethod(method.getReference()).use(); dependencyAnalyzer.linkMethod(method.getReference()).use();
} }
} }
dependencyAnalyzer.addDependencyListener(new ExceptionHandlingDependencyListener());
} }
@Override @Override
@ -249,7 +261,8 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
@Override @Override
public void emit(ListableClassHolderSource classes, BuildTarget buildTarget, String outputName) throws IOException { public void emit(ListableClassHolderSource classes, BuildTarget buildTarget, String outputName) throws IOException {
VirtualTableProvider vtableProvider = createVirtualTableProvider(classes); VirtualTableProvider vtableProvider = createVirtualTableProvider(classes);
TagRegistry tagRegistry = new TagRegistry(classes); ClassHierarchy hierarchy = new ClassHierarchy(classes);
TagRegistry tagRegistry = new TagRegistry(classes, hierarchy);
StringPool stringPool = new StringPool(); StringPool stringPool = new StringPool();
Decompiler decompiler = new Decompiler(classes, new HashSet<>(), false, true); Decompiler decompiler = new Decompiler(classes, new HashSet<>(), false, true);
@ -404,6 +417,8 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
private void generateSpecialFunctions(GenerationContext context, CodeWriter writer) { private void generateSpecialFunctions(GenerationContext context, CodeWriter writer) {
generateThrowCCE(context, writer); generateThrowCCE(context, writer);
generateAllocateStringArray(context, writer); generateAllocateStringArray(context, writer);
generateAllocateCharArray(context, writer);
generateCreateString(context, writer);
} }
private void generateThrowCCE(GenerationContext context, CodeWriter writer) { private void generateThrowCCE(GenerationContext context, CodeWriter writer) {
@ -425,6 +440,25 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
writer.outdent().println("}"); writer.outdent().println("}");
} }
private void generateAllocateCharArray(GenerationContext context, CodeWriter writer) {
writer.println("static JavaArray* teavm_allocateCharArray(int32_t size) {").indent();
String allocateArrayName = context.getNames().forMethod(new MethodReference(Allocator.class,
"allocateArray", RuntimeClass.class, int.class, Address.class));
String charClassName = context.getNames().forClassInstance(ValueType.arrayOf(ValueType.CHARACTER));
writer.println("return (JavaArray*) " + allocateArrayName + "(&" + charClassName + ", size);");
writer.outdent().println("}");
}
private void generateCreateString(GenerationContext context, CodeWriter writer) {
NameProvider names = context.getNames();
writer.println("static JavaString* teavm_createString(JavaArray* array) {").indent();
writer.print("JavaString* str = (JavaString*) ").print(names.forMethod(CodeGenerationVisitor.ALLOC_METHOD))
.print("(&").print(names.forClassInstance(ValueType.object("java.lang.String"))).println(");");
writer.print(names.forMethod(STRING_CONSTRUCTOR)).println("(str, array);");
writer.println("return str;");
writer.outdent().println("}");
}
private void generateArrayOfClassReferences(GenerationContext context, CodeWriter writer, private void generateArrayOfClassReferences(GenerationContext context, CodeWriter writer,
List<? extends ValueType> types) { List<? extends ValueType> types) {
writer.print("static JavaClass* teavm_classReferences[" + types.size() + "] = {").indent(); writer.print("static JavaClass* teavm_classReferences[" + types.size() + "] = {").indent();
@ -512,9 +546,10 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
} }
private void generateFiberStart(GenerationContext context, CodeWriter writer) { private void generateFiberStart(GenerationContext context, CodeWriter writer) {
String startName = context.getNames().forMethod(new MethodReference(Fiber.class, "startMain", void.class)); String startName = context.getNames().forMethod(new MethodReference(Fiber.class,
"startMain", String[].class, void.class));
String processName = context.getNames().forMethod(new MethodReference(EventQueue.class, "process", void.class)); String processName = context.getNames().forMethod(new MethodReference(EventQueue.class, "process", void.class));
writer.println(startName + "();"); writer.println(startName + "(teavm_parseArguments(argc, argv));");
writer.println(processName + "();"); writer.println(processName + "();");
} }
@ -537,7 +572,7 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
public void apply(IntrinsicContext context, InvocationExpr invocation) { public void apply(IntrinsicContext context, InvocationExpr invocation) {
switch (invocation.getMethod().getName()) { switch (invocation.getMethod().getName()) {
case "runMain": case "runMain":
generateCallToMainMethod(context.names(), context.writer()); generateCallToMainMethod(context, invocation);
break; break;
case "setCurrentThread": case "setCurrentThread":
String methodName = context.names().forMethod(new MethodReference(Thread.class, String methodName = context.names().forMethod(new MethodReference(Thread.class,
@ -550,11 +585,14 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
} }
} }
private void generateCallToMainMethod(NameProvider names, CodeWriter writer) { private void generateCallToMainMethod(IntrinsicContext context, InvocationExpr invocation) {
NameProvider names = context.names();
TeaVMEntryPoint entryPoint = controller.getEntryPoints().get("main"); TeaVMEntryPoint entryPoint = controller.getEntryPoints().get("main");
if (entryPoint != null) { if (entryPoint != null) {
String mainMethod = names.forMethod(entryPoint.getMethod()); String mainMethod = names.forMethod(entryPoint.getMethod());
writer.println(mainMethod + "(NULL);"); context.writer().print(mainMethod + "(");
context.emit(invocation.getArguments().get(0));
context.writer().println(");");
} }
} }

View File

@ -118,6 +118,7 @@ public class ClassGenerator {
public void generateClass(ClassHolder cls) { public void generateClass(ClassHolder cls) {
generateClassStructure(cls); generateClassStructure(cls);
generateClassStaticFields(cls);
generateClassMethods(cls); generateClassMethods(cls);
generateInitializer(cls); generateInitializer(cls);
} }
@ -230,7 +231,6 @@ public class ClassGenerator {
String name = context.getNames().forClass(cls.getName()); String name = context.getNames().forClass(cls.getName());
CodeWriter structWriter = structuresWriter.fragment(); CodeWriter structWriter = structuresWriter.fragment();
CodeWriter fieldsWriter = structuresWriter.fragment();
structWriter.print("typedef struct ").print(name).println(" {").indent(); structWriter.print("typedef struct ").print(name).println(" {").indent();
@ -244,38 +244,19 @@ public class ClassGenerator {
int layoutIndex = currentLayoutIndex; int layoutIndex = currentLayoutIndex;
FieldReference[] staticFields = new FieldReference[cls.getFields().size()];
int staticIndex = 0;
FieldReference[] instanceFields = new FieldReference[cls.getFields().size()]; FieldReference[] instanceFields = new FieldReference[cls.getFields().size()];
int instanceIndex = 0; int instanceIndex = 0;
for (FieldHolder field : cls.getFields()) { for (FieldHolder field : cls.getFields()) {
if (field.hasModifier(ElementModifier.STATIC)) { if (field.hasModifier(ElementModifier.STATIC)) {
String fieldName = context.getNames().forStaticField(field.getReference()); continue;
fieldsWriter.print("static ").printStrictType(field.getType()).print(" ").print(fieldName) }
.println(";"); String fieldName = context.getNames().forMemberField(field.getReference());
if (isReferenceType(field.getType())) { structWriter.printStrictType(field.getType()).print(" ").print(fieldName).println(";");
staticFields[staticIndex++] = field.getReference(); if (isReferenceType(field.getType())) {
} instanceFields[instanceIndex++] = field.getReference();
Object initialValue = field.getInitialValue();
if (initialValue == null) {
initialValue = getDefaultValue(field.getType());
}
staticFieldInitWriter.print(fieldName + " = ");
CodeGeneratorUtil.writeValue(staticFieldInitWriter, context, initialValue);
staticFieldInitWriter.println(";");
} else {
String fieldName = context.getNames().forMemberField(field.getReference());
structWriter.printStrictType(field.getType()).print(" ").print(fieldName).println(";");
if (isReferenceType(field.getType())) {
instanceFields[instanceIndex++] = field.getReference();
}
} }
} }
if (staticIndex > 0) {
staticGcRoots.add(Arrays.copyOf(staticFields, staticIndex));
}
if (instanceIndex > 0) { if (instanceIndex > 0) {
classLayoutOffsets.put(cls.getName(), layoutIndex); classLayoutOffsets.put(cls.getName(), layoutIndex);
layouts.add(Arrays.copyOf(instanceFields, instanceIndex)); layouts.add(Arrays.copyOf(instanceFields, instanceIndex));
@ -285,6 +266,36 @@ public class ClassGenerator {
structWriter.outdent().print("} ").print(name).println(";"); structWriter.outdent().print("} ").print(name).println(";");
} }
private void generateClassStaticFields(ClassHolder cls) {
CodeWriter fieldsWriter = structuresWriter.fragment();
FieldReference[] staticFields = new FieldReference[cls.getFields().size()];
int staticIndex = 0;
for (FieldHolder field : cls.getFields()) {
if (!field.hasModifier(ElementModifier.STATIC)) {
continue;
}
String fieldName = context.getNames().forStaticField(field.getReference());
fieldsWriter.print("static ").printStrictType(field.getType()).print(" ").print(fieldName)
.println(";");
if (isReferenceType(field.getType())) {
staticFields[staticIndex++] = field.getReference();
}
Object initialValue = field.getInitialValue();
if (initialValue == null) {
initialValue = getDefaultValue(field.getType());
}
staticFieldInitWriter.print(fieldName + " = ");
CodeGeneratorUtil.writeValue(staticFieldInitWriter, context, initialValue);
staticFieldInitWriter.println(";");
}
if (staticIndex > 0) {
staticGcRoots.add(Arrays.copyOf(staticFields, staticIndex));
}
}
private static Object getDefaultValue(ValueType type) { private static Object getDefaultValue(ValueType type) {
if (type instanceof ValueType.Primitive) { if (type instanceof ValueType.Primitive) {
ValueType.Primitive primitive = (ValueType.Primitive) type; ValueType.Primitive primitive = (ValueType.Primitive) type;

View File

@ -78,7 +78,7 @@ import org.teavm.runtime.RuntimeClass;
import org.teavm.runtime.RuntimeObject; import org.teavm.runtime.RuntimeObject;
public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor { public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor {
private static final MethodReference ALLOC_METHOD = new MethodReference(Allocator.class, public static final MethodReference ALLOC_METHOD = new MethodReference(Allocator.class,
"allocate", RuntimeClass.class, Address.class); "allocate", RuntimeClass.class, Address.class);
private static final MethodReference ALLOC_ARRAY_METHOD = new MethodReference(Allocator.class, private static final MethodReference ALLOC_ARRAY_METHOD = new MethodReference(Allocator.class,
"allocateArray", RuntimeClass.class, int.class, Address.class); "allocateArray", RuntimeClass.class, int.class, Address.class);

View File

@ -0,0 +1,49 @@
/*
* Copyright 2019 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.backend.lowlevel.dependency;
import org.teavm.dependency.AbstractDependencyListener;
import org.teavm.dependency.DependencyAgent;
import org.teavm.dependency.DependencyNode;
import org.teavm.dependency.DependencyType;
import org.teavm.dependency.MethodDependency;
import org.teavm.model.FieldReference;
import org.teavm.model.MethodReference;
public class ExceptionHandlingDependencyListener extends AbstractDependencyListener {
private static final MethodReference FILL_IN_STACK_TRACE = new MethodReference(Throwable.class,
"fillInStackTrace", Throwable.class);
private static final FieldReference STACK_TRACE = new FieldReference(Throwable.class.getName(), "stackTrace");
private static final MethodReference STACK_TRACE_ELEMENT_INIT = new MethodReference(StackTraceElement.class,
"<init>", String.class, String.class, String.class, int.class, void.class);
@Override
public void methodReached(DependencyAgent agent, MethodDependency method) {
if (method.getReference().equals(FILL_IN_STACK_TRACE)) {
DependencyNode node = agent.linkField(STACK_TRACE).getValue();
node.propagate(agent.getType("[java/lang.StackTraceElement;"));
node.getArrayItem().propagate(agent.getType("java.lang.StackTraceElement"));
MethodDependency initElem = agent.linkMethod(STACK_TRACE_ELEMENT_INIT);
initElem.use();
DependencyType stringType = agent.getType("java.lang.String");
initElem.propagate(0, agent.getType(STACK_TRACE_ELEMENT_INIT.getClassName()));
initElem.propagate(1, stringType);
initElem.propagate(2, stringType);
initElem.propagate(3, stringType);
}
}
}

View File

@ -104,6 +104,7 @@ import org.teavm.interop.StaticInit;
import org.teavm.model.AnnotationHolder; import org.teavm.model.AnnotationHolder;
import org.teavm.model.BasicBlock; import org.teavm.model.BasicBlock;
import org.teavm.model.CallLocation; import org.teavm.model.CallLocation;
import org.teavm.model.ClassHierarchy;
import org.teavm.model.ClassHolder; import org.teavm.model.ClassHolder;
import org.teavm.model.ClassHolderTransformer; import org.teavm.model.ClassHolderTransformer;
import org.teavm.model.ClassReader; import org.teavm.model.ClassReader;
@ -314,7 +315,8 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
WasmFunction initFunction = new WasmFunction("__start__"); WasmFunction initFunction = new WasmFunction("__start__");
VirtualTableProvider vtableProvider = createVirtualTableProvider(classes); VirtualTableProvider vtableProvider = createVirtualTableProvider(classes);
TagRegistry tagRegistry = new TagRegistry(classes); ClassHierarchy hierarchy = new ClassHierarchy(classes);
TagRegistry tagRegistry = new TagRegistry(classes, hierarchy);
BinaryWriter binaryWriter = new BinaryWriter(256); BinaryWriter binaryWriter = new BinaryWriter(256);
NameProvider names = new NameProvider(controller.getUnprocessedClassSource()); NameProvider names = new NameProvider(controller.getUnprocessedClassSource());
WasmClassGenerator classGenerator = new WasmClassGenerator(classes, controller.getUnprocessedClassSource(), WasmClassGenerator classGenerator = new WasmClassGenerator(classes, controller.getUnprocessedClassSource(),

View File

@ -26,15 +26,15 @@ import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.teavm.model.ClassHierarchy;
import org.teavm.model.ClassReader; import org.teavm.model.ClassReader;
import org.teavm.model.ClassReaderSource;
import org.teavm.model.ElementModifier; import org.teavm.model.ElementModifier;
import org.teavm.model.ListableClassReaderSource; import org.teavm.model.ListableClassReaderSource;
public class TagRegistry { public class TagRegistry {
private Map<String, List<Range>> ranges = new HashMap<>(); private Map<String, List<Range>> ranges = new HashMap<>();
public TagRegistry(ListableClassReaderSource classSource) { public TagRegistry(ListableClassReaderSource classSource, ClassHierarchy classHierarchy) {
List<String> roots = new ArrayList<>(); List<String> roots = new ArrayList<>();
Map<String, Set<String>> implementedBy = new HashMap<>(); Map<String, Set<String>> implementedBy = new HashMap<>();
@ -45,8 +45,7 @@ public class TagRegistry {
continue; continue;
} }
for (String iface : cls.getInterfaces()) { for (String iface : cls.getInterfaces()) {
String topmostImplementor = findTopmostImplementor(classSource, className, iface); markImplementor(classHierarchy, className, iface, implementedBy);
markImplementor(classSource, topmostImplementor, iface, implementedBy);
} }
if (cls.getParent() == null || cls.getParent().equals(cls.getName())) { if (cls.getParent() == null || cls.getParent().equals(cls.getName())) {
roots.add(className); roots.add(className);
@ -58,8 +57,7 @@ public class TagRegistry {
Map<String, Range> simpleRanges = new HashMap<>(); Map<String, Range> simpleRanges = new HashMap<>();
int current = 0; int current = 0;
for (String root : roots) { for (String root : roots) {
assignRange(current, hierarchy, root, simpleRanges); current = 1 + assignRange(current, hierarchy, root, simpleRanges);
++current;
} }
for (String className : classSource.getClassNames()) { for (String className : classSource.getClassNames()) {
@ -71,7 +69,7 @@ public class TagRegistry {
Set<String> implementorRoots = implementedBy.get(cls.getName()); Set<String> implementorRoots = implementedBy.get(cls.getName());
if (implementorRoots != null) { if (implementorRoots != null) {
List<Range> ifaceRanges = implementorRoots.stream() List<Range> ifaceRanges = implementorRoots.stream()
.map(implementor -> simpleRanges.get(implementor)) .map(simpleRanges::get)
.filter(Objects::nonNull) .filter(Objects::nonNull)
.sorted(Comparator.comparing(range -> range.lower)) .sorted(Comparator.comparing(range -> range.lower))
.collect(Collectors.toList()); .collect(Collectors.toList());
@ -86,37 +84,40 @@ public class TagRegistry {
} }
} }
} }
} }
private String findTopmostImplementor(ClassReaderSource classSource, String className, String ifaceName) { private String findTopmostImplementor(ClassHierarchy hierarchy, String className, String ifaceName) {
ClassReader cls = classSource.get(className); ClassReader cls = hierarchy.getClassSource().get(className);
if (cls == null) { if (cls == null) {
return null; return null;
} }
if (cls.getParent() != null) { if (cls.getParent() != null) {
String candidate = findTopmostImplementor(classSource, cls.getParent(), ifaceName); String candidate = findTopmostImplementor(hierarchy, cls.getParent(), ifaceName);
if (candidate != null) { if (candidate != null) {
return candidate; return candidate;
} }
} }
return cls.getInterfaces().contains(ifaceName) ? className : null; return hierarchy.isSuperType(ifaceName, className, false) ? className : null;
} }
private void markImplementor(ClassReaderSource classSource, String className, String ifaceName, private void markImplementor(ClassHierarchy hierarchy, String className, String ifaceName,
Map<String, Set<String>> implementedBy) { Map<String, Set<String>> implementedBy) {
className = findTopmostImplementor(hierarchy, className, ifaceName);
if (!implementedBy.computeIfAbsent(ifaceName, key -> new LinkedHashSet<>()).add(className)) { if (!implementedBy.computeIfAbsent(ifaceName, key -> new LinkedHashSet<>()).add(className)) {
return; return;
} }
ClassReader iface = classSource.get(ifaceName); ClassReader iface = hierarchy.getClassSource().get(ifaceName);
if (iface == null) { if (iface == null) {
return; return;
} }
for (String superIface : iface.getInterfaces()) { for (String superIface : iface.getInterfaces()) {
markImplementor(classSource, className, superIface, implementedBy); markImplementor(hierarchy, className, superIface, implementedBy);
} }
} }

View File

@ -115,9 +115,11 @@ public class RegisterAllocator {
case FLOAT: case FLOAT:
return 2; return 2;
case DOUBLE: case DOUBLE:
return 2;
default:
return 3; return 3;
case OBJECT:
return 4;
default:
return 5;
} }
} }

View File

@ -213,11 +213,11 @@ public class Fiber {
new Fiber(runner, daemon).start(); new Fiber(runner, daemon).start();
} }
static void startMain() { static void startMain(String[] args) {
start(Fiber::runMain, false); start(() -> runMain(args), false);
} }
static native void runMain(); static native void runMain(String[] args);
private void start() { private void start() {
Fiber former = current; Fiber former = current;

View File

@ -52,38 +52,37 @@ static JavaArray* teavm_resourceMapKeys(TeaVM_ResourceMap *map) {
return array; return array;
} }
static inline int teavm_isHighSurrogate(char16_t c) {
return (c & 0xFC00) == 0xD800;
}
static inline int teavm_isLowSurrogate(char16_t c) {
return (c & 0xFC00) == 0xDC00;
}
static inline int teavm_isSurrogatePair(char16_t* chars, int32_t index, int32_t limit) {
return index < limit - 1 && teavm_isHighSurrogate(chars[index]) && teavm_isLowSurrogate(chars[index + 1]);
}
static inline int teavm_getCodePoint(char16_t* chars, int32_t *index, int32_t limit) {
wchar_t codePoint;
if (teavm_isSurrogatePair(chars, *index, limit)) {
codePoint = (wchar_t) (((((chars[*index] & 0x03FF) << 10) | chars[*index + 1] & 0x03FF)) + 0x010000);
(*index)++;
} else {
codePoint = (wchar_t) chars[*index];
}
return codePoint;
}
static size_t teavm_mbSize(char16_t* javaChars, int32_t javaCharsCount) { static size_t teavm_mbSize(char16_t* javaChars, int32_t javaCharsCount) {
size_t sz = 0; size_t sz = 0;
char buffer[6]; char buffer[__STDC_UTF_16__];
mbstate_t state = {0};
for (int32_t i = 0; i < javaCharsCount; ++i) { for (int32_t i = 0; i < javaCharsCount; ++i) {
sz += wctomb(buffer, teavm_getCodePoint(javaChars, &i, javaCharsCount)); size_t result = c16rtomb(buffer, javaChars[i], &state);
if (result < 0) {
break;
}
sz += result;
} }
return sz; return sz;
} }
static int32_t teavm_c16Size(char* cstring, size_t count) {
mbstate_t state = {0};
int32_t sz = 0;
while (count > 0) {
size_t result = mbrtoc16(NULL, cstring, count, &state);
if (result == -1) {
break;
} else if (result >= 0) {
sz++;
count -= result;
cstring += result;
}
}
return sz;
}
static char* teavm_stringToC(void* obj) { static char* teavm_stringToC(void* obj) {
if (obj == NULL) { if (obj == NULL) {
return NULL; return NULL;
@ -98,15 +97,47 @@ static char* teavm_stringToC(void* obj) {
int32_t j = 0; int32_t j = 0;
char* dst = result; char* dst = result;
mbstate_t state = {0};
for (int32_t i = 0; i < charArray->size; ++i) { for (int32_t i = 0; i < charArray->size; ++i) {
dst += wctomb(dst, teavm_getCodePoint(javaChars, &i, charArray->size)); dst += c16rtomb(dst, javaChars[i], &state);
} }
*dst = '\0'; *dst = '\0';
return result; return result;
} }
static JavaString* teavm_cToString(char* cstring) {
if (cstring == NULL) {
return NULL;
}
size_t clen = strlen(cstring);
int32_t size = teavm_c16Size(cstring, clen);
JavaArray* charArray = teavm_allocateCharArray(size);
char16_t* javaChars = ARRAY_DATA(charArray, char16_t);
mbstate_t state = {0};
for (int32_t i = 0; i < size; ++i) {
int32_t result = mbrtoc16(javaChars++, cstring, clen, &state);
if (result == -1) {
break;
} else if (result >= 0) {
clen -= result;
cstring += result;
}
}
return teavm_createString(charArray);
}
static inline void teavm_free(void* s) { static inline void teavm_free(void* s) {
if (s != NULL) { if (s != NULL) {
free(s); free(s);
} }
} }
static JavaArray* teavm_parseArguments(int argc, char** argv) {
JavaArray* array = teavm_allocateStringArray(argc - 1);
JavaString** arrayData = ARRAY_DATA(array, JavaString*);
for (int i = 1; i < argc; ++i) {
arrayData[i - 1] = teavm_cToString(argv[i]);
}
return array;
}

View File

@ -141,6 +141,8 @@ typedef struct {
static int32_t teavm_hashCode(JavaString*); static int32_t teavm_hashCode(JavaString*);
static int32_t teavm_equals(JavaString*, JavaString*); static int32_t teavm_equals(JavaString*, JavaString*);
static JavaArray* teavm_allocateStringArray(int32_t size); static JavaArray* teavm_allocateStringArray(int32_t size);
static JavaArray* teavm_allocateCharArray(int32_t size);
static JavaString* teavm_createString(JavaArray* chars);
static TeaVM_ResourceMapEntry* teavm_lookupResource(TeaVM_ResourceMap *map, JavaString* string) { static TeaVM_ResourceMapEntry* teavm_lookupResource(TeaVM_ResourceMap *map, JavaString* string) {
uint32_t hashCode = teavm_hashCode(string); uint32_t hashCode = teavm_hashCode(string);

View File

@ -15,6 +15,7 @@
*/ */
package org.teavm.samples.benchmark.teavm; package org.teavm.samples.benchmark.teavm;
import java.util.Arrays;
import org.jbox2d.collision.shapes.CircleShape; import org.jbox2d.collision.shapes.CircleShape;
import org.jbox2d.collision.shapes.PolygonShape; import org.jbox2d.collision.shapes.PolygonShape;
import org.jbox2d.collision.shapes.Shape; import org.jbox2d.collision.shapes.Shape;
@ -42,6 +43,8 @@ public final class Gtk3BenchmarkStarter {
} }
public static void main(String[] args) { public static void main(String[] args) {
System.out.println(Arrays.asList(args));
Gtk.init(null, null); Gtk.init(null, null);
Gtk.Window window = Gtk.windowNew(Gtk.WINDOW_TOPLEVEL); Gtk.Window window = Gtk.windowNew(Gtk.WINDOW_TOPLEVEL);
GLib.signalConnect(window, "delete-event", GLib.signalConnect(window, "delete-event",

View File

@ -0,0 +1,75 @@
/*
* Copyright 2019 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.vm;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.teavm.junit.TeaVMTestRunner;
@RunWith(TeaVMTestRunner.class)
public class RttiTest {
@Test
public void instanceOfInterface() {
checkImplements(new A(), true, false, false);
checkImplements(new B(), false, true, true);
checkImplements(new C(), false, true, false);
checkImplements(new D(), false, true, true);
checkImplements(new E(), true, false, false);
checkImplements(new F(), false, true, true);
checkImplements(new G(), true, true, false);
}
private void checkImplements(Object o, boolean i, boolean j, boolean k) {
assertTrue(predicate(o, i, "I"), !i ^ o instanceof I);
assertTrue(predicate(o, j, "J"), !j ^ o instanceof J);
assertTrue(predicate(o, k, "K"), !k ^ o instanceof K);
}
private String predicate(Object o, boolean b, String name) {
return o.getClass().getName() + " should" + (b ? " not" : "") + " implement " + name;
}
static class A implements I {
}
static class B implements K {
}
static class C implements J {
}
static class D extends C implements K {
}
static class E extends A implements I {
}
static class F extends B implements J {
}
static class G extends C implements I {
}
interface I {
}
interface J {
}
interface K extends J {
}
}