From 2ae7b587d11ae57c8e8e65e2dbc68cacb06b2c67 Mon Sep 17 00:00:00 2001 From: konsoletyper Date: Sun, 8 Feb 2015 22:35:51 +0400 Subject: [PATCH] Most of TClass now uses Platform instead of code generation --- .../impl/DeclaringClassMetadataGenerator.java | 20 ++-- .../org/teavm/classlib/impl/JCLPlugin.java | 4 +- .../classlib/impl/ServiceLoaderSupport.java | 2 +- .../java/lang/ClassNativeGenerator.java | 67 +------------ .../org/teavm/classlib/java/lang/TClass.java | 30 ++++-- .../lang/reflect/ArrayNativeGenerator.java | 7 +- .../classlib/java/lang/reflect/TArray.java | 5 +- .../classlib/java/util/TServiceLoader.java | 5 +- .../java/org/teavm/javascript/Renderer.java | 52 +++------- .../javascript/spi/GeneratorContext.java | 3 + .../src/main/java/org/teavm/vm/TeaVM.java | 5 +- .../resources/org/teavm/javascript/runtime.js | 24 +++-- .../teavm/tooling/test/res/junit-support.js | 2 +- .../teavm/jso/plugin/JSNativeGenerator.java | 2 +- .../java/org/teavm/platform/Platform.java | 2 +- .../org/teavm/platform/PlatformClass.java | 3 +- .../teavm/platform/PlatformClassMetadata.java | 3 - .../teavm/platform/PlatformPrimitives.java | 20 ++-- .../org/teavm/platform/PlatformSequence.java | 2 +- .../ClassScopedMetadataGenerator.java | 35 +++++++ .../metadata/ClassScopedMetadataProvider.java | 34 +++++++ .../platform/metadata/MetadataGenerator.java | 2 + .../plugin/BuildTimeResourceProxyBuilder.java | 4 +- .../plugin/BuildTimeResourceWriterMethod.java | 2 +- .../plugin}/ClassLookupDependencySupport.java | 7 +- ...ScopedMetadataProviderNativeGenerator.java | 97 +++++++++++++++++++ .../MetadataProviderNativeGenerator.java | 23 +++-- .../plugin/MetadataProviderTransformer.java | 27 ++++-- .../platform/plugin/PlatformGenerator.java | 49 ++++++---- .../teavm/platform/plugin/PlatformPlugin.java | 1 + .../platform/plugin/ResourceWriterHelper.java | 28 ++++++ 31 files changed, 368 insertions(+), 199 deletions(-) create mode 100644 teavm-platform/src/main/java/org/teavm/platform/metadata/ClassScopedMetadataGenerator.java create mode 100644 teavm-platform/src/main/java/org/teavm/platform/metadata/ClassScopedMetadataProvider.java rename {teavm-classlib/src/main/java/org/teavm/classlib/impl => teavm-platform/src/main/java/org/teavm/platform/plugin}/ClassLookupDependencySupport.java (90%) create mode 100644 teavm-platform/src/main/java/org/teavm/platform/plugin/ClassScopedMetadataProviderNativeGenerator.java diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/impl/DeclaringClassMetadataGenerator.java b/teavm-classlib/src/main/java/org/teavm/classlib/impl/DeclaringClassMetadataGenerator.java index 8dab8cd2e..30842e676 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/impl/DeclaringClassMetadataGenerator.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/impl/DeclaringClassMetadataGenerator.java @@ -15,18 +15,26 @@ */ package org.teavm.classlib.impl; +import java.util.HashMap; +import java.util.Map; +import org.teavm.model.ClassReader; import org.teavm.model.MethodReference; -import org.teavm.platform.metadata.MetadataGenerator; -import org.teavm.platform.metadata.MetadataGeneratorContext; -import org.teavm.platform.metadata.Resource; +import org.teavm.platform.metadata.*; /** * * @author Alexey Andreev */ -public class DeclaringClassMetadataGenerator implements MetadataGenerator { +public class DeclaringClassMetadataGenerator implements ClassScopedMetadataGenerator { @Override - public Resource generateMetadata(MetadataGeneratorContext context, MethodReference method) { - return null; + public Map generateMetadata(MetadataGeneratorContext context, MethodReference method) { + Map result = new HashMap<>(); + for (String clsName : context.getClassSource().getClassNames()) { + ClassReader cls = context.getClassSource().get(clsName); + if (cls.getOwnerName() != null) { + result.put(clsName, context.createClassResource(cls.getOwnerName())); + } + } + return result; } } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/impl/JCLPlugin.java b/teavm-classlib/src/main/java/org/teavm/classlib/impl/JCLPlugin.java index af9de2a36..7a86e690f 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/impl/JCLPlugin.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/impl/JCLPlugin.java @@ -18,6 +18,7 @@ package org.teavm.classlib.impl; import java.util.ServiceLoader; import org.teavm.classlib.impl.unicode.CLDRReader; import org.teavm.model.MethodReference; +import org.teavm.platform.PlatformClass; import org.teavm.vm.spi.TeaVMHost; import org.teavm.vm.spi.TeaVMPlugin; @@ -30,12 +31,11 @@ public class JCLPlugin implements TeaVMPlugin { public void install(TeaVMHost host) { host.add(new EnumDependencySupport()); host.add(new EnumTransformer()); - host.add(new ClassLookupDependencySupport()); host.add(new ObjectEnrichRenderer()); ServiceLoaderSupport serviceLoaderSupp = new ServiceLoaderSupport(host.getClassLoader()); host.add(serviceLoaderSupp); MethodReference loadServicesMethod = new MethodReference(ServiceLoader.class, "loadServices", - Class.class, Object[].class); + PlatformClass.class, Object[].class); host.add(loadServicesMethod, serviceLoaderSupp); JavacSupport javacSupport = new JavacSupport(); host.add(javacSupport); diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/impl/ServiceLoaderSupport.java b/teavm-classlib/src/main/java/org/teavm/classlib/impl/ServiceLoaderSupport.java index 0bf342efc..f019593a7 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/impl/ServiceLoaderSupport.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/impl/ServiceLoaderSupport.java @@ -65,7 +65,7 @@ public class ServiceLoaderSupport implements Generator, DependencyListener { } writer.outdent().append("}").softNewLine(); String param = context.getParameterName(1); - writer.append("var cls = " + param + ".$data;").softNewLine(); + writer.append("var cls = " + param + ";").softNewLine(); writer.append("if (!cls.$$serviceList$$) {").indent().softNewLine(); writer.append("return $rt_createArray($rt_objcls(), 0);").softNewLine(); writer.outdent().append("}").softNewLine(); 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 7080fd740..ccf99dee3 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 @@ -16,12 +16,6 @@ package org.teavm.classlib.java.lang; import java.io.IOException; -import org.teavm.codegen.SourceWriter; -import org.teavm.dependency.DependencyAgent; -import org.teavm.dependency.DependencyPlugin; -import org.teavm.dependency.MethodDependency; -import org.teavm.javascript.spi.Generator; -import org.teavm.javascript.spi.GeneratorContext; import org.teavm.javascript.spi.Injector; import org.teavm.javascript.spi.InjectorContext; import org.teavm.model.*; @@ -30,70 +24,13 @@ import org.teavm.model.*; * * @author Alexey Andreev */ -public class ClassNativeGenerator implements Generator, Injector, DependencyPlugin { - @Override - public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) - throws IOException { - switch (methodRef.getName()) { - case "forNameImpl": - generateForName(context, writer); - break; - case "getDeclaringClass": - generateGetDeclaringClass(context, writer); - break; - } - } - +public class ClassNativeGenerator implements Injector { @Override public void generate(InjectorContext context, MethodReference methodRef) throws IOException { switch (methodRef.getName()) { case "getEnumConstantsImpl": context.writeExpr(context.getArgument(0)); - context.getWriter().append(".$data.values()"); - break; - } - } - - private void generateForName(GeneratorContext context, SourceWriter writer) throws IOException { - String param = context.getParameterName(1); - writer.append("switch ($rt_ustr(" + param + ")) {").softNewLine().indent(); - for (String name : context.getClassSource().getClassNames()) { - writer.append("case \"" + name + "\": ").appendClass(name).append(".$clinit(); ") - .append("return $rt_cls(").appendClass(name).append(");").softNewLine(); - } - writer.append("default: return null;").softNewLine(); - writer.outdent().append("}").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 - public void methodAchieved(DependencyAgent agent, MethodDependency graph, CallLocation location) { - switch (graph.getReference().getName()) { - case "forNameImpl": - case "getDeclaringClass": - graph.getResult().propagate(agent.getType("java.lang.Class")); - break; - case "newInstance": - agent.linkMethod(new MethodReference(InstantiationException.class, "", void.class), - location).use(); + context.getWriter().append(".values()"); 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 668bde0a1..814e01b82 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 @@ -19,7 +19,8 @@ import org.teavm.classlib.impl.DeclaringClassMetadataGenerator; import org.teavm.javascript.spi.InjectedBy; import org.teavm.platform.Platform; import org.teavm.platform.PlatformClass; -import org.teavm.platform.metadata.MetadataProvider; +import org.teavm.platform.metadata.ClassResource; +import org.teavm.platform.metadata.ClassScopedMetadataProvider; /** * @@ -36,7 +37,7 @@ public class TClass extends TObject { platformClass.setJavaClass(Platform.getPlatformObject(this)); } - static TClass getClass(PlatformClass cls) { + public static TClass getClass(PlatformClass cls) { if (cls == null) { return null; } @@ -47,7 +48,7 @@ public class TClass extends TObject { return result; } - PlatformClass getPlatformClass() { + public PlatformClass getPlatformClass() { return platformClass; } @@ -71,7 +72,7 @@ public class TClass extends TObject { } public boolean isArray() { - return platformClass.getMetadata().isArray(); + return platformClass.getMetadata().getArrayItem() != null; } public boolean isEnum() { @@ -141,12 +142,13 @@ public class TClass extends TObject { return (TClass)getClass(platformClass.getMetadata().getSuperclass()); } + @SuppressWarnings("unchecked") public T[] getEnumConstants() { - return isEnum() ? getEnumConstantsImpl() : null; + return isEnum() ? (T[])getEnumConstantsImpl(platformClass) : null; } @InjectedBy(ClassNativeGenerator.class) - public native T[] getEnumConstantsImpl(); + private static native Object[] getEnumConstantsImpl(PlatformClass cls); @SuppressWarnings("unchecked") public T cast(TObject obj) { @@ -175,12 +177,22 @@ public class TClass extends TObject { return forName(name); } + @SuppressWarnings("unchecked") public T newInstance() throws TInstantiationException, TIllegalAccessException { - return Platform.newInstance(platformClass); + Object instance = Platform.newInstance(platformClass); + if (instance == null) { + throw new TInstantiationException(); + } + return (T)instance; } - @MetadataProvider(DeclaringClassMetadataGenerator.class) - public native TClass getDeclaringClass(); + public TClass getDeclaringClass() { + ClassResource res = getDeclaringClass(platformClass); + return res != null ? getClass(Platform.classFromResource(res)) : null; + } + + @ClassScopedMetadataProvider(DeclaringClassMetadataGenerator.class) + private static native ClassResource getDeclaringClass(PlatformClass cls); @SuppressWarnings("unchecked") public TClass asSubclass(TClass clazz) { diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/reflect/ArrayNativeGenerator.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/reflect/ArrayNativeGenerator.java index 0dfed5b26..468334f63 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/reflect/ArrayNativeGenerator.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/reflect/ArrayNativeGenerator.java @@ -93,15 +93,14 @@ public class ArrayNativeGenerator implements Generator, DependencyPlugin { private void generateNewInstance(GeneratorContext context, SourceWriter writer) throws IOException { String type = context.getParameterName(1); String length = context.getParameterName(2); - writer.append("var cls = " + type + ".$data;").softNewLine(); - writer.append("if (cls.primitive) {").softNewLine().indent(); + writer.append("if (").append(type).append(".$meta.primitive) {").softNewLine().indent(); for (String primitive : primitives) { - writer.append("if (cls == $rt_" + primitive.toLowerCase() + "cls()) {").indent().softNewLine(); + writer.append("if (" + type + " == $rt_" + primitive.toLowerCase() + "cls()) {").indent().softNewLine(); writer.append("return $rt_create" + primitive + "Array(" + length + ");").softNewLine(); writer.outdent().append("}").softNewLine(); } writer.outdent().append("} else {").indent().softNewLine(); - writer.append("return $rt_createArray(cls, " + length + ")").softNewLine(); + writer.append("return $rt_createArray(" + type + ", " + length + ")").softNewLine(); writer.outdent().append("}").softNewLine(); } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/reflect/TArray.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/reflect/TArray.java index 7c52cf346..0f46fbf0f 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/reflect/TArray.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/reflect/TArray.java @@ -18,6 +18,7 @@ package org.teavm.classlib.java.lang.reflect; import org.teavm.classlib.java.lang.*; import org.teavm.dependency.PluggableDependency; import org.teavm.javascript.spi.GeneratedBy; +import org.teavm.platform.PlatformClass; /** * @@ -38,12 +39,12 @@ public final class TArray extends TObject { if (length < 0) { throw new TNegativeArraySizeException(); } - return newInstanceImpl(componentType, length); + return newInstanceImpl(componentType.getPlatformClass(), length); } @GeneratedBy(ArrayNativeGenerator.class) @PluggableDependency(ArrayNativeGenerator.class) - private static native TObject newInstanceImpl(TClass componentType, int length); + private static native TObject newInstanceImpl(PlatformClass componentType, int length); public static TObject get(TObject array, int index) throws TIllegalArgumentException, TArrayIndexOutOfBoundsException { diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TServiceLoader.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TServiceLoader.java index 6299fed4c..035066dde 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TServiceLoader.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TServiceLoader.java @@ -16,6 +16,7 @@ package org.teavm.classlib.java.util; import org.teavm.classlib.java.lang.*; +import org.teavm.platform.PlatformClass; /** * @@ -48,7 +49,7 @@ public final class TServiceLoader extends TObject implements TIterable { } public static TServiceLoader load(TClass service) { - return new TServiceLoader<>(loadServices(service)); + return new TServiceLoader<>(loadServices(service.getPlatformClass())); } public static TServiceLoader load(TClass service, @SuppressWarnings("unused") TClassLoader loader) { @@ -59,7 +60,7 @@ public final class TServiceLoader extends TObject implements TIterable { return load(service); } - private static native T[] loadServices(TClass serviceType); + private static native T[] loadServices(PlatformClass cls); public void reload() { // Do nothing, services are bound at build time diff --git a/teavm-core/src/main/java/org/teavm/javascript/Renderer.java b/teavm-core/src/main/java/org/teavm/javascript/Renderer.java index b4074040c..57827593e 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/Renderer.java +++ b/teavm-core/src/main/java/org/teavm/javascript/Renderer.java @@ -26,6 +26,7 @@ import org.teavm.common.ServiceRepository; import org.teavm.debugging.information.DebugInformationEmitter; import org.teavm.debugging.information.DeferredCallSite; import org.teavm.debugging.information.DummyDebugInformationEmitter; +import org.teavm.diagnostics.Diagnostics; import org.teavm.javascript.ast.*; import org.teavm.javascript.spi.GeneratorContext; import org.teavm.javascript.spi.InjectedBy; @@ -54,6 +55,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext private DeferredCallSite lastCallSite; private DeferredCallSite prevCallSite; private Set asyncMethods; + private Diagnostics diagnostics; private boolean async; private static class InjectorHolder { @@ -77,13 +79,14 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext } public Renderer(SourceWriter writer, ListableClassHolderSource classSource, ClassLoader classLoader, - ServiceRepository services, Set asyncMethods) { + ServiceRepository services, Set asyncMethods, Diagnostics diagnostics) { this.naming = writer.getNaming(); this.writer = writer; this.classSource = classSource; this.classLoader = classLoader; this.services = services; this.asyncMethods = new HashSet<>(asyncMethods); + this.diagnostics = diagnostics; } @Override @@ -167,43 +170,11 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext } private void renderRuntimeCls() throws IOException { - writer.append("function $rt_cls").ws().append("(clsProto)").ws().append("{") - .indent().softNewLine(); - String classClass = "java.lang.Class"; - writer.append("var cls").ws().append("=").ws().append("clsProto.classObject;").softNewLine(); - writer.append("if").ws().append("(typeof cls").ws().append("===").ws().append("'undefined')").ws() - .append("{").softNewLine().indent(); - MethodReference createMethodRef = new MethodReference(classClass, "createNew", ValueType.object(classClass)); - writer.append("cls").ws().append("=").ws().appendMethodBody(createMethodRef).append("();").softNewLine(); - writer.append("cls.$data = clsProto;").softNewLine(); - if (classSource.get(classClass).getField("name") != null) { - writer.append("cls.").appendField(new FieldReference(classClass, "name")).ws().append("=").ws() - .append("clsProto.$meta.name").ws().append("!==").ws().append("undefined").ws().append("?").ws() - .append("$rt_str(clsProto.$meta.name)").ws().append(":").ws().append("null;").softNewLine(); - } - if (classSource.get(classClass).getField("name") != null) { - writer.append("cls.").appendField(new FieldReference(classClass, "binaryName")).ws().append("=").ws() - .append("clsProto.$meta.binaryName").ws().append("!==").ws().append("undefined").ws() - .append("?").ws() - .append("$rt_str(clsProto.$meta.binaryName)").ws().append(":").ws().append("null;").softNewLine(); - } - if (classSource.get(classClass).getField("primitive") != null) { - writer.append("cls.").appendField(new FieldReference(classClass, "primitive")) - .append(" = clsProto.$meta.primitive ? 1 : 0;").newLine(); - } - if (classSource.get(classClass).getField("array") != null) { - writer.append("cls.").appendField(new FieldReference(classClass, "array")).ws() - .append("=").ws().append("clsProto.$meta.item").ws().append("?").ws() - .append("1").ws().append(":").ws().append("0;").softNewLine(); - } - if (classSource.get(classClass).getField("isEnum") != null) { - writer.append("cls.").appendField(new FieldReference(classClass, "isEnum")).ws() - .append("=").ws().append("clsProto.$meta.enum").ws().append("?").ws() - .append("1").ws().append(":").ws().append("0;").softNewLine(); - } - writer.append("clsProto.classObject").ws().append("=").ws().append("cls;").softNewLine(); - writer.outdent().append("}").softNewLine(); - writer.append("return cls;").softNewLine(); + writer.append("function $rt_cls(cls)").ws().append("{").softNewLine().indent(); + writer.append("return ").appendMethodBody("java.lang.Class", "getClass", + ValueType.object("org.teavm.platform.PlatformClass"), + ValueType.object("java.lang.Class")).append("(cls);") + .softNewLine(); writer.outdent().append("}").newLine(); } @@ -706,6 +677,11 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext public String getCompleteContinuation() { return "$return"; } + + @Override + public Diagnostics getDiagnostics() { + return diagnostics; + } } private void pushLocation(NodeLocation location) { diff --git a/teavm-core/src/main/java/org/teavm/javascript/spi/GeneratorContext.java b/teavm-core/src/main/java/org/teavm/javascript/spi/GeneratorContext.java index f60b8b08f..927813f0f 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/spi/GeneratorContext.java +++ b/teavm-core/src/main/java/org/teavm/javascript/spi/GeneratorContext.java @@ -17,6 +17,7 @@ package org.teavm.javascript.spi; import java.util.Properties; import org.teavm.common.ServiceRepository; +import org.teavm.diagnostics.Diagnostics; import org.teavm.model.ListableClassReaderSource; import org.teavm.model.MethodReference; @@ -38,4 +39,6 @@ public interface GeneratorContext extends ServiceRepository { String getCompleteContinuation(); boolean isAsync(MethodReference method); + + Diagnostics getDiagnostics(); } diff --git a/teavm-core/src/main/java/org/teavm/vm/TeaVM.java b/teavm-core/src/main/java/org/teavm/vm/TeaVM.java index 9c5815800..e964c15b3 100644 --- a/teavm-core/src/main/java/org/teavm/vm/TeaVM.java +++ b/teavm-core/src/main/java/org/teavm/vm/TeaVM.java @@ -334,7 +334,8 @@ public class TeaVM implements TeaVMHost, ServiceRepository { return progressListener.progressReached(0) == TeaVMProgressFeedback.CONTINUE; } }); - dependencyChecker.linkMethod(new MethodReference(Class.class, "createNew", Class.class), null).use(); + dependencyChecker.linkMethod(new MethodReference(Class.class.getName(), "getClass", + ValueType.object("org.teavm.platform.PlatformClass"), ValueType.parse(Class.class)), null).use(); dependencyChecker.linkMethod(new MethodReference(String.class, "", char[].class, void.class), null).use(); dependencyChecker.linkMethod(new MethodReference(String.class, "getChars", int.class, int.class, char[].class, @@ -396,7 +397,7 @@ public class TeaVM implements TeaVMHost, ServiceRepository { SourceWriterBuilder builder = new SourceWriterBuilder(naming); builder.setMinified(minifying); SourceWriter sourceWriter = builder.build(writer); - Renderer renderer = new Renderer(sourceWriter, classSet, classLoader, this, asyncMethods); + Renderer renderer = new Renderer(sourceWriter, classSet, classLoader, this, asyncMethods, diagnostics); renderer.setProperties(properties); if (debugEmitter != null) { int classIndex = 0; diff --git a/teavm-core/src/main/resources/org/teavm/javascript/runtime.js b/teavm-core/src/main/resources/org/teavm/javascript/runtime.js index ae71f1784..638b4db73 100644 --- a/teavm-core/src/main/resources/org/teavm/javascript/runtime.js +++ b/teavm-core/src/main/resources/org/teavm/javascript/runtime.js @@ -130,15 +130,18 @@ function $rt_arraycls(cls) { } var name = "[" + cls.$meta.binaryName; arraycls.$meta = { item : cls, supertypes : [$rt_objcls()], primitive : false, superclass : $rt_objcls(), - name : name, binaryName : name }; + name : name, binaryName : name, enum : false }; + arraycls.classObject = null; cls.$array = arraycls; } return cls.$array; } function $rt_createcls() { return { + classObject : null, $meta : { - supertypes : [] + supertypes : [], + superclass : null } }; } @@ -147,6 +150,8 @@ function $rt_createPrimitiveCls(name, binaryName) { cls.$meta.primitive = true; cls.$meta.name = name; cls.$meta.binaryName = binaryName; + cls.$meta.enum = false; + cls.$meta.item = null; return cls; } var $rt_booleanclsCache = null; @@ -365,18 +370,21 @@ function $rt_putStderr(ch) { } function $rt_declClass(cls, data) { cls.$meta = {}; - cls.$meta.superclass = data.superclass; - cls.$meta.supertypes = data.interfaces ? data.interfaces.slice() : []; + var m = cls.$meta + m.superclass = typeof(data.superclass) !== 'undefined' ? data.superclass : null; + m.supertypes = data.interfaces ? data.interfaces.slice() : []; if (data.superclass) { - cls.$meta.supertypes.push(data.superclass); + m.supertypes.push(data.superclass); cls.prototype = new data.superclass(); } else { cls.prototype = new Object(); } - cls.$meta.name = data.name; - cls.$meta.binaryName = "L" + data.name + ";"; - cls.$meta.enum = data.enum; + m.name = data.name; + m.binaryName = "L" + data.name + ";"; + m.enum = data.enum; + m.item = null; cls.prototype.constructor = cls; + cls.classObject = null; cls.$clinit = data.clinit ? data.clinit : function() {}; } function $rt_virtualMethods(cls) { diff --git a/teavm-core/src/main/resources/org/teavm/tooling/test/res/junit-support.js b/teavm-core/src/main/resources/org/teavm/tooling/test/res/junit-support.js index 411fca35a..18f25d016 100644 --- a/teavm-core/src/main/resources/org/teavm/tooling/test/res/junit-support.js +++ b/teavm-core/src/main/resources/org/teavm/tooling/test/res/junit-support.js @@ -370,11 +370,11 @@ var JUnitClient = {}; JUnitClient.run = function() { var handler = window.addEventListener("message", function() { window.removeEventListener("message", handler); + var message = {}; try { var instance = new TestClass(); initInstance(instance); runTest(instance, function(restore) { - var message = {}; try { var result = restore(); message.status = "ok"; diff --git a/teavm-jso/src/main/java/org/teavm/jso/plugin/JSNativeGenerator.java b/teavm-jso/src/main/java/org/teavm/jso/plugin/JSNativeGenerator.java index 16792fe25..1bb899f8b 100644 --- a/teavm-jso/src/main/java/org/teavm/jso/plugin/JSNativeGenerator.java +++ b/teavm-jso/src/main/java/org/teavm/jso/plugin/JSNativeGenerator.java @@ -88,7 +88,7 @@ public class JSNativeGenerator implements Injector, DependencyPlugin { } writer.append("))"); break; - case "pass": + case "marshall": context.writeExpr(context.getArgument(0)); break; case "wrap": diff --git a/teavm-platform/src/main/java/org/teavm/platform/Platform.java b/teavm-platform/src/main/java/org/teavm/platform/Platform.java index e115ff33b..acbcd595e 100644 --- a/teavm-platform/src/main/java/org/teavm/platform/Platform.java +++ b/teavm-platform/src/main/java/org/teavm/platform/Platform.java @@ -72,7 +72,7 @@ public final class Platform { @PluggableDependency(PlatformGenerator.class) public static native void initClass(PlatformClass cls); - @GeneratedBy(PlatformGenerator.class) + @InjectedBy(PlatformGenerator.class) @PluggableDependency(PlatformGenerator.class) public static native PlatformClass classFromResource(ClassResource resource); } diff --git a/teavm-platform/src/main/java/org/teavm/platform/PlatformClass.java b/teavm-platform/src/main/java/org/teavm/platform/PlatformClass.java index b127fe84f..abb9bcd46 100644 --- a/teavm-platform/src/main/java/org/teavm/platform/PlatformClass.java +++ b/teavm-platform/src/main/java/org/teavm/platform/PlatformClass.java @@ -17,13 +17,12 @@ package org.teavm.platform; import org.teavm.jso.JSObject; import org.teavm.jso.JSProperty; -import org.teavm.platform.metadata.Resource; /** * * @author Alexey Andreev */ -public interface PlatformClass extends JSObject, Resource { +public interface PlatformClass extends JSObject { @JSProperty("$meta") PlatformClassMetadata getMetadata(); diff --git a/teavm-platform/src/main/java/org/teavm/platform/PlatformClassMetadata.java b/teavm-platform/src/main/java/org/teavm/platform/PlatformClassMetadata.java index 80a540f60..d17dfc703 100644 --- a/teavm-platform/src/main/java/org/teavm/platform/PlatformClassMetadata.java +++ b/teavm-platform/src/main/java/org/teavm/platform/PlatformClassMetadata.java @@ -38,9 +38,6 @@ public interface PlatformClassMetadata extends JSObject { @JSProperty boolean isPrimitive(); - @JSProperty - boolean isArray(); - @JSProperty boolean isEnum(); } diff --git a/teavm-platform/src/main/java/org/teavm/platform/PlatformPrimitives.java b/teavm-platform/src/main/java/org/teavm/platform/PlatformPrimitives.java index f1a9b9cf9..7a7556958 100644 --- a/teavm-platform/src/main/java/org/teavm/platform/PlatformPrimitives.java +++ b/teavm-platform/src/main/java/org/teavm/platform/PlatformPrimitives.java @@ -15,38 +15,38 @@ */ package org.teavm.platform; +import org.teavm.jso.JSMethod; import org.teavm.jso.JSObject; -import org.teavm.jso.JSProperty; /** * * @author Alexey Andreev */ public interface PlatformPrimitives extends JSObject { - @JSProperty("$rt_voidcls") + @JSMethod("$rt_voidcls") PlatformClass getVoidClass(); - @JSProperty("$rt_booleancls") + @JSMethod("$rt_booleancls") PlatformClass getBooleanClass(); - @JSProperty("$rt_bytecls") + @JSMethod("$rt_bytecls") PlatformClass getByteClass(); - @JSProperty("$rt_shortcls") + @JSMethod("$rt_shortcls") PlatformClass getShortClass(); - @JSProperty("$rt_charcls") + @JSMethod("$rt_charcls") PlatformClass getCharClass(); - @JSProperty("$rt_intcls") + @JSMethod("$rt_intcls") PlatformClass getIntClass(); - @JSProperty("$rt_longcls") + @JSMethod("$rt_longcls") PlatformClass getLongClass(); - @JSProperty("$rt_floatcls") + @JSMethod("$rt_floatcls") PlatformClass getFloatClass(); - @JSProperty("$rt_doublecls") + @JSMethod("$rt_doublecls") PlatformClass getDoubleClass(); } diff --git a/teavm-platform/src/main/java/org/teavm/platform/PlatformSequence.java b/teavm-platform/src/main/java/org/teavm/platform/PlatformSequence.java index c5ce51330..213277406 100644 --- a/teavm-platform/src/main/java/org/teavm/platform/PlatformSequence.java +++ b/teavm-platform/src/main/java/org/teavm/platform/PlatformSequence.java @@ -23,7 +23,7 @@ import org.teavm.jso.JSProperty; * * @author Alexey Andreev */ -public interface PlatformSequence extends JSObject { +public interface PlatformSequence extends JSObject { @JSProperty int getLength(); diff --git a/teavm-platform/src/main/java/org/teavm/platform/metadata/ClassScopedMetadataGenerator.java b/teavm-platform/src/main/java/org/teavm/platform/metadata/ClassScopedMetadataGenerator.java new file mode 100644 index 000000000..a884bfac2 --- /dev/null +++ b/teavm-platform/src/main/java/org/teavm/platform/metadata/ClassScopedMetadataGenerator.java @@ -0,0 +1,35 @@ +/* + * Copyright 2015 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.platform.metadata; + +import java.util.Map; +import org.teavm.model.MethodReference; +import org.teavm.platform.PlatformClass; + +/** + *

Behaviour of this class is similar to {@link MetadataGenerator}. The difference is that method, marked with + * {@link ClassScopedMetadataProvider} must take one argument of type {@link PlatformClass}. It will + * return different resource for each given class, corresponding to map entries, produced by + * {@link #generateMetadata(MetadataGeneratorContext, MethodReference)}. + * + * @see ClassScopedMetadataProvider + * @see MetadataGenerator + * + * @author Alexey Andreev + */ +public interface ClassScopedMetadataGenerator { + Map generateMetadata(MetadataGeneratorContext context, MethodReference method); +} diff --git a/teavm-platform/src/main/java/org/teavm/platform/metadata/ClassScopedMetadataProvider.java b/teavm-platform/src/main/java/org/teavm/platform/metadata/ClassScopedMetadataProvider.java new file mode 100644 index 000000000..617cc36fc --- /dev/null +++ b/teavm-platform/src/main/java/org/teavm/platform/metadata/ClassScopedMetadataProvider.java @@ -0,0 +1,34 @@ +/* + * Copyright 2015 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.platform.metadata; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + *

Binds a {@link ClassScopedMetadataGenerator} to a native method.

+ * + * @see MetadataProvider + * + * @author Alexey Andreev + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface ClassScopedMetadataProvider { + Class value(); +} diff --git a/teavm-platform/src/main/java/org/teavm/platform/metadata/MetadataGenerator.java b/teavm-platform/src/main/java/org/teavm/platform/metadata/MetadataGenerator.java index 92c0ce73a..5ca4546d6 100644 --- a/teavm-platform/src/main/java/org/teavm/platform/metadata/MetadataGenerator.java +++ b/teavm-platform/src/main/java/org/teavm/platform/metadata/MetadataGenerator.java @@ -50,6 +50,8 @@ import org.teavm.model.MethodReference; * *

All other types are not considered to be resources and therefore are not accepted.

* + * @see ClassScopedMetadataGenerator + * * @author Alexey Andreev */ public interface MetadataGenerator { diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/BuildTimeResourceProxyBuilder.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/BuildTimeResourceProxyBuilder.java index a936fee0f..a1cda00fd 100644 --- a/teavm-platform/src/main/java/org/teavm/platform/plugin/BuildTimeResourceProxyBuilder.java +++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/BuildTimeResourceProxyBuilder.java @@ -102,8 +102,8 @@ class BuildTimeResourceProxyBuilder { private void scanIface(Class iface) { if (!Resource.class.isAssignableFrom(iface)) { - throw new IllegalArgumentException("Error creating a new resource of type " + iface.getName() + - ". This type does not implement the " + Resource.class.getName() + " interface"); + throw new IllegalArgumentException("Error creating a new resource of type " + iface.getName() + "." + + " This type does not implement the " + Resource.class.getName() + " interface"); } // Scan methods diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/BuildTimeResourceWriterMethod.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/BuildTimeResourceWriterMethod.java index dead2901c..b24c0547d 100644 --- a/teavm-platform/src/main/java/org/teavm/platform/plugin/BuildTimeResourceWriterMethod.java +++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/BuildTimeResourceWriterMethod.java @@ -36,7 +36,7 @@ class BuildTimeResourceWriterMethod implements BuildTimeResourceMethod { if (i > 0) { writer.append(',').ws(); } - ResourceWriterHelper.writeString(writer, propertyNames[i]); + ResourceWriterHelper.writeIdentifier(writer, propertyNames[i]); writer.ws().append(':').ws(); ResourceWriterHelper.write(writer, proxy.data[i]); } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/impl/ClassLookupDependencySupport.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/ClassLookupDependencySupport.java similarity index 90% rename from teavm-classlib/src/main/java/org/teavm/classlib/impl/ClassLookupDependencySupport.java rename to teavm-platform/src/main/java/org/teavm/platform/plugin/ClassLookupDependencySupport.java index 4d4238300..a57d59b02 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/impl/ClassLookupDependencySupport.java +++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/ClassLookupDependencySupport.java @@ -13,10 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.teavm.classlib.impl; +package org.teavm.platform.plugin; import org.teavm.dependency.*; import org.teavm.model.*; +import org.teavm.platform.Platform; /** * @@ -38,14 +39,14 @@ public class ClassLookupDependencySupport implements DependencyListener { @Override public void methodAchieved(final DependencyAgent agent, MethodDependency method, final CallLocation location) { MethodReference ref = method.getReference(); - if (ref.getClassName().equals("java.lang.Class") && ref.getName().equals("forNameImpl")) { + if (ref.getClassName().equals(Platform.class.getName()) && ref.getName().equals("lookupClass")) { allClasses.addConsumer(new DependencyConsumer() { @Override public void consume(DependencyAgentType type) { ClassReader cls = agent.getClassSource().get(type.getName()); if (cls == null) { return; } - MethodReader initMethod = cls.getMethod(new MethodDescriptor("", ValueType.VOID)); + MethodReader initMethod = cls.getMethod(new MethodDescriptor("", void.class)); if (initMethod != null) { agent.linkMethod(initMethod.getReference(), location).use(); } diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/ClassScopedMetadataProviderNativeGenerator.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/ClassScopedMetadataProviderNativeGenerator.java new file mode 100644 index 000000000..eef273ead --- /dev/null +++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/ClassScopedMetadataProviderNativeGenerator.java @@ -0,0 +1,97 @@ +/* + * Copyright 2015 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.platform.plugin; + +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.Map; +import org.teavm.codegen.SourceWriter; +import org.teavm.javascript.Renderer; +import org.teavm.javascript.spi.Generator; +import org.teavm.javascript.spi.GeneratorContext; +import org.teavm.model.*; +import org.teavm.platform.metadata.ClassScopedMetadataGenerator; +import org.teavm.platform.metadata.ClassScopedMetadataProvider; +import org.teavm.platform.metadata.Resource; + +/** + * + * @author Alexey Andreev + */ +public class ClassScopedMetadataProviderNativeGenerator implements Generator { + @Override + public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException { + // Validate method + ClassReader cls = context.getClassSource().get(methodRef.getClassName()); + MethodReader method = cls.getMethod(methodRef.getDescriptor()); + AnnotationReader providerAnnot = method.getAnnotations().get(ClassScopedMetadataProvider.class.getName()); + if (providerAnnot == null) { + return; + } + if (!method.hasModifier(ElementModifier.NATIVE)) { + context.getDiagnostics().error(new CallLocation(methodRef), "Method {{m0}} is marked with " + + "{{c1}} annotation, but it is not native", methodRef, ClassScopedMetadataProvider.class.getName()); + return; + } + + // Find and instantiate metadata generator + ValueType generatorType = providerAnnot.getValue("value").getJavaClass(); + String generatorClassName = ((ValueType.Object)generatorType).getClassName(); + Class generatorClass; + try { + generatorClass = Class.forName(generatorClassName, true, context.getClassLoader()); + } catch (ClassNotFoundException e) { + context.getDiagnostics().error(new CallLocation(methodRef), "Can't find metadata provider class {{c0}}", + generatorClassName); + return; + } + Constructor cons; + try { + cons = generatorClass.getConstructor(); + } catch (NoSuchMethodException e) { + context.getDiagnostics().error(new CallLocation(methodRef), "Metadata generator {{c0}} does not have " + + "a public no-arg constructor", generatorClassName); + return; + } + ClassScopedMetadataGenerator generator; + try { + generator = (ClassScopedMetadataGenerator)cons.newInstance(); + } catch (IllegalAccessException | InstantiationException | InvocationTargetException e) { + context.getDiagnostics().error(new CallLocation(methodRef), "Error instantiating metadata " + + "generator {{c0}}", generatorClassName); + return; + } + DefaultMetadataGeneratorContext metadataContext = new DefaultMetadataGeneratorContext(context.getClassSource(), + context.getClassLoader(), context.getProperties(), context); + + Map resourceMap = generator.generateMetadata(metadataContext, methodRef); + writer.append("var p").ws().append("=").ws().append("\"" + Renderer.escapeString("$$res_" + + writer.getNaming().getNameFor(methodRef)) + "\"").append(";").softNewLine(); + for (Map.Entry entry : resourceMap.entrySet()) { + writer.appendClass(entry.getKey()).append("[p]").ws().append("=").ws(); + ResourceWriterHelper.write(writer, entry.getValue()); + writer.append(";").softNewLine(); + } + writer.appendMethodBody(methodRef).ws().append('=').ws().append("function(cls)").ws().append("{") + .softNewLine().indent(); + writer.append("return cls.hasOwnProperty(p)").ws().append("?").ws().append("cls[p]").ws().append(":") + .ws().append("null;").softNewLine(); + writer.outdent().append("}").softNewLine(); + writer.append("return ").appendMethodBody(methodRef).append("(").append(context.getParameterName(1)) + .append(");").softNewLine(); + } +} diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/MetadataProviderNativeGenerator.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/MetadataProviderNativeGenerator.java index 5fe2d9204..3d44de603 100644 --- a/teavm-platform/src/main/java/org/teavm/platform/plugin/MetadataProviderNativeGenerator.java +++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/MetadataProviderNativeGenerator.java @@ -41,8 +41,9 @@ public class MetadataProviderNativeGenerator implements Generator { return; } if (!method.hasModifier(ElementModifier.NATIVE)) { - throw new IllegalStateException("Method " + method.getReference() + " was marked with " + - MetadataProvider.class.getName() + " but it is not native"); + context.getDiagnostics().error(new CallLocation(methodRef), "Method {{m0}} is marked with " + + "{{c1}} annotation, but it is not native", methodRef, MetadataProvider.class.getName()); + return; } // Find and instantiate metadata generator @@ -52,23 +53,25 @@ public class MetadataProviderNativeGenerator implements Generator { try { generatorClass = Class.forName(generatorClassName, true, context.getClassLoader()); } catch (ClassNotFoundException e) { - throw new RuntimeException("Can't find metadata generator class: " + generatorClassName, e); + context.getDiagnostics().error(new CallLocation(methodRef), "Can't find metadata provider class {{c0}}", + generatorClassName); + return; } Constructor cons; try { cons = generatorClass.getConstructor(); } catch (NoSuchMethodException e) { - throw new RuntimeException("Metadata generator " + generatorClassName + " does not have a public " + - "no-arg constructor", e); + context.getDiagnostics().error(new CallLocation(methodRef), "Metadata generator {{c0}} does not have " + + "a public no-arg constructor", generatorClassName); + return; } MetadataGenerator generator; try { generator = (MetadataGenerator)cons.newInstance(); - } catch (IllegalAccessException | InstantiationException e) { - throw new RuntimeException("Error instantiating metadata generator " + generatorClassName, e); - } catch (InvocationTargetException e) { - throw new RuntimeException("Error instantiating metadata generator " + generatorClassName, - e.getTargetException()); + } catch (IllegalAccessException | InstantiationException | InvocationTargetException e) { + context.getDiagnostics().error(new CallLocation(methodRef), "Error instantiating metadata " + + "generator {{c0}}", generatorClassName); + return; } DefaultMetadataGeneratorContext metadataContext = new DefaultMetadataGeneratorContext(context.getClassSource(), context.getClassLoader(), context.getProperties(), context); diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/MetadataProviderTransformer.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/MetadataProviderTransformer.java index b2183357a..0bf498544 100644 --- a/teavm-platform/src/main/java/org/teavm/platform/plugin/MetadataProviderTransformer.java +++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/MetadataProviderTransformer.java @@ -18,6 +18,8 @@ package org.teavm.platform.plugin; import org.teavm.diagnostics.Diagnostics; import org.teavm.javascript.spi.GeneratedBy; import org.teavm.model.*; +import org.teavm.platform.PlatformClass; +import org.teavm.platform.metadata.ClassScopedMetadataProvider; import org.teavm.platform.metadata.MetadataProvider; /** @@ -29,13 +31,26 @@ class MetadataProviderTransformer implements ClassHolderTransformer { public void transformClass(ClassHolder cls, ClassReaderSource innerSource, Diagnostics diagnostics) { for (MethodHolder method : cls.getMethods()) { AnnotationReader providerAnnot = method.getAnnotations().get(MetadataProvider.class.getName()); - if (providerAnnot == null) { - continue; + if (providerAnnot != null) { + AnnotationHolder genAnnot = new AnnotationHolder(GeneratedBy.class.getName()); + genAnnot.getValues().put("value", new AnnotationValue(ValueType.object( + MetadataProviderNativeGenerator.class.getName()))); + method.getAnnotations().add(genAnnot); + } + providerAnnot = method.getAnnotations().get(ClassScopedMetadataProvider.class.getName()); + if (providerAnnot != null) { + ValueType[] params = method.getParameterTypes(); + if (params.length != 1 && params[0].isObject(PlatformClass.class.getName())) { + diagnostics.error(new CallLocation(method.getReference()), "Method {{m0}} marked with {{c1}} " + + "must take exactly one parameter of type {{c2}}", + method.getReference(), ClassScopedMetadataProvider.class.getName(), + PlatformClass.class.getName()); + } + AnnotationHolder genAnnot = new AnnotationHolder(GeneratedBy.class.getName()); + genAnnot.getValues().put("value", new AnnotationValue(ValueType.object( + ClassScopedMetadataProviderNativeGenerator.class.getName()))); + method.getAnnotations().add(genAnnot); } - AnnotationHolder genAnnot = new AnnotationHolder(GeneratedBy.class.getName()); - genAnnot.getValues().put("value", new AnnotationValue(ValueType.object( - MetadataProviderNativeGenerator.class.getName()))); - method.getAnnotations().add(genAnnot); } } } diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/PlatformGenerator.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/PlatformGenerator.java index 1e83f74e1..29514da6f 100644 --- a/teavm-platform/src/main/java/org/teavm/platform/plugin/PlatformGenerator.java +++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/PlatformGenerator.java @@ -25,7 +25,6 @@ import org.teavm.javascript.spi.GeneratorContext; import org.teavm.javascript.spi.Injector; import org.teavm.javascript.spi.InjectorContext; import org.teavm.model.*; -import org.teavm.platform.Platform; /** * @@ -45,6 +44,7 @@ public class PlatformGenerator implements Generator, Injector, DependencyPlugin public void generate(InjectorContext context, MethodReference methodRef) throws IOException { switch (methodRef.getName()) { case "asJavaClass": + case "classFromResource": context.writeExpr(context.getArgument(0)); return; } @@ -54,34 +54,45 @@ public class PlatformGenerator implements Generator, Injector, DependencyPlugin public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException { switch (methodRef.getName()) { case "newInstance": - generateNewInstance(context, writer); + generateNewInstance(context, writer, methodRef); + break; + case "lookupClass": + generateLookup(context, writer); + break; } } - private void generateNewInstance(GeneratorContext context, SourceWriter writer) throws IOException { - String self = context.getParameterName(0); - writer.append("if").ws().append("(!").appendClass(Platform.class).append(".$$constructors$$)").ws() - .append("{").indent().softNewLine(); - writer.appendClass(Platform.class).append(".$$constructors$$").ws().append("=").append("true;").softNewLine(); + private void generateNewInstance(GeneratorContext context, SourceWriter writer, MethodReference methodRef) + throws IOException { + writer.append("var c").ws().append("=").ws().append("'$$constructor$$';").softNewLine(); for (String clsName : context.getClassSource().getClassNames()) { ClassReader cls = context.getClassSource().get(clsName); MethodReader method = cls.getMethod(new MethodDescriptor("", void.class)); if (method != null) { - writer.appendClass(clsName).append(".$$constructor$$").ws().append("=").ws() - .appendMethodBody(method.getReference()).append(";").softNewLine(); + writer.appendClass(clsName).append("[c]").ws().append("=").ws() + .append(writer.getNaming().getNameForInit(method.getReference())) + .append(";").softNewLine(); } } + writer.appendMethodBody(methodRef).ws().append("=").ws().append("function(cls)").ws().append("{") + .softNewLine().indent(); + writer.append("if").ws().append("(!cls.hasOwnProperty(c))").ws().append("{").indent().softNewLine(); + writer.append("return null;").softNewLine(); writer.outdent().append("}").softNewLine(); - writer.append("var cls = " + self + ".$data;").softNewLine(); - writer.append("var ctor = cls.$$constructor$$;").softNewLine(); - writer.append("if (!ctor) {").indent().softNewLine(); - writer.append("var ex = new ").appendClass(InstantiationException.class.getName()).append("();").softNewLine(); - writer.appendMethodBody(new MethodReference(InstantiationException.class, "", void.class)) - .append("(ex);").softNewLine(); - writer.append("$rt_throw(ex);").softNewLine(); + writer.append("return cls[c]();").softNewLine(); + writer.outdent().append("}").softNewLine(); + writer.append("return ").appendMethodBody(methodRef).append("(") + .append(context.getParameterName(1)).append(");").softNewLine(); + } + + private void generateLookup(GeneratorContext context, SourceWriter writer) throws IOException { + String param = context.getParameterName(1); + writer.append("switch ($rt_ustr(" + param + ")) {").softNewLine().indent(); + for (String name : context.getClassSource().getClassNames()) { + writer.append("case \"" + name + "\": ").appendClass(name).append(".$clinit(); ") + .append("return ").appendClass(name).append(";").softNewLine(); + } + writer.append("default: return null;").softNewLine(); writer.outdent().append("}").softNewLine(); - writer.append("var instance = new cls();").softNewLine(); - writer.append("ctor(instance);").softNewLine(); - writer.append("return instance;").softNewLine(); } } diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/PlatformPlugin.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/PlatformPlugin.java index e722ccfd8..805709fac 100644 --- a/teavm-platform/src/main/java/org/teavm/platform/plugin/PlatformPlugin.java +++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/PlatformPlugin.java @@ -31,5 +31,6 @@ public class PlatformPlugin implements TeaVMPlugin { host.add(new ResourceAccessorDependencyListener()); host.add(new AsyncMethodProcessor()); host.add(new NewInstanceDependencySupport()); + host.add(new ClassLookupDependencySupport()); } } diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceWriterHelper.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceWriterHelper.java index af816217f..715d248ba 100644 --- a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceWriterHelper.java +++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceWriterHelper.java @@ -45,6 +45,34 @@ final class ResourceWriterHelper { } } + public static void writeIdentifier(SourceWriter writer, String id) throws IOException { + if (id.isEmpty() || !isIdentifierStart(id.charAt(0))) { + writeString(writer, id); + return; + } + for (int i = 1; i < id.length(); ++i) { + if (isIdentifierPart(id.charAt(i))) { + writeString(writer, id); + return; + } + } + writer.append(id); + } + + private static boolean isIdentifierStart(char c) { + if (c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z') { + return true; + } + return c == '$' || c == '_'; + } + + private static boolean isIdentifierPart(char c) { + if (isIdentifierStart(c)) { + return true; + } + return c >= '0' && c <= '9'; + } + public static void writeString(SourceWriter writer, String s) throws IOException { writer.append('"'); for (int i = 0; i < s.length(); ++i) {