From 31958794673124b7367a7fe986375cdb2f799d26 Mon Sep 17 00:00:00 2001 From: konsoletyper Date: Sun, 23 Feb 2014 23:17:30 +0400 Subject: [PATCH] Adds support of Class.getDeclaringClass method --- .../impl/NewInstanceDependencySupport.java | 17 ++++++++++-- .../java/lang/ClassNativeGenerator.java | 27 +++++++++++++++++-- .../org/teavm/classlib/java/lang/TClass.java | 4 +++ .../teavm/classlib/java/lang/ClassTest.java | 8 ++++++ .../java/org/teavm/model/ClassHolder.java | 10 +++++++ .../java/org/teavm/model/ClassReader.java | 2 ++ .../teavm/model/CopyClassHolderSource.java | 1 + .../org/teavm/parsing/ClassRefsRenamer.java | 3 +++ .../main/java/org/teavm/parsing/Parser.java | 8 ++++++ 9 files changed, 76 insertions(+), 4 deletions(-) diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/impl/NewInstanceDependencySupport.java b/teavm-classlib/src/main/java/org/teavm/classlib/impl/NewInstanceDependencySupport.java index da4b47e2f..1e8aecad6 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/impl/NewInstanceDependencySupport.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/impl/NewInstanceDependencySupport.java @@ -24,6 +24,7 @@ import org.teavm.model.*; */ public class NewInstanceDependencySupport implements DependencyListener { private DependencyNode allClassesNode; + private DependencyStack newInstanceStack; @Override public void started(DependencyChecker dependencyChecker) { @@ -36,19 +37,31 @@ public class NewInstanceDependencySupport implements DependencyListener { if (cls.hasModifier(ElementModifier.ABSTRACT) || cls.hasModifier(ElementModifier.INTERFACE)) { return; } - if (cls.getMethod(new MethodDescriptor("", ValueType.VOID)) != null) { + MethodReader method = cls.getMethod(new MethodDescriptor("", ValueType.VOID)); + if (method != null) { allClassesNode.propagate(className); } } @Override - public void methodAchieved(DependencyChecker dependencyChecker, MethodDependency method) { + public void methodAchieved(final DependencyChecker dependencyChecker, MethodDependency method) { MethodReader reader = method.getMethod(); if (reader.getOwnerName().equals("java.lang.Class") && reader.getName().equals("newInstance")) { + newInstanceStack = method.getStack(); allClassesNode.connect(method.getResult()); + method.getResult().addConsumer(new DependencyConsumer() { + @Override public void consume(String type) { + attachConstructor(dependencyChecker, type); + } + }); } } + private void attachConstructor(DependencyChecker checker, String type) { + MethodReference ref = new MethodReference(type, new MethodDescriptor("", ValueType.VOID)); + checker.linkMethod(ref, newInstanceStack).use(); + } + @Override public void fieldAchieved(DependencyChecker dependencyChecker, FieldDependency field) { } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ClassNativeGenerator.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ClassNativeGenerator.java index ea2ab1e5d..868424c18 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ClassNativeGenerator.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ClassNativeGenerator.java @@ -47,6 +47,9 @@ public class ClassNativeGenerator implements Generator, Injector, DependencyPlug case "newInstance": generateNewInstance(context, writer); break; + case "getDeclaringClass": + generateGetDeclaringClass(context, writer); + break; } } @@ -141,8 +144,27 @@ public class ClassNativeGenerator implements Generator, Injector, DependencyPlug writer.append("$rt_throw(ex);").softNewLine(); writer.outdent().append("}").softNewLine(); writer.append("var instance = new cls();").softNewLine(); - writer.append("ctor(instance)"); - writer.append("return instance"); + writer.append("ctor(instance);").softNewLine(); + writer.append("return instance;").softNewLine(); + } + + private void generateGetDeclaringClass(GeneratorContext context, SourceWriter writer) throws IOException { + String self = context.getParameterName(0); + writer.append("if (!").appendClass("java.lang.Class").append(".$$owners$$) {").indent().softNewLine(); + writer.appendClass("java.lang.Class").append(".$$owners$$ = true;").softNewLine(); + for (String clsName : context.getClassSource().getClassNames()) { + ClassReader cls = context.getClassSource().get(clsName); + writer.appendClass(clsName).append(".$$owner$$ = "); + if (cls.getOwnerName() != null) { + writer.appendClass(cls.getOwnerName()); + } else { + writer.append("null"); + } + writer.append(";").softNewLine(); + } + writer.outdent().append("}").softNewLine(); + writer.append("var cls = " + self + ".$data;").softNewLine(); + writer.append("return cls.$$owner$$ != null ? $rt_cls(cls.$$owner$$) : null;").softNewLine(); } @Override @@ -154,6 +176,7 @@ public class ClassNativeGenerator implements Generator, Injector, DependencyPlug case "getSuperclass": case "getComponentType0": case "forNameImpl": + case "getDeclaringClass": graph.getResult().propagate("java.lang.Class"); break; } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TClass.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TClass.java index 2bc393085..a96bdc74d 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TClass.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TClass.java @@ -134,4 +134,8 @@ public class TClass extends TObject { @GeneratedBy(ClassNativeGenerator.class) public native T newInstance() throws TInstantiationException, TIllegalAccessException; + + @GeneratedBy(ClassNativeGenerator.class) + @PluggableDependency(ClassNativeGenerator.class) + public native TClass getDeclaringClass(); } diff --git a/teavm-classlib/src/test/java/org/teavm/classlib/java/lang/ClassTest.java b/teavm-classlib/src/test/java/org/teavm/classlib/java/lang/ClassTest.java index f92a53aa7..2cc4cf501 100644 --- a/teavm-classlib/src/test/java/org/teavm/classlib/java/lang/ClassTest.java +++ b/teavm-classlib/src/test/java/org/teavm/classlib/java/lang/ClassTest.java @@ -97,4 +97,12 @@ public class ClassTest { assertEquals(TestObject.class, instance.getClass()); assertEquals(1, ((TestObject)instance).getCounter()); } + + @Test + public void declaringClassFound() { + assertEquals(ClassTest.class, new A().getClass().getDeclaringClass()); + } + + private static class A { + } } diff --git a/teavm-core/src/main/java/org/teavm/model/ClassHolder.java b/teavm-core/src/main/java/org/teavm/model/ClassHolder.java index 22d1e19e2..3440de6bb 100644 --- a/teavm-core/src/main/java/org/teavm/model/ClassHolder.java +++ b/teavm-core/src/main/java/org/teavm/model/ClassHolder.java @@ -26,6 +26,7 @@ public class ClassHolder extends ElementHolder implements ClassReader { private Set interfaces = new HashSet<>(); private Map methods = new HashMap<>(); private Map fields = new HashMap<>(); + private String ownerName; public ClassHolder(String name) { super(name); @@ -106,4 +107,13 @@ public class ClassHolder extends ElementHolder implements ClassReader { fields.remove(field.getName()); field.setOwner(null); } + + @Override + public String getOwnerName() { + return ownerName; + } + + public void setOwnerName(String ownerName) { + this.ownerName = ownerName; + } } diff --git a/teavm-core/src/main/java/org/teavm/model/ClassReader.java b/teavm-core/src/main/java/org/teavm/model/ClassReader.java index 6854e8a6b..480ff17c1 100644 --- a/teavm-core/src/main/java/org/teavm/model/ClassReader.java +++ b/teavm-core/src/main/java/org/teavm/model/ClassReader.java @@ -34,4 +34,6 @@ public interface ClassReader extends ElementReader { FieldReader getField(String name); Collection getFields(); + + String getOwnerName(); } diff --git a/teavm-core/src/main/java/org/teavm/model/CopyClassHolderSource.java b/teavm-core/src/main/java/org/teavm/model/CopyClassHolderSource.java index 722a47608..0fb83fda2 100644 --- a/teavm-core/src/main/java/org/teavm/model/CopyClassHolderSource.java +++ b/teavm-core/src/main/java/org/teavm/model/CopyClassHolderSource.java @@ -59,6 +59,7 @@ public class CopyClassHolderSource implements ClassHolderSource { for (FieldHolder field : original.getFields()) { copy.addField(copyField(field)); } + copy.setOwnerName(original.getOwnerName()); copyAnnotations(original.getAnnotations(), copy.getAnnotations()); return copy; } diff --git a/teavm-core/src/main/java/org/teavm/parsing/ClassRefsRenamer.java b/teavm-core/src/main/java/org/teavm/parsing/ClassRefsRenamer.java index 22074161c..340310c4c 100644 --- a/teavm-core/src/main/java/org/teavm/parsing/ClassRefsRenamer.java +++ b/teavm-core/src/main/java/org/teavm/parsing/ClassRefsRenamer.java @@ -57,6 +57,9 @@ class ClassRefsRenamer implements InstructionVisitor { cls.removeField(field); renamedCls.addField(field); } + if (cls.getOwnerName() != null) { + renamedCls.setOwnerName(classNameMapper.map(cls.getOwnerName())); + } rename(cls.getAnnotations(), renamedCls.getAnnotations()); for (String iface : cls.getInterfaces()) { renamedCls.getInterfaces().add(classNameMapper.map(iface)); diff --git a/teavm-core/src/main/java/org/teavm/parsing/Parser.java b/teavm-core/src/main/java/org/teavm/parsing/Parser.java index 67abb12d8..e77d25a0e 100644 --- a/teavm-core/src/main/java/org/teavm/parsing/Parser.java +++ b/teavm-core/src/main/java/org/teavm/parsing/Parser.java @@ -64,6 +64,14 @@ public class Parser { MethodNode methodNode = (MethodNode)obj; cls.addMethod(parseMethod(methodNode, node.name)); } + if (node.outerClass != null) { + cls.setOwnerName(node.outerClass.replace('/', '.')); + } else { + int lastIndex = node.name.lastIndexOf('$'); + if (lastIndex != -1) { + cls.setOwnerName(node.name.substring(0, lastIndex).replace('/', '.')); + } + } parseAnnotations(cls.getAnnotations(), node); return cls; }