diff --git a/classlib/src/main/java/org/teavm/classlib/java/lang/ClassGenerator.java b/classlib/src/main/java/org/teavm/classlib/java/lang/ClassGenerator.java index c1ef07694..5fea93452 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/lang/ClassGenerator.java +++ b/classlib/src/main/java/org/teavm/classlib/java/lang/ClassGenerator.java @@ -292,7 +292,7 @@ public class ClassGenerator implements Generator, Injector, DependencyPlugin { private void initClass(SourceWriter writer, MemberReader member) throws IOException { if (member.hasModifier(ElementModifier.STATIC)) { - writer.append(writer.getNaming().getNameForClassInit(member.getOwnerName())).append("();").softNewLine(); + writer.appendClassInit(member.getOwnerName()).append("();").softNewLine(); } } diff --git a/classlib/src/main/java/org/teavm/classlib/java/lang/reflect/ArrayNativeGenerator.java b/classlib/src/main/java/org/teavm/classlib/java/lang/reflect/ArrayNativeGenerator.java index cea4ad923..177a182ef 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/lang/reflect/ArrayNativeGenerator.java +++ b/classlib/src/main/java/org/teavm/classlib/java/lang/reflect/ArrayNativeGenerator.java @@ -94,7 +94,7 @@ public class ArrayNativeGenerator implements Generator, DependencyPlugin { writer.append("if (" + array + " === null || " + array + ".constructor.$meta.item === undefined) {") .softNewLine().indent(); MethodReference cons = new MethodReference("java.lang.IllegalArgumentException", "", ValueType.VOID); - writer.append("$rt_throw(").append(writer.getNaming().getNameForInit(cons)).append("());").softNewLine(); + writer.append("$rt_throw(").appendInit(cons).append("());").softNewLine(); writer.outdent().append("}").softNewLine(); writer.append("return " + array + ".data.length;").softNewLine(); } diff --git a/core/src/main/java/org/teavm/backend/javascript/JavaScriptTarget.java b/core/src/main/java/org/teavm/backend/javascript/JavaScriptTarget.java index 0c79b9e89..c92776325 100644 --- a/core/src/main/java/org/teavm/backend/javascript/JavaScriptTarget.java +++ b/core/src/main/java/org/teavm/backend/javascript/JavaScriptTarget.java @@ -112,6 +112,7 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost { private final Set asyncFamilyMethods = new HashSet<>(); private ClassInitializerInsertionTransformer clinitInsertionTransformer; private List customVirtualMethods = new ArrayList<>(); + private boolean classScoped; @Override public List getTransformers() { @@ -190,6 +191,10 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost { this.debugEmitter = debugEmitter; } + public void setClassScoped(boolean classScoped) { + this.classScoped = classScoped; + } + @Override public boolean requiresRegisterAllocation() { return true; @@ -306,6 +311,7 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost { DefaultNamingStrategy naming = new DefaultNamingStrategy(aliasProvider, controller.getUnprocessedClassSource()); SourceWriterBuilder builder = new SourceWriterBuilder(naming); builder.setMinified(minifying); + builder.setClassScoped(classScoped); SourceWriter sourceWriter = builder.build(writer); DebugInformationEmitter debugEmitterToUse = debugEmitter; @@ -320,7 +326,7 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost { controller.getDependencyInfo(), m -> isVirtual(virtualMethodContributorContext, m)); renderingContext.setMinifying(minifying); Renderer renderer = new Renderer(sourceWriter, asyncMethods, asyncFamilyMethods, - controller.getDiagnostics(), renderingContext); + controller.getDiagnostics(), renderingContext, classScoped); RuntimeRenderer runtimeRenderer = new RuntimeRenderer(classes, naming, sourceWriter); renderer.setProperties(controller.getProperties()); renderer.setMinifying(minifying); @@ -373,7 +379,7 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost { : controller.getEntryPoints().entrySet()) { sourceWriter.append("").append(entry.getKey()).ws().append("=").ws(); MethodReference ref = entry.getValue().getMethod(); - sourceWriter.append("$rt_mainStarter(").append(naming.getFullNameFor(ref)); + sourceWriter.append("$rt_mainStarter(").appendMethodBody(ref); sourceWriter.append(");").newLine(); } diff --git a/core/src/main/java/org/teavm/backend/javascript/codegen/SourceWriter.java b/core/src/main/java/org/teavm/backend/javascript/codegen/SourceWriter.java index 3e14a850b..6e724cfff 100644 --- a/core/src/main/java/org/teavm/backend/javascript/codegen/SourceWriter.java +++ b/core/src/main/java/org/teavm/backend/javascript/codegen/SourceWriter.java @@ -31,11 +31,13 @@ public class SourceWriter implements Appendable, LocationProvider { private int column; private int line; private int offset; + private boolean classScoped; - SourceWriter(NamingStrategy naming, Appendable innerWriter, int lineWidth) { + SourceWriter(NamingStrategy naming, Appendable innerWriter, int lineWidth, boolean classScoped) { this.naming = naming; this.innerWriter = innerWriter; this.lineWidth = lineWidth; + this.classScoped = classScoped; } void setMinified(boolean minified) { @@ -111,6 +113,7 @@ public class SourceWriter implements Appendable, LocationProvider { } public SourceWriter appendStaticField(FieldReference field) throws IOException { + appendClassScopeIfNecessary(field.getClassName()); return append(naming.getFullNameFor(field)); } @@ -123,21 +126,38 @@ public class SourceWriter implements Appendable, LocationProvider { } public SourceWriter appendMethodBody(MethodReference method) throws IOException { + appendClassScopeIfNecessary(method.getClassName()); return append(naming.getFullNameFor(method)); } public SourceWriter appendMethodBody(String className, String name, ValueType... params) throws IOException { - return append(naming.getFullNameFor(new MethodReference(className, new MethodDescriptor(name, params)))); + return appendMethodBody(new MethodReference(className, new MethodDescriptor(name, params))); } public SourceWriter appendMethodBody(Class cls, String name, Class... params) throws IOException { - return append(naming.getFullNameFor(new MethodReference(cls, name, params))); + return appendMethodBody(new MethodReference(cls, name, params)); } public SourceWriter appendFunction(String name) throws IOException { return append(naming.getNameForFunction(name)); } + public SourceWriter appendInit(MethodReference method) throws IOException { + appendClassScopeIfNecessary(method.getClassName()); + return append(naming.getNameForInit(method)); + } + + public SourceWriter appendClassInit(String className) throws IOException { + appendClassScopeIfNecessary(className); + return append(naming.getNameForClassInit(className)); + } + + private void appendClassScopeIfNecessary(String className) throws IOException { + if (classScoped) { + append(naming.getNameFor(className)).append("."); + } + } + private void appendIndent() throws IOException { if (minified) { return; diff --git a/core/src/main/java/org/teavm/backend/javascript/codegen/SourceWriterBuilder.java b/core/src/main/java/org/teavm/backend/javascript/codegen/SourceWriterBuilder.java index 8ecdd12ee..56785b3bf 100644 --- a/core/src/main/java/org/teavm/backend/javascript/codegen/SourceWriterBuilder.java +++ b/core/src/main/java/org/teavm/backend/javascript/codegen/SourceWriterBuilder.java @@ -18,6 +18,7 @@ package org.teavm.backend.javascript.codegen; public class SourceWriterBuilder { private NamingStrategy naming; private boolean minified; + private boolean classScoped; private int lineWidth = 512; public SourceWriterBuilder(NamingStrategy naming) { @@ -36,8 +37,12 @@ public class SourceWriterBuilder { this.lineWidth = lineWidth; } + public void setClassScoped(boolean classScoped) { + this.classScoped = classScoped; + } + public SourceWriter build(Appendable innerWriter) { - SourceWriter writer = new SourceWriter(naming, innerWriter, lineWidth); + SourceWriter writer = new SourceWriter(naming, innerWriter, lineWidth, classScoped); writer.setMinified(minified); return writer; } diff --git a/core/src/main/java/org/teavm/backend/javascript/rendering/AstWriter.java b/core/src/main/java/org/teavm/backend/javascript/rendering/AstWriter.java index 05b0eda9b..c8a9264ec 100644 --- a/core/src/main/java/org/teavm/backend/javascript/rendering/AstWriter.java +++ b/core/src/main/java/org/teavm/backend/javascript/rendering/AstWriter.java @@ -419,7 +419,7 @@ public class AstWriter { } writer.outdent(); } - writer.append('}'); + writer.outdent().append('}'); } private void print(TryStatement node) throws IOException { diff --git a/core/src/main/java/org/teavm/backend/javascript/rendering/Renderer.java b/core/src/main/java/org/teavm/backend/javascript/rendering/Renderer.java index 1973a9cf4..69c19719d 100644 --- a/core/src/main/java/org/teavm/backend/javascript/rendering/Renderer.java +++ b/core/src/main/java/org/teavm/backend/javascript/rendering/Renderer.java @@ -65,6 +65,7 @@ public class Renderer implements RenderingManager { private final ListableClassReaderSource classSource; private final ClassLoader classLoader; private boolean minifying; + private boolean classScoped; private final Properties properties = new Properties(); private final ServiceRepository services; private DebugInformationEmitter debugEmitter = new DummyDebugInformationEmitter(); @@ -83,7 +84,7 @@ public class Renderer implements RenderingManager { private boolean threadLibraryUsed; public Renderer(SourceWriter writer, Set asyncMethods, Set asyncFamilyMethods, - Diagnostics diagnostics, RenderingContext context) { + Diagnostics diagnostics, RenderingContext context, boolean classScoped) { this.naming = context.getNaming(); this.writer = writer; this.classSource = context.getClassSource(); @@ -93,6 +94,7 @@ public class Renderer implements RenderingManager { this.asyncFamilyMethods = new HashSet<>(asyncFamilyMethods); this.diagnostics = diagnostics; this.context = context; + this.classScoped = classScoped; } public boolean isLongLibraryUsed() { @@ -294,7 +296,7 @@ public class Renderer implements RenderingManager { } private void renderDeclaration(ClassNode cls) throws RenderingException { - String jsName = writer.getNaming().getNameFor(cls.getName()); + String jsName = naming.getNameFor(cls.getName()); debugEmitter.addClass(jsName, cls.getName(), cls.getParentName()); try { writer.append("function " + jsName + "()").ws().append("{") @@ -345,7 +347,12 @@ public class Renderer implements RenderingManager { postponedFieldInitializers.add(new PostponedFieldInitializer(fieldRef, (String) value)); value = null; } - writer.append("var ").appendStaticField(fieldRef).ws().append("=").ws() + if (classScoped) { + writer.append(jsName).append("."); + } else { + writer.append("var "); + } + writer.append(naming.getFullNameFor(fieldRef)).ws().append("=").ws() .append(context.constantToString(value)).append(";").softNewLine(); } } catch (IOException e) { @@ -366,14 +373,14 @@ public class Renderer implements RenderingManager { for (MethodNode method : cls.getMethods()) { if (!method.getModifiers().contains(ElementModifier.STATIC)) { if (method.getReference().getName().equals("")) { - renderInitializer(method); + renderInitializer(cls.getName(), method); } } } } for (MethodNode method : cls.getMethods()) { - renderBody(method); + renderBody(cls.getName(), method); } } catch (IOException e) { throw new RenderingException("IO error occurred", e); @@ -390,7 +397,8 @@ public class Renderer implements RenderingManager { .append("false;").softNewLine(); } - writer.append("function ").append(naming.getNameForClassInit(cls.getName())).append("()").ws() + renderFunctionDeclaration(cls.getName(), naming.getNameForClassInit(cls.getName())); + writer.append("()").ws() .append("{").softNewLine().indent(); if (isAsync) { @@ -435,11 +443,15 @@ public class Renderer implements RenderingManager { writer.appendFunction("$rt_nativeThread").append("().push(" + context.pointerName() + ");").softNewLine(); } - writer.outdent().append("}").newLine(); + writer.outdent().append("}"); + if (classScoped) { + writer.append(";"); + } + writer.newLine(); } private void renderEraseClinit(ClassNode cls) throws IOException { - writer.append(naming.getNameForClassInit(cls.getName())).ws().append("=").ws() + writer.appendClassInit(cls.getName()).ws().append("=").ws() .appendFunction("$rt_eraseClinit").append("(") .appendClass(cls.getName()).append(");").softNewLine(); } @@ -514,7 +526,7 @@ public class Renderer implements RenderingManager { MethodReader clinit = classSource.get(cls.getName()).getMethod( new MethodDescriptor("", ValueType.VOID)); if (clinit != null) { - writer.append(naming.getNameForClassInit(cls.getName())); + writer.appendClassInit(cls.getName()); } else { writer.append('0'); } @@ -676,10 +688,11 @@ public class Renderer implements RenderingManager { return null; } - private void renderInitializer(MethodNode method) throws IOException { + private void renderInitializer(String className, MethodNode method) throws IOException { MethodReference ref = method.getReference(); debugEmitter.emitMethod(ref.getDescriptor()); - writer.append("function ").append(naming.getNameForInit(ref)).append("("); + renderFunctionDeclaration(className, naming.getNameForInit(ref)); + writer.append("("); for (int i = 0; i < ref.parameterCount(); ++i) { if (i > 0) { writer.append(",").ws(); @@ -691,14 +704,18 @@ public class Renderer implements RenderingManager { String instanceName = variableNameForInitializer(ref.parameterCount()); writer.append("var " + instanceName).ws().append("=").ws().append("new ").appendClass( ref.getClassName()).append("();").softNewLine(); - writer.append(naming.getFullNameFor(ref)).append("(" + instanceName); + writer.appendMethodBody(ref).append("(" + instanceName); for (int i = 0; i < ref.parameterCount(); ++i) { writer.append(",").ws(); writer.append(variableNameForInitializer(i)); } writer.append(");").softNewLine(); writer.append("return " + instanceName + ";").softNewLine(); - writer.outdent().append("}").newLine(); + writer.outdent().append("}"); + if (classScoped) { + writer.append(";"); + } + writer.newLine(); debugEmitter.emitMethod(null); } @@ -755,7 +772,7 @@ public class Renderer implements RenderingManager { writer.append(");").ws().append("}"); } - private void renderBody(MethodNode method) throws IOException { + private void renderBody(String className, MethodNode method) throws IOException { StatementRenderer statementRenderer = new StatementRenderer(context, writer); statementRenderer.setCurrentMethod(method); @@ -763,7 +780,8 @@ public class Renderer implements RenderingManager { debugEmitter.emitMethod(ref.getDescriptor()); String name = naming.getFullNameFor(ref); - writer.append("function ").append(name).append("("); + renderFunctionDeclaration(className, name); + writer.append("("); int startParam = 0; if (method.getModifiers().contains(ElementModifier.STATIC)) { startParam = 1; @@ -778,6 +796,9 @@ public class Renderer implements RenderingManager { method.acceptVisitor(new MethodBodyRenderer(statementRenderer)); writer.outdent().append("}"); + if (classScoped) { + writer.append(";"); + } writer.newLine(); debugEmitter.emitMethod(null); @@ -785,6 +806,16 @@ public class Renderer implements RenderingManager { longLibraryUsed |= statementRenderer.isLongLibraryUsed(); } + private void renderFunctionDeclaration(String className, String name) throws IOException { + if (classScoped) { + writer.appendClass(className).append(".").append(name).ws().append("=").ws(); + } + writer.append("function"); + if (!classScoped) { + writer.append(" ").append(name); + } + } + private void renderAsyncPrologue() throws IOException { writer.append(context.mainLoopName()).append(":").ws().append("while").ws().append("(true)") .ws().append("{").ws(); diff --git a/core/src/main/java/org/teavm/backend/javascript/rendering/RuntimeRenderer.java b/core/src/main/java/org/teavm/backend/javascript/rendering/RuntimeRenderer.java index 50836d91d..100421440 100644 --- a/core/src/main/java/org/teavm/backend/javascript/rendering/RuntimeRenderer.java +++ b/core/src/main/java/org/teavm/backend/javascript/rendering/RuntimeRenderer.java @@ -124,7 +124,7 @@ public class RuntimeRenderer { writer.append("for (var i = 0; i < str.length; i = (i + 1) | 0) {").indent().softNewLine(); writer.append("charsBuffer[i] = str.charCodeAt(i) & 0xFFFF;").softNewLine(); writer.outdent().append("}").softNewLine(); - writer.append("return ").append(naming.getNameForInit(stringCons)).append("(characters);").softNewLine(); + writer.append("return ").appendInit(stringCons).append("(characters);").softNewLine(); writer.outdent().append("}").newLine(); } @@ -147,7 +147,7 @@ public class RuntimeRenderer { private void renderRuntimeNullCheck() throws IOException { writer.append("function $rt_nullCheck(val) {").indent().softNewLine(); writer.append("if (val === null) {").indent().softNewLine(); - writer.append("$rt_throw(").append(naming.getNameForInit(NPE_INIT_METHOD)).append("());").softNewLine(); + writer.append("$rt_throw(").appendInit(NPE_INIT_METHOD).append("());").softNewLine(); writer.outdent().append("}").softNewLine(); writer.append("return val;").softNewLine(); writer.outdent().append("}").newLine(); @@ -194,8 +194,7 @@ public class RuntimeRenderer { private void renderRuntimeCreateException() throws IOException { writer.append("function $rt_createException(message)").ws().append("{").indent().softNewLine(); writer.append("return "); - writer.append(writer.getNaming().getNameForInit(new MethodReference(RuntimeException.class, - "", String.class, void.class))); + writer.appendInit(new MethodReference(RuntimeException.class, "", String.class, void.class)); writer.append("(message);").softNewLine(); writer.outdent().append("}").newLine(); } @@ -211,7 +210,7 @@ public class RuntimeRenderer { .append("lineNumber)").ws().append("{").indent().softNewLine(); writer.append("return "); if (supported) { - writer.append(writer.getNaming().getNameForInit(STACK_TRACE_ELEM_INIT)); + writer.appendInit(STACK_TRACE_ELEM_INIT); writer.append("(className,").ws() .append("methodName,").ws() .append("fileName,").ws() diff --git a/core/src/main/java/org/teavm/backend/javascript/rendering/StatementRenderer.java b/core/src/main/java/org/teavm/backend/javascript/rendering/StatementRenderer.java index 35272019e..27d51a630 100644 --- a/core/src/main/java/org/teavm/backend/javascript/rendering/StatementRenderer.java +++ b/core/src/main/java/org/teavm/backend/javascript/rendering/StatementRenderer.java @@ -442,7 +442,7 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor { if (statement.getLocation() != null) { pushLocation(statement.getLocation()); } - writer.append(naming.getNameForClassInit(statement.getClassName())).append("();").softNewLine(); + writer.appendClassInit(statement.getClassName()).append("();").softNewLine(); if (statement.isAsync()) { emitSuspendChecker(); } @@ -1095,7 +1095,7 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor { boolean virtual = false; switch (expr.getType()) { case STATIC: - writer.append(naming.getFullNameFor(method)).append("("); + writer.appendMethodBody(method).append("("); prevCallSite = debugEmitter.emitCallSite(); for (int i = 0; i < expr.getArguments().size(); ++i) { if (i > 0) { @@ -1106,7 +1106,7 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor { } break; case SPECIAL: - writer.append(naming.getFullNameFor(method)).append("("); + writer.appendMethodBody(method).append("("); prevCallSite = debugEmitter.emitCallSite(); precedence = Precedence.min(); expr.getArguments().get(0).acceptVisitor(this); @@ -1129,7 +1129,7 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor { virtual = true; break; case CONSTRUCTOR: - writer.append(naming.getNameForInit(expr.getMethod())).append("("); + writer.appendInit(expr.getMethod()).append("("); prevCallSite = debugEmitter.emitCallSite(); for (int i = 0; i < expr.getArguments().size(); ++i) { if (i > 0) { diff --git a/platform/src/main/java/org/teavm/platform/plugin/PlatformGenerator.java b/platform/src/main/java/org/teavm/platform/plugin/PlatformGenerator.java index 9f79925f3..8ceaea4d1 100644 --- a/platform/src/main/java/org/teavm/platform/plugin/PlatformGenerator.java +++ b/platform/src/main/java/org/teavm/platform/plugin/PlatformGenerator.java @@ -197,9 +197,10 @@ public class PlatformGenerator implements Generator, Injector, DependencyPlugin } } - String selfName = writer.getNaming().getFullNameFor(new MethodReference(Platform.class, "getEnumConstants", - PlatformClass.class, Enum[].class)); - writer.append(selfName).ws().append("=").ws().append("function(cls)").ws().append("{").softNewLine().indent(); + MethodReference selfRef = new MethodReference(Platform.class, "getEnumConstants", + PlatformClass.class, Enum[].class); + writer.appendMethodBody(selfRef).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(); @@ -210,7 +211,7 @@ public class PlatformGenerator implements Generator, Injector, DependencyPlugin writer.append("return cls[c];").softNewLine(); writer.outdent().append("};").softNewLine(); - writer.append("return ").append(selfName).append("(").append(context.getParameterName(1)) + writer.append("return ").appendMethodBody(selfRef).append("(").append(context.getParameterName(1)) .append(");").softNewLine(); } @@ -221,21 +222,22 @@ public class PlatformGenerator implements Generator, Injector, DependencyPlugin if (annotCls != null) { writer.appendClass(clsName).append("[c]").ws().append("=").ws(); MethodReference ctor = new MethodReference(annotCls.getName(), "", ValueType.VOID); - writer.append(writer.getNaming().getNameForInit(ctor)); + writer.appendInit(ctor); writer.append("();").softNewLine(); } } - String selfName = writer.getNaming().getFullNameFor(new MethodReference(Platform.class, "getAnnotations", - PlatformClass.class, Annotation[].class)); - writer.append(selfName).ws().append("=").ws().append("function(cls)").ws().append("{").softNewLine().indent(); + MethodReference selfRef = new MethodReference(Platform.class, "getAnnotations", PlatformClass.class, + Annotation[].class); + writer.appendMethodBody(selfRef).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("return cls[c].").appendMethod("getAnnotations", Annotation[].class).append("();").softNewLine(); writer.outdent().append("};").softNewLine(); - writer.append("return ").append(selfName).append("(").append(context.getParameterName(1)) + writer.append("return ").appendMethodBody(selfRef).append("(").append(context.getParameterName(1)) .append(");").softNewLine(); } } diff --git a/tools/devserver/src/main/java/org/teavm/devserver/CodeServlet.java b/tools/devserver/src/main/java/org/teavm/devserver/CodeServlet.java index 192c1e1c2..be59e91d2 100644 --- a/tools/devserver/src/main/java/org/teavm/devserver/CodeServlet.java +++ b/tools/devserver/src/main/java/org/teavm/devserver/CodeServlet.java @@ -724,6 +724,7 @@ public class CodeServlet extends HttpServlet { jsTarget.setMinifying(false); jsTarget.setAstCache(astCache); jsTarget.setDebugEmitter(debugInformationBuilder); + jsTarget.setClassScoped(true); vm.setOptimizationLevel(TeaVMOptimizationLevel.SIMPLE); vm.setCacheStatus(classSource); vm.addVirtualMethods(m -> true);