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 e896ebbf2..4914f43a9 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/Renderer.java +++ b/teavm-core/src/main/java/org/teavm/javascript/Renderer.java @@ -228,6 +228,7 @@ public class Renderer implements ExprVisitor, StatementVisitor { } writer.ws().append("});").newLine().outdent(); List nonInitMethods = new ArrayList<>(); + List virtualMethods = new ArrayList<>(); if (!cls.getModifiers().contains(NodeModifier.INTERFACE)) { writer.append("function ").appendClass(cls.getName()).append("_$clinit()").ws() .append("{").softNewLine().indent(); @@ -252,8 +253,10 @@ public class Renderer implements ExprVisitor, StatementVisitor { writer.outdent().append("}").newLine(); for (MethodNode method : cls.getMethods()) { cls.getMethods(); - if (!method.getModifiers().contains(NodeModifier.STATIC) || method.isOriginalNamePreserved()) { - renderDeclaration(method); + if (!method.getModifiers().contains(NodeModifier.STATIC)) { + virtualMethods.add(method); + } else if (method.isOriginalNamePreserved()) { + renderStaticDeclaration(method); } } if (stubNames.size() > 0) { @@ -271,6 +274,7 @@ public class Renderer implements ExprVisitor, StatementVisitor { for (MethodNode method : nonInitMethods) { renderBody(method, false); } + renderVirtualDeclarations(cls.getName(), virtualMethods); } catch (NamingException e) { throw new RenderingException("Error rendering class " + cls.getName() + ". See a cause for details", e); } catch (IOException e) { @@ -327,45 +331,46 @@ public class Renderer implements ExprVisitor, StatementVisitor { writer.outdent().append("}").newLine(); } - public void renderDeclaration(MethodNode method) throws RenderingException, IOException { - try { - if (method.getModifiers().contains(NodeModifier.STATIC)) { - renderStaticDeclaration(method); + private void renderVirtualDeclarations(String className, List methods) + throws NamingException, IOException { + for (MethodNode method : methods) { + MethodReference ref = method.getReference(); + if (ref.getDescriptor().getName().equals("")) { + renderInitializer(method); + } + } + if (methods.isEmpty()) { + return; + } + writer.append("$rt_virtualMethods(").appendClass(className).indent(); + for (MethodNode method : methods) { + MethodReference ref = method.getReference(); + writer.append(",").newLine(); + if (method.isOriginalNamePreserved()) { + writer.append("[\"").appendMethod(ref).append("\",").ws().append("\"").append(ref.getName()) + .append("\"]"); } else { - renderVirtualDeclaration(method); + writer.append("\"").appendMethod(ref).append("\""); } - } catch (NamingException e) { - throw new RenderingException("Error rendering method " + method.getReference() + ". " + - "See cause for details", e); - } - } - - private void renderVirtualDeclaration(MethodNode method) throws NamingException, IOException { - MethodReference ref = method.getReference(); - if (ref.getDescriptor().getName().equals("")) { - renderInitializer(method); - } - writer.appendClass(ref.getClassName()).append(".prototype.").appendMethod(ref) - .ws().append("=").ws().append("function("); - for (int i = 1; i <= ref.parameterCount(); ++i) { - if (i > 1) { - writer.append(", "); + writer.append(",").ws().append("function("); + for (int i = 1; i <= ref.parameterCount(); ++i) { + if (i > 1) { + writer.append(",").ws(); + } + writer.append(variableName(i)); } - writer.append(variableName(i)); - } - writer.append(")").ws().append("{").softNewLine().indent(); - writer.append("return ").appendMethodBody(ref).append("("); - writer.append("this"); - for (int i = 1; i <= ref.parameterCount(); ++i) { - writer.append(",").ws().append(variableName(i)); - } - writer.append(");").softNewLine(); - writer.outdent().append("}").newLine(); - if (method.isOriginalNamePreserved()) { - writer.appendClass(ref.getClassName()).append(".prototype.").append(ref.getName()).ws().append("=") - .ws().appendClass(ref.getClassName()).append(".prototype.").appendMethod(ref) - .append(';').newLine(); + writer.append(")").ws().append("{").ws(); + if (ref.getDescriptor().getResultType() != ValueType.VOID) { + writer.append("return "); + } + writer.appendMethodBody(ref).append("("); + writer.append("this"); + for (int i = 1; i <= ref.parameterCount(); ++i) { + writer.append(",").ws().append(variableName(i)); + } + writer.append(");").ws().append("}"); } + writer.append(");").newLine().outdent(); } private void renderStaticDeclaration(MethodNode method) throws NamingException, IOException { 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 6282ff0bc..69b4af673 100644 --- a/teavm-core/src/main/resources/org/teavm/javascript/runtime.js +++ b/teavm-core/src/main/resources/org/teavm/javascript/runtime.js @@ -387,6 +387,19 @@ function $rt_declClass(cls, data) { cls.prototype.constructor = cls; cls.$clinit = data.clinit; } +function $rt_virtualMethods(cls) { + for (var i = 1; i < arguments.length; i += 2) { + var name = arguments[i]; + var func = arguments[i + 1]; + if (typeof name == 'string') { + cls.prototype[name] = func; + } else { + for (var j = 0; j < name.length; ++j) { + cls.prototype[name[j]] = func; + } + } + } +} Long = function(lo, hi) { this.lo = lo | 0;