From 4908293e503e213e57bd3a929f8a792f3ddec44f Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Tue, 24 Feb 2015 15:51:27 +0400 Subject: [PATCH] Fix NPE in Renderer: https://github.com/konsoletyper/teavm/issues/76 Add async support in Class.newInstance() --- .../java/org/teavm/javascript/Renderer.java | 15 +++-- .../plugin/NewInstanceDependencySupport.java | 5 +- .../platform/plugin/PlatformGenerator.java | 62 ++++++++++++++++--- 3 files changed, 65 insertions(+), 17 deletions(-) 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 a20cadb5c..b28568e48 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/Renderer.java +++ b/teavm-core/src/main/java/org/teavm/javascript/Renderer.java @@ -1955,13 +1955,16 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext private Injector getInjector(MethodReference ref) { InjectorHolder holder = injectorMap.get(ref); if (holder == null) { - MethodHolder method = classSource.get(ref.getClassName()).getMethod(ref.getDescriptor()); holder = new InjectorHolder(null); - if (method != null) { - AnnotationHolder injectedByAnnot = method.getAnnotations().get(InjectedBy.class.getName()); - if (injectedByAnnot != null) { - ValueType type = injectedByAnnot.getValues().get("value").getJavaClass(); - holder = new InjectorHolder(instantiateInjector(((ValueType.Object)type).getClassName())); + ClassHolder cls = classSource.get(ref.getClassName()); + if (cls != null) { + MethodHolder method = cls.getMethod(ref.getDescriptor()); + if (method != null) { + AnnotationHolder injectedByAnnot = method.getAnnotations().get(InjectedBy.class.getName()); + if (injectedByAnnot != null) { + ValueType type = injectedByAnnot.getValues().get("value").getJavaClass(); + holder = new InjectorHolder(instantiateInjector(((ValueType.Object)type).getClassName())); + } } } injectorMap.put(ref, holder); diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/NewInstanceDependencySupport.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/NewInstanceDependencySupport.java index 14897e80b..346500701 100644 --- a/teavm-platform/src/main/java/org/teavm/platform/plugin/NewInstanceDependencySupport.java +++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/NewInstanceDependencySupport.java @@ -47,13 +47,14 @@ public class NewInstanceDependencySupport implements DependencyListener { } @Override - public void methodAchieved(final DependencyAgent agent, MethodDependency method, final CallLocation location) { + public void methodAchieved(final DependencyAgent agent, MethodDependency method, CallLocation location) { MethodReader reader = method.getMethod(); if (reader.getOwnerName().equals(Platform.class.getName()) && reader.getName().equals("newInstance")) { allClassesNode.connect(method.getResult()); + final MethodReference methodRef = reader.getReference(); method.getResult().addConsumer(new DependencyConsumer() { @Override public void consume(DependencyAgentType type) { - attachConstructor(agent, type.getName(), location); + attachConstructor(agent, type.getName(), new CallLocation(methodRef)); } }); } 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 8085d7263..3e57b6b1e 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 @@ -91,24 +91,68 @@ public class PlatformGenerator implements Generator, Injector, DependencyPlugin private void generateNewInstance(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException { writer.append("var c").ws().append("=").ws().append("'$$constructor$$';").softNewLine(); + if (context.isAsync()) { + writer.append("function async(cls, init) {").indent().softNewLine(); + writer.append("return function($return) {").indent().softNewLine(); + writer.append("var r = new cls;").softNewLine(); + writer.append("init(r, $rt_guardAsync(function($restore) {").indent().softNewLine(); + writer.append("$restore();").softNewLine(); + writer.append("$return($rt_asyncResult(r))").softNewLine(); + writer.outdent().append("}));").softNewLine(); + writer.outdent().append("};").softNewLine(); + writer.outdent().append("}").softNewLine(); + + writer.append("function sync(cls, init) {").indent().softNewLine(); + writer.append("return function($return) {").indent().softNewLine(); + writer.append("var r = new cls;").softNewLine(); + writer.append("try {").indent().softNewLine(); + writer.append("init(r);").softNewLine(); + writer.append("$return($rt_asyncResult(r));").softNewLine(); + writer.outdent().append("} catch (e) {").indent().softNewLine(); + writer.append("$return($rt_asyncError(e));").softNewLine(); + writer.outdent().append("}").softNewLine(); + writer.outdent().append("};").softNewLine(); + writer.outdent().append("}").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("[c]").ws().append("=").ws() - .append(writer.getNaming().getNameForInit(method.getReference())) - .append(";").softNewLine(); + writer.appendClass(clsName).append("[c]").ws().append("=").ws(); + if (!context.isAsync()) { + writer.append(writer.getNaming().getNameForInit(method.getReference())); + } else { + String function = context.isAsync(method.getReference()) ? "async" : "sync"; + writer.append(function).append("(").appendClass(clsName).append(',').ws() + .appendMethodBody(method.getReference()).append(")"); + } + writer.append(";").softNewLine(); } } - writer.appendMethodBody(methodRef).ws().append("=").ws().append("function(cls)").ws().append("{") - .softNewLine().indent(); + writer.appendMethodBody(methodRef).ws().append("=").ws().append("function(cls"); + if (context.isAsync()) { + writer.append(',').ws().append("$return"); + } + writer.append(")").ws().append("{").softNewLine().indent(); writer.append("if").ws().append("(!cls.hasOwnProperty(c))").ws().append("{").indent().softNewLine(); - writer.append("return null;").softNewLine(); + if (!context.isAsync()) { + writer.append("return null;").softNewLine(); + } else { + writer.append("return $return($rt_asyncResult(null));").softNewLine(); + } writer.outdent().append("}").softNewLine(); - writer.append("return cls[c]();").softNewLine(); + if (!context.isAsync()) { + writer.append("return cls[c]();").softNewLine(); + } else { + writer.append("return cls[c]($return);").softNewLine(); + } writer.outdent().append("}").softNewLine(); - writer.append("return ").appendMethodBody(methodRef).append("(") - .append(context.getParameterName(1)).append(");").softNewLine(); + + writer.append("return ").appendMethodBody(methodRef).append("(").append(context.getParameterName(1)); + if (context.isAsync()) { + writer.append(',').ws().append("$return"); + } + writer.append(");").softNewLine(); } private void generateLookup(GeneratorContext context, SourceWriter writer) throws IOException {