mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
C: fix bugs in RTTI. Support args parameter of main method
This commit is contained in:
parent
56cb14e30c
commit
ec8bae1d40
|
@ -206,7 +206,11 @@ public class TDouble extends TNumber implements TComparable<TDouble> {
|
|||
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -87,7 +87,11 @@ public class TFloat extends TNumber implements TComparable<TFloat> {
|
|||
|
||||
@Override
|
||||
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);")
|
||||
|
|
|
@ -38,6 +38,7 @@ import org.teavm.ast.decompilation.Decompiler;
|
|||
import org.teavm.backend.c.analyze.CDependencyListener;
|
||||
import org.teavm.backend.c.generate.BufferedCodeWriter;
|
||||
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.CodeWriter;
|
||||
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.ShadowStackIntrinsic;
|
||||
import org.teavm.backend.c.intrinsic.StructureIntrinsic;
|
||||
import org.teavm.backend.lowlevel.dependency.ExceptionHandlingDependencyListener;
|
||||
import org.teavm.backend.lowlevel.transform.CoroutineTransformation;
|
||||
import org.teavm.dependency.ClassDependency;
|
||||
import org.teavm.dependency.DependencyAnalyzer;
|
||||
|
@ -71,6 +73,7 @@ import org.teavm.interop.Address;
|
|||
import org.teavm.interop.PlatformMarkers;
|
||||
import org.teavm.interop.Structure;
|
||||
import org.teavm.model.BasicBlock;
|
||||
import org.teavm.model.ClassHierarchy;
|
||||
import org.teavm.model.ClassHolder;
|
||||
import org.teavm.model.ClassHolderTransformer;
|
||||
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(
|
||||
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 ClassInitializerEliminator classInitializerEliminator;
|
||||
private ClassInitializerTransformer classInitializerTransformer;
|
||||
|
@ -196,6 +202,10 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
|
|||
dependencyAnalyzer.linkClass("java.lang.String");
|
||||
dependencyAnalyzer.linkClass("java.lang.Class");
|
||||
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 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, "isSuspending", boolean.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(Thread.class, "setCurrentThread", Thread.class,
|
||||
void.class)).use();
|
||||
|
@ -220,6 +230,8 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
|
|||
dependencyAnalyzer.linkMethod(method.getReference()).use();
|
||||
}
|
||||
}
|
||||
|
||||
dependencyAnalyzer.addDependencyListener(new ExceptionHandlingDependencyListener());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -249,7 +261,8 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
|
|||
@Override
|
||||
public void emit(ListableClassHolderSource classes, BuildTarget buildTarget, String outputName) throws IOException {
|
||||
VirtualTableProvider vtableProvider = createVirtualTableProvider(classes);
|
||||
TagRegistry tagRegistry = new TagRegistry(classes);
|
||||
ClassHierarchy hierarchy = new ClassHierarchy(classes);
|
||||
TagRegistry tagRegistry = new TagRegistry(classes, hierarchy);
|
||||
StringPool stringPool = new StringPool();
|
||||
|
||||
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) {
|
||||
generateThrowCCE(context, writer);
|
||||
generateAllocateStringArray(context, writer);
|
||||
generateAllocateCharArray(context, writer);
|
||||
generateCreateString(context, writer);
|
||||
}
|
||||
|
||||
private void generateThrowCCE(GenerationContext context, CodeWriter writer) {
|
||||
|
@ -425,6 +440,25 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
|
|||
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,
|
||||
List<? extends ValueType> types) {
|
||||
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) {
|
||||
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));
|
||||
writer.println(startName + "();");
|
||||
writer.println(startName + "(teavm_parseArguments(argc, argv));");
|
||||
writer.println(processName + "();");
|
||||
}
|
||||
|
||||
|
@ -537,7 +572,7 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
|
|||
public void apply(IntrinsicContext context, InvocationExpr invocation) {
|
||||
switch (invocation.getMethod().getName()) {
|
||||
case "runMain":
|
||||
generateCallToMainMethod(context.names(), context.writer());
|
||||
generateCallToMainMethod(context, invocation);
|
||||
break;
|
||||
case "setCurrentThread":
|
||||
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");
|
||||
if (entryPoint != null) {
|
||||
String mainMethod = names.forMethod(entryPoint.getMethod());
|
||||
writer.println(mainMethod + "(NULL);");
|
||||
context.writer().print(mainMethod + "(");
|
||||
context.emit(invocation.getArguments().get(0));
|
||||
context.writer().println(");");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -118,6 +118,7 @@ public class ClassGenerator {
|
|||
|
||||
public void generateClass(ClassHolder cls) {
|
||||
generateClassStructure(cls);
|
||||
generateClassStaticFields(cls);
|
||||
generateClassMethods(cls);
|
||||
generateInitializer(cls);
|
||||
}
|
||||
|
@ -230,7 +231,6 @@ public class ClassGenerator {
|
|||
String name = context.getNames().forClass(cls.getName());
|
||||
|
||||
CodeWriter structWriter = structuresWriter.fragment();
|
||||
CodeWriter fieldsWriter = structuresWriter.fragment();
|
||||
|
||||
structWriter.print("typedef struct ").print(name).println(" {").indent();
|
||||
|
||||
|
@ -244,38 +244,19 @@ public class ClassGenerator {
|
|||
|
||||
int layoutIndex = currentLayoutIndex;
|
||||
|
||||
FieldReference[] staticFields = new FieldReference[cls.getFields().size()];
|
||||
int staticIndex = 0;
|
||||
FieldReference[] instanceFields = new FieldReference[cls.getFields().size()];
|
||||
int instanceIndex = 0;
|
||||
for (FieldHolder field : cls.getFields()) {
|
||||
if (field.hasModifier(ElementModifier.STATIC)) {
|
||||
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(";");
|
||||
} else {
|
||||
String fieldName = context.getNames().forMemberField(field.getReference());
|
||||
structWriter.printStrictType(field.getType()).print(" ").print(fieldName).println(";");
|
||||
if (isReferenceType(field.getType())) {
|
||||
instanceFields[instanceIndex++] = field.getReference();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
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) {
|
||||
classLayoutOffsets.put(cls.getName(), layoutIndex);
|
||||
layouts.add(Arrays.copyOf(instanceFields, instanceIndex));
|
||||
|
@ -285,6 +266,36 @@ public class ClassGenerator {
|
|||
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) {
|
||||
if (type instanceof ValueType.Primitive) {
|
||||
ValueType.Primitive primitive = (ValueType.Primitive) type;
|
||||
|
|
|
@ -78,7 +78,7 @@ import org.teavm.runtime.RuntimeClass;
|
|||
import org.teavm.runtime.RuntimeObject;
|
||||
|
||||
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);
|
||||
private static final MethodReference ALLOC_ARRAY_METHOD = new MethodReference(Allocator.class,
|
||||
"allocateArray", RuntimeClass.class, int.class, Address.class);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -104,6 +104,7 @@ import org.teavm.interop.StaticInit;
|
|||
import org.teavm.model.AnnotationHolder;
|
||||
import org.teavm.model.BasicBlock;
|
||||
import org.teavm.model.CallLocation;
|
||||
import org.teavm.model.ClassHierarchy;
|
||||
import org.teavm.model.ClassHolder;
|
||||
import org.teavm.model.ClassHolderTransformer;
|
||||
import org.teavm.model.ClassReader;
|
||||
|
@ -314,7 +315,8 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
|||
WasmFunction initFunction = new WasmFunction("__start__");
|
||||
|
||||
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);
|
||||
NameProvider names = new NameProvider(controller.getUnprocessedClassSource());
|
||||
WasmClassGenerator classGenerator = new WasmClassGenerator(classes, controller.getUnprocessedClassSource(),
|
||||
|
|
|
@ -26,15 +26,15 @@ import java.util.Map;
|
|||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import org.teavm.model.ClassHierarchy;
|
||||
import org.teavm.model.ClassReader;
|
||||
import org.teavm.model.ClassReaderSource;
|
||||
import org.teavm.model.ElementModifier;
|
||||
import org.teavm.model.ListableClassReaderSource;
|
||||
|
||||
public class TagRegistry {
|
||||
private Map<String, List<Range>> ranges = new HashMap<>();
|
||||
|
||||
public TagRegistry(ListableClassReaderSource classSource) {
|
||||
public TagRegistry(ListableClassReaderSource classSource, ClassHierarchy classHierarchy) {
|
||||
List<String> roots = new ArrayList<>();
|
||||
Map<String, Set<String>> implementedBy = new HashMap<>();
|
||||
|
||||
|
@ -45,8 +45,7 @@ public class TagRegistry {
|
|||
continue;
|
||||
}
|
||||
for (String iface : cls.getInterfaces()) {
|
||||
String topmostImplementor = findTopmostImplementor(classSource, className, iface);
|
||||
markImplementor(classSource, topmostImplementor, iface, implementedBy);
|
||||
markImplementor(classHierarchy, className, iface, implementedBy);
|
||||
}
|
||||
if (cls.getParent() == null || cls.getParent().equals(cls.getName())) {
|
||||
roots.add(className);
|
||||
|
@ -58,8 +57,7 @@ public class TagRegistry {
|
|||
Map<String, Range> simpleRanges = new HashMap<>();
|
||||
int current = 0;
|
||||
for (String root : roots) {
|
||||
assignRange(current, hierarchy, root, simpleRanges);
|
||||
++current;
|
||||
current = 1 + assignRange(current, hierarchy, root, simpleRanges);
|
||||
}
|
||||
|
||||
for (String className : classSource.getClassNames()) {
|
||||
|
@ -71,7 +69,7 @@ public class TagRegistry {
|
|||
Set<String> implementorRoots = implementedBy.get(cls.getName());
|
||||
if (implementorRoots != null) {
|
||||
List<Range> ifaceRanges = implementorRoots.stream()
|
||||
.map(implementor -> simpleRanges.get(implementor))
|
||||
.map(simpleRanges::get)
|
||||
.filter(Objects::nonNull)
|
||||
.sorted(Comparator.comparing(range -> range.lower))
|
||||
.collect(Collectors.toList());
|
||||
|
@ -86,37 +84,40 @@ public class TagRegistry {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private String findTopmostImplementor(ClassReaderSource classSource, String className, String ifaceName) {
|
||||
ClassReader cls = classSource.get(className);
|
||||
private String findTopmostImplementor(ClassHierarchy hierarchy, String className, String ifaceName) {
|
||||
ClassReader cls = hierarchy.getClassSource().get(className);
|
||||
if (cls == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (cls.getParent() != null) {
|
||||
String candidate = findTopmostImplementor(classSource, cls.getParent(), ifaceName);
|
||||
String candidate = findTopmostImplementor(hierarchy, cls.getParent(), ifaceName);
|
||||
if (candidate != null) {
|
||||
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) {
|
||||
className = findTopmostImplementor(hierarchy, className, ifaceName);
|
||||
|
||||
if (!implementedBy.computeIfAbsent(ifaceName, key -> new LinkedHashSet<>()).add(className)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ClassReader iface = classSource.get(ifaceName);
|
||||
ClassReader iface = hierarchy.getClassSource().get(ifaceName);
|
||||
if (iface == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (String superIface : iface.getInterfaces()) {
|
||||
markImplementor(classSource, className, superIface, implementedBy);
|
||||
markImplementor(hierarchy, className, superIface, implementedBy);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -115,9 +115,11 @@ public class RegisterAllocator {
|
|||
case FLOAT:
|
||||
return 2;
|
||||
case DOUBLE:
|
||||
return 2;
|
||||
default:
|
||||
return 3;
|
||||
case OBJECT:
|
||||
return 4;
|
||||
default:
|
||||
return 5;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -213,11 +213,11 @@ public class Fiber {
|
|||
new Fiber(runner, daemon).start();
|
||||
}
|
||||
|
||||
static void startMain() {
|
||||
start(Fiber::runMain, false);
|
||||
static void startMain(String[] args) {
|
||||
start(() -> runMain(args), false);
|
||||
}
|
||||
|
||||
static native void runMain();
|
||||
static native void runMain(String[] args);
|
||||
|
||||
private void start() {
|
||||
Fiber former = current;
|
||||
|
|
|
@ -52,38 +52,37 @@ static JavaArray* teavm_resourceMapKeys(TeaVM_ResourceMap *map) {
|
|||
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) {
|
||||
size_t sz = 0;
|
||||
char buffer[6];
|
||||
char buffer[__STDC_UTF_16__];
|
||||
mbstate_t state = {0};
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
if (obj == NULL) {
|
||||
return NULL;
|
||||
|
@ -98,15 +97,47 @@ static char* teavm_stringToC(void* obj) {
|
|||
|
||||
int32_t j = 0;
|
||||
char* dst = result;
|
||||
mbstate_t state = {0};
|
||||
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';
|
||||
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) {
|
||||
if (s != NULL) {
|
||||
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;
|
||||
}
|
|
@ -141,6 +141,8 @@ typedef struct {
|
|||
static int32_t teavm_hashCode(JavaString*);
|
||||
static int32_t teavm_equals(JavaString*, JavaString*);
|
||||
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) {
|
||||
uint32_t hashCode = teavm_hashCode(string);
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
package org.teavm.samples.benchmark.teavm;
|
||||
|
||||
import java.util.Arrays;
|
||||
import org.jbox2d.collision.shapes.CircleShape;
|
||||
import org.jbox2d.collision.shapes.PolygonShape;
|
||||
import org.jbox2d.collision.shapes.Shape;
|
||||
|
@ -42,6 +43,8 @@ public final class Gtk3BenchmarkStarter {
|
|||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(Arrays.asList(args));
|
||||
|
||||
Gtk.init(null, null);
|
||||
Gtk.Window window = Gtk.windowNew(Gtk.WINDOW_TOPLEVEL);
|
||||
GLib.signalConnect(window, "delete-event",
|
||||
|
|
75
tests/src/test/java/org/teavm/vm/RttiTest.java
Normal file
75
tests/src/test/java/org/teavm/vm/RttiTest.java
Normal 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 {
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user