javascript: refactor renderer

This commit is contained in:
Alexey Andreev 2016-09-16 22:46:19 +03:00
parent 7cd72f0e96
commit ed7e8ff7f4
18 changed files with 2054 additions and 1815 deletions

View File

@ -8,6 +8,7 @@ import java.util.HashSet;
import java.util.ServiceLoader; import java.util.ServiceLoader;
import java.util.Set; import java.util.Set;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.teavm.backend.javascript.rendering.RenderingUtil;
import org.teavm.classlib.ResourceSupplier; import org.teavm.classlib.ResourceSupplier;
import org.teavm.backend.javascript.codegen.SourceWriter; import org.teavm.backend.javascript.codegen.SourceWriter;
import org.teavm.backend.javascript.rendering.Renderer; import org.teavm.backend.javascript.rendering.Renderer;
@ -54,7 +55,7 @@ public class ClassLoaderNativeGenerator implements Injector {
first = false; first = false;
writer.newLine(); writer.newLine();
String data = Base64.getEncoder().encodeToString(IOUtils.toByteArray(input)); String data = Base64.getEncoder().encodeToString(IOUtils.toByteArray(input));
writer.append("\"").append(Renderer.escapeString(resource)).append("\""); writer.append("\"").append(RenderingUtil.escapeString(resource)).append("\"");
writer.ws().append(':').ws(); writer.ws().append(':').ws();
writer.append("\"").append(data).append("\""); writer.append("\"").append(data).append("\"");
} }

View File

@ -37,11 +37,13 @@ import org.teavm.backend.javascript.codegen.MinifyingAliasProvider;
import org.teavm.backend.javascript.codegen.SourceWriter; import org.teavm.backend.javascript.codegen.SourceWriter;
import org.teavm.backend.javascript.codegen.SourceWriterBuilder; import org.teavm.backend.javascript.codegen.SourceWriterBuilder;
import org.teavm.backend.javascript.rendering.Renderer; import org.teavm.backend.javascript.rendering.Renderer;
import org.teavm.backend.javascript.rendering.RenderingContext;
import org.teavm.backend.javascript.spi.GeneratedBy; import org.teavm.backend.javascript.spi.GeneratedBy;
import org.teavm.backend.javascript.spi.Generator; import org.teavm.backend.javascript.spi.Generator;
import org.teavm.backend.javascript.spi.InjectedBy; import org.teavm.backend.javascript.spi.InjectedBy;
import org.teavm.backend.javascript.spi.Injector; import org.teavm.backend.javascript.spi.Injector;
import org.teavm.debugging.information.DebugInformationEmitter; import org.teavm.debugging.information.DebugInformationEmitter;
import org.teavm.debugging.information.DummyDebugInformationEmitter;
import org.teavm.debugging.information.SourceLocation; import org.teavm.debugging.information.SourceLocation;
import org.teavm.dependency.DependencyChecker; import org.teavm.dependency.DependencyChecker;
import org.teavm.dependency.DependencyListener; import org.teavm.dependency.DependencyListener;
@ -225,8 +227,14 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
builder.setMinified(minifying); builder.setMinified(minifying);
SourceWriter sourceWriter = builder.build(writer); SourceWriter sourceWriter = builder.build(writer);
Renderer renderer = new Renderer(sourceWriter, classes, controller.getClassLoader(), controller.getServices(), DebugInformationEmitter debugEmitterToUse = debugEmitter;
asyncMethods, asyncFamilyMethods, controller.getDiagnostics()); if (debugEmitterToUse == null) {
debugEmitterToUse = new DummyDebugInformationEmitter();
}
RenderingContext renderingContext = new RenderingContext(debugEmitterToUse, classes,
controller.getClassLoader(), controller.getServices(), controller.getProperties(), naming);
Renderer renderer = new Renderer(sourceWriter, asyncMethods, asyncFamilyMethods,
controller.getDiagnostics(), renderingContext);
renderer.setProperties(controller.getProperties()); renderer.setProperties(controller.getProperties());
renderer.setMinifying(minifying); renderer.setMinifying(minifying);
if (debugEmitter != null) { if (debugEmitter != null) {
@ -245,7 +253,7 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
} }
renderer.getDebugEmitter().setLocationProvider(sourceWriter); renderer.getDebugEmitter().setLocationProvider(sourceWriter);
for (Map.Entry<MethodReference, Injector> entry : methodInjectors.entrySet()) { for (Map.Entry<MethodReference, Injector> entry : methodInjectors.entrySet()) {
renderer.addInjector(entry.getKey(), entry.getValue()); renderingContext.addInjector(entry.getKey(), entry.getValue());
} }
try { try {
for (RendererListener listener : rendererListeners) { for (RendererListener listener : rendererListeners) {

View File

@ -56,10 +56,16 @@ public class DefaultAliasProvider implements AliasProvider {
@Override @Override
public String getMethodAlias(MethodDescriptor method) { public String getMethodAlias(MethodDescriptor method) {
String alias = method.getName(); String alias = method.getName();
if (alias.equals("<init>")) { switch (alias) {
alias = "$init"; case "<init>":
} else if (alias.equals("<clinit>")) { alias = "$_init_";
alias = "$clinit"; break;
case "<clinit>":
alias = "$_clinit_";
break;
default:
alias = "$" + alias;
break;
} }
return makeUnique(knownVirtualAliases, alias); return makeUnique(knownVirtualAliases, alias);
} }
@ -67,10 +73,13 @@ public class DefaultAliasProvider implements AliasProvider {
@Override @Override
public String getStaticMethodAlias(MethodReference method) { public String getStaticMethodAlias(MethodReference method) {
String alias = method.getDescriptor().getName(); String alias = method.getDescriptor().getName();
if (alias.equals("<init>")) { switch (alias) {
alias = "$init"; case "<init>":
} else if (alias.equals("<clinit>")) { alias = "_init_";
alias = "$clinit"; break;
case "<clinit>":
alias = "_clinit_";
break;
} }
return makeUnique(knownAliases, getClassAlias(method.getClassName()) + "_" + alias); return makeUnique(knownAliases, getClassAlias(method.getClassName()) + "_" + alias);
@ -78,7 +87,7 @@ public class DefaultAliasProvider implements AliasProvider {
@Override @Override
public String getFieldAlias(FieldReference field) { public String getFieldAlias(FieldReference field) {
return makeUnique(knownVirtualAliases, field.getFieldName()); return makeUnique(knownVirtualAliases, "$" + field.getFieldName());
} }
@Override @Override

View File

@ -15,22 +15,269 @@
*/ */
package org.teavm.backend.javascript.rendering; package org.teavm.backend.javascript.rendering;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Deque;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties; import java.util.Properties;
import org.teavm.backend.javascript.codegen.NamingStrategy; import org.teavm.backend.javascript.codegen.NamingStrategy;
import org.teavm.backend.javascript.codegen.SourceWriter; import org.teavm.backend.javascript.spi.InjectedBy;
import org.teavm.backend.javascript.spi.Injector;
import org.teavm.common.ServiceRepository; import org.teavm.common.ServiceRepository;
import org.teavm.debugging.information.DebugInformationEmitter;
import org.teavm.model.AnnotationReader;
import org.teavm.model.ClassReader;
import org.teavm.model.ListableClassReaderSource; import org.teavm.model.ListableClassReaderSource;
import org.teavm.model.MethodReader;
import org.teavm.model.MethodReference;
import org.teavm.model.TextLocation;
import org.teavm.model.ValueType;
public interface RenderingContext extends ServiceRepository { public class RenderingContext {
NamingStrategy getNaming(); private final DebugInformationEmitter debugEmitter;
private ListableClassReaderSource classSource;
private ClassLoader classLoader;
private ServiceRepository services;
private Properties properties;
private NamingStrategy naming;
private final Deque<LocationStackEntry> locationStack = new ArrayDeque<>();
private final Map<String, Integer> stringPoolMap = new HashMap<>();
private final List<String> stringPool = new ArrayList<>();
private final List<String> readonlyStringPool = Collections.unmodifiableList(stringPool);
private final Map<MethodReference, InjectorHolder> injectorMap = new HashMap<>();
private boolean minifying;
SourceWriter getWriter(); public RenderingContext(DebugInformationEmitter debugEmitter, ListableClassReaderSource classSource,
ClassLoader classLoader, ServiceRepository services, Properties properties,
boolean isMinifying(); NamingStrategy naming) {
this.debugEmitter = debugEmitter;
ListableClassReaderSource getClassSource(); this.classSource = classSource;
this.classLoader = classLoader;
ClassLoader getClassLoader(); this.services = services;
this.properties = properties;
Properties getProperties(); this.naming = naming;
}
public ListableClassReaderSource getClassSource() {
return classSource;
}
public ClassLoader getClassLoader() {
return classLoader;
}
public ServiceRepository getServices() {
return services;
}
public Properties getProperties() {
return properties;
}
public NamingStrategy getNaming() {
return naming;
}
public void setMinifying(boolean minifying) {
this.minifying = minifying;
}
public DebugInformationEmitter getDebugEmitter() {
return debugEmitter;
}
public void pushLocation(TextLocation location) {
LocationStackEntry prevEntry = locationStack.peek();
if (location != null) {
if (prevEntry == null || !location.equals(prevEntry.location)) {
debugEmitter.emitLocation(location.getFileName(), location.getLine());
}
} else {
if (prevEntry != null) {
debugEmitter.emitLocation(null, -1);
}
}
locationStack.push(new LocationStackEntry(location));
}
public void popLocation() {
LocationStackEntry prevEntry = locationStack.pop();
LocationStackEntry entry = locationStack.peek();
if (entry != null) {
if (!entry.location.equals(prevEntry.location)) {
debugEmitter.emitLocation(entry.location.getFileName(), entry.location.getLine());
}
} else {
debugEmitter.emitLocation(null, -1);
}
}
public boolean isMinifying() {
return minifying;
}
public int lookupString(String string) {
return stringPoolMap.computeIfAbsent(string, key -> {
stringPool.add(key);
return stringPool.size() - 1;
});
}
public List<String> getStringPool() {
return readonlyStringPool;
}
public String constantToString(Object cst) {
if (cst == null) {
return "null";
}
if (cst instanceof ValueType) {
ValueType type = (ValueType) cst;
return naming.getNameForFunction("$rt_cls") + "(" + typeToClsString(type) + ")";
} else if (cst instanceof String) {
String string = (String) cst;
int index = lookupString(string);
return "$rt_s(" + index + ")";
} else if (cst instanceof Long) {
long value = (Long) cst;
if (value == 0) {
return "Long_ZERO";
} else if ((int) value == value) {
return "Long_fromInt(" + value + ")";
} else {
return "new Long(" + (value & 0xFFFFFFFFL) + ", " + (value >>> 32) + ")";
}
} else if (cst instanceof Character) {
return Integer.toString((Character) cst);
} else {
return cst.toString();
}
}
public String typeToClsString(ValueType type) {
int arrayCount = 0;
while (type instanceof ValueType.Array) {
arrayCount++;
type = ((ValueType.Array) type).getItemType();
}
String value;
if (type instanceof ValueType.Object) {
ValueType.Object objType = (ValueType.Object) type;
value = naming.getNameFor(objType.getClassName());
} else if (type instanceof ValueType.Void) {
value = "$rt_voidcls()";
} else if (type instanceof ValueType.Primitive) {
ValueType.Primitive primitiveType = (ValueType.Primitive) type;
switch (primitiveType.getKind()) {
case BOOLEAN:
value = "$rt_booleancls()";
break;
case CHARACTER:
value = "$rt_charcls()";
break;
case BYTE:
value = "$rt_bytecls()";
break;
case SHORT:
value = "$rt_shortcls()";
break;
case INTEGER:
value = "$rt_intcls()";
break;
case LONG:
value = "$rt_longcls()";
break;
case FLOAT:
value = "$rt_floatcls()";
break;
case DOUBLE:
value = "$rt_doublecls()";
break;
default:
throw new IllegalArgumentException("The type is not renderable");
}
} else {
throw new IllegalArgumentException("The type is not renderable");
}
for (int i = 0; i < arrayCount; ++i) {
value = "$rt_arraycls(" + value + ")";
}
return value;
}
public String pointerName() {
return minifying ? "$p" : "$ptr";
}
public String mainLoopName() {
return minifying ? "$m" : "$main";
}
public String tempVarName() {
return minifying ? "$z" : "$tmp";
}
public String threadName() {
return minifying ? "$T" : "$thread";
}
private static class LocationStackEntry {
final TextLocation location;
LocationStackEntry(TextLocation location) {
this.location = location;
}
}
public void addInjector(MethodReference method, Injector injector) {
injectorMap.put(method, new InjectorHolder(injector));
}
public Injector getInjector(MethodReference ref) {
InjectorHolder holder = injectorMap.get(ref);
if (holder == null) {
holder = new InjectorHolder(null);
ClassReader cls = classSource.get(ref.getClassName());
if (cls != null) {
MethodReader method = cls.getMethod(ref.getDescriptor());
if (method != null) {
AnnotationReader injectedByAnnot = method.getAnnotations().get(InjectedBy.class.getName());
if (injectedByAnnot != null) {
ValueType type = injectedByAnnot.getValue("value").getJavaClass();
holder = new InjectorHolder(instantiateInjector(((ValueType.Object) type).getClassName()));
}
}
}
injectorMap.put(ref, holder);
}
return holder.injector;
}
private Injector instantiateInjector(String type) {
try {
Class<? extends Injector> cls = Class.forName(type, true, classLoader).asSubclass(Injector.class);
Constructor<? extends Injector> cons = cls.getConstructor();
return cons.newInstance();
} catch (ClassNotFoundException e) {
throw new RuntimeException("Illegal injector: " + type, e);
} catch (NoSuchMethodException e) {
throw new RuntimeException("Default constructor was not found in the " + type + " injector", e);
} catch (IllegalAccessException | InstantiationException | InvocationTargetException e) {
throw new RuntimeException("Error instantiating injector " + type, e);
}
}
private static class InjectorHolder {
public final Injector injector;
private InjectorHolder(Injector injector) {
this.injector = injector;
}
}
} }

View File

@ -0,0 +1,36 @@
/*
* Copyright 2016 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.backend.javascript.rendering;
import java.util.Properties;
import org.teavm.backend.javascript.codegen.NamingStrategy;
import org.teavm.backend.javascript.codegen.SourceWriter;
import org.teavm.common.ServiceRepository;
import org.teavm.model.ListableClassReaderSource;
public interface RenderingManager extends ServiceRepository {
NamingStrategy getNaming();
SourceWriter getWriter();
boolean isMinifying();
ListableClassReaderSource getClassSource();
ClassLoader getClassLoader();
Properties getProperties();
}

View File

@ -0,0 +1,84 @@
/*
* Copyright 2016 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.backend.javascript.rendering;
public final class RenderingUtil {
public static final String variableNames = "abcdefghijkmnopqrstuvwxyz";
public static final String variablePartNames = "abcdefghijkmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
private RenderingUtil() {
}
public static String escapeName(String name) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < name.length(); ++i) {
char c = name.charAt(i);
sb.append(Character.isJavaIdentifierPart(c) ? c : '_');
}
return sb.toString();
}
public static String escapeString(String str) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < str.length(); ++i) {
char c = str.charAt(i);
switch (c) {
case '\r':
sb.append("\\r");
break;
case '\n':
sb.append("\\n");
break;
case '\t':
sb.append("\\t");
break;
case '\'':
sb.append("\\'");
break;
case '\"':
sb.append("\\\"");
break;
case '\\':
sb.append("\\\\");
break;
default:
if (c < ' ') {
sb.append("\\u00").append(Character.forDigit(c / 16, 16))
.append(Character.forDigit(c % 16, 16));
} else if (Character.isLowSurrogate(c) || Character.isHighSurrogate(c)) {
sb.append("\\u")
.append(Character.forDigit(c / 0x1000, 0x10))
.append(Character.forDigit((c / 0x100) % 0x10, 0x10))
.append(Character.forDigit((c / 0x10) % 0x10, 0x10))
.append(Character.forDigit(c % 0x10, 0x10));
} else {
sb.append(c);
}
break;
}
}
return sb.toString();
}
public static String indexToId(int index) {
StringBuilder sb = new StringBuilder();
do {
sb.append(variablePartNames.charAt(index % variablePartNames.length()));
index /= variablePartNames.length();
} while (index > 0);
return sb.toString();
}
}

File diff suppressed because it is too large Load Diff

View File

@ -20,11 +20,8 @@ import org.teavm.common.ServiceRepository;
import org.teavm.diagnostics.Diagnostics; import org.teavm.diagnostics.Diagnostics;
import org.teavm.model.ListableClassReaderSource; import org.teavm.model.ListableClassReaderSource;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
import org.teavm.model.ValueType;
/**
*
* @author Alexey Andreev
*/
public interface GeneratorContext extends ServiceRepository { public interface GeneratorContext extends ServiceRepository {
String getParameterName(int index); String getParameterName(int index);
@ -41,4 +38,6 @@ public interface GeneratorContext extends ServiceRepository {
boolean isAsyncFamily(MethodReference method); boolean isAsyncFamily(MethodReference method);
Diagnostics getDiagnostics(); Diagnostics getDiagnostics();
String typeToClassString(ValueType type);
} }

View File

@ -16,16 +16,12 @@
package org.teavm.vm.spi; package org.teavm.vm.spi;
import java.io.IOException; import java.io.IOException;
import org.teavm.backend.javascript.rendering.RenderingContext; import org.teavm.backend.javascript.rendering.RenderingManager;
import org.teavm.vm.BuildTarget; import org.teavm.vm.BuildTarget;
/**
*
* @author Alexey Andreev
*/
public abstract class AbstractRendererListener implements RendererListener { public abstract class AbstractRendererListener implements RendererListener {
@Override @Override
public void begin(RenderingContext context, BuildTarget buildTarget) throws IOException { public void begin(RenderingManager manager, BuildTarget buildTarget) throws IOException {
} }
@Override @Override

View File

@ -16,7 +16,7 @@
package org.teavm.vm.spi; package org.teavm.vm.spi;
import java.io.IOException; import java.io.IOException;
import org.teavm.backend.javascript.rendering.RenderingContext; import org.teavm.backend.javascript.rendering.RenderingManager;
import org.teavm.vm.BuildTarget; import org.teavm.vm.BuildTarget;
/** /**
@ -24,7 +24,7 @@ import org.teavm.vm.BuildTarget;
* @author Alexey Andreev * @author Alexey Andreev
*/ */
public interface RendererListener { public interface RendererListener {
void begin(RenderingContext context, BuildTarget buildTarget) throws IOException; void begin(RenderingManager context, BuildTarget buildTarget) throws IOException;
void complete() throws IOException; void complete() throws IOException;
} }

View File

@ -20,10 +20,17 @@ import java.util.List;
import net.java.html.js.JavaScriptBody; import net.java.html.js.JavaScriptBody;
import org.teavm.backend.javascript.codegen.NamingStrategy; import org.teavm.backend.javascript.codegen.NamingStrategy;
import org.teavm.backend.javascript.codegen.SourceWriter; import org.teavm.backend.javascript.codegen.SourceWriter;
import org.teavm.backend.javascript.rendering.Renderer;
import org.teavm.backend.javascript.spi.Generator; import org.teavm.backend.javascript.spi.Generator;
import org.teavm.backend.javascript.spi.GeneratorContext; import org.teavm.backend.javascript.spi.GeneratorContext;
import org.teavm.model.*; import org.teavm.model.AnnotationReader;
import org.teavm.model.AnnotationValue;
import org.teavm.model.ClassReader;
import org.teavm.model.ClassReaderSource;
import org.teavm.model.ElementModifier;
import org.teavm.model.MethodDescriptor;
import org.teavm.model.MethodReader;
import org.teavm.model.MethodReference;
import org.teavm.model.ValueType;
public class JavaScriptBodyGenerator implements Generator { public class JavaScriptBodyGenerator implements Generator {
@Override @Override
@ -35,7 +42,8 @@ public class JavaScriptBodyGenerator implements Generator {
List<AnnotationValue> args = annot.getValue("args").getList(); List<AnnotationValue> args = annot.getValue("args").getList();
AnnotationValue javacall = annot.getValue("javacall"); AnnotationValue javacall = annot.getValue("javacall");
if (javacall != null && javacall.getBoolean()) { if (javacall != null && javacall.getBoolean()) {
GeneratorJsCallback callbackGen = new GeneratorJsCallback(context.getClassSource(), writer.getNaming()); GeneratorJsCallback callbackGen = new GeneratorJsCallback(context, context.getClassSource(),
writer.getNaming());
body = callbackGen.parse(body); body = callbackGen.parse(body);
} }
writer.append("var result = (function("); writer.append("var result = (function(");
@ -55,7 +63,7 @@ public class JavaScriptBodyGenerator implements Generator {
} }
writer.append(");").softNewLine(); writer.append(");").softNewLine();
writer.append("return "); writer.append("return ");
unwrapValue(writer, method.getResultType(), "result"); unwrapValue(context, writer, method.getResultType(), "result");
writer.append(";").softNewLine(); writer.append(";").softNewLine();
} }
@ -64,16 +72,19 @@ public class JavaScriptBodyGenerator implements Generator {
writer.append("(").append(param).append(")"); writer.append("(").append(param).append(")");
} }
private void unwrapValue(SourceWriter writer, ValueType type, String param) throws IOException { private void unwrapValue(GeneratorContext context, SourceWriter writer, ValueType type, String param)
throws IOException {
writer.appendMethodBody(JavaScriptConvGenerator.fromJsMethod); writer.appendMethodBody(JavaScriptConvGenerator.fromJsMethod);
writer.append("(").append(param).append(",").ws().append(Renderer.typeToClsString(writer.getNaming(), type)) writer.append("(").append(param).append(",").ws().append(context.typeToClassString(type))
.append(")"); .append(")");
} }
private static class GeneratorJsCallback extends JsCallback { private static class GeneratorJsCallback extends JsCallback {
private GeneratorContext context;
private ClassReaderSource classSource; private ClassReaderSource classSource;
private NamingStrategy naming; private NamingStrategy naming;
public GeneratorJsCallback(ClassReaderSource classSource, NamingStrategy naming) { public GeneratorJsCallback(GeneratorContext context, ClassReaderSource classSource, NamingStrategy naming) {
this.context = context;
this.classSource = classSource; this.classSource = classSource;
this.naming = naming; this.naming = naming;
} }
@ -105,7 +116,7 @@ public class JavaScriptBodyGenerator implements Generator {
ValueType paramType = simplifyParamType(reader.parameterType(i)); ValueType paramType = simplifyParamType(reader.parameterType(i));
sb.append(naming.getFullNameFor(JavaScriptConvGenerator.fromJsMethod)).append("(p").append(i) sb.append(naming.getFullNameFor(JavaScriptConvGenerator.fromJsMethod)).append("(p").append(i)
.append(", ") .append(", ")
.append(Renderer.typeToClsString(naming, paramType)).append(")"); .append(context.typeToClassString(paramType)).append(")");
} }
sb.append(")); })("); sb.append(")); })(");
if (ident != null) { if (ident != null) {

View File

@ -20,7 +20,7 @@ import java.io.InputStream;
import java.io.StringWriter; import java.io.StringWriter;
import net.java.html.js.JavaScriptResource; import net.java.html.js.JavaScriptResource;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.teavm.backend.javascript.rendering.RenderingContext; import org.teavm.backend.javascript.rendering.RenderingManager;
import org.teavm.model.AnnotationReader; import org.teavm.model.AnnotationReader;
import org.teavm.model.ClassReader; import org.teavm.model.ClassReader;
import org.teavm.vm.BuildTarget; import org.teavm.vm.BuildTarget;
@ -29,10 +29,10 @@ import org.teavm.vm.spi.AbstractRendererListener;
public class JavaScriptResourceInterceptor extends AbstractRendererListener { public class JavaScriptResourceInterceptor extends AbstractRendererListener {
@Override @Override
public void begin(RenderingContext context, BuildTarget buildTarget) throws IOException { public void begin(RenderingManager manager, BuildTarget buildTarget) throws IOException {
boolean hasOneResource = false; boolean hasOneResource = false;
for (String className : context.getClassSource().getClassNames()) { for (String className : manager.getClassSource().getClassNames()) {
ClassReader cls = context.getClassSource().get(className); ClassReader cls = manager.getClassSource().get(className);
AnnotationReader annot = cls.getAnnotations().get(JavaScriptResource.class.getName()); AnnotationReader annot = cls.getAnnotations().get(JavaScriptResource.class.getName());
if (annot == null) { if (annot == null) {
continue; continue;
@ -40,7 +40,7 @@ public class JavaScriptResourceInterceptor extends AbstractRendererListener {
String path = annot.getValue("value").getString(); String path = annot.getValue("value").getString();
String packageName = className.substring(0, className.lastIndexOf('.')); String packageName = className.substring(0, className.lastIndexOf('.'));
String resourceName = packageName.replace('.', '/') + "/" + path; String resourceName = packageName.replace('.', '/') + "/" + path;
try (InputStream input = context.getClassLoader().getResourceAsStream(resourceName)) { try (InputStream input = manager.getClassLoader().getResourceAsStream(resourceName)) {
if (input == null) { if (input == null) {
throw new RenderingException("Error processing JavaScriptResource annotation on class " throw new RenderingException("Error processing JavaScriptResource annotation on class "
+ className + ". Resource not found: " + resourceName); + className + ". Resource not found: " + resourceName);
@ -48,13 +48,13 @@ public class JavaScriptResourceInterceptor extends AbstractRendererListener {
StringWriter writer = new StringWriter(); StringWriter writer = new StringWriter();
IOUtils.copy(input, writer); IOUtils.copy(input, writer);
writer.close(); writer.close();
context.getWriter().append("// Resource " + path + " included by " + className).newLine(); manager.getWriter().append("// Resource " + path + " included by " + className).newLine();
context.getWriter().append(writer.toString()).newLine().newLine(); manager.getWriter().append(writer.toString()).newLine().newLine();
} }
hasOneResource = true; hasOneResource = true;
} }
if (hasOneResource) { if (hasOneResource) {
context.getWriter().append("// TeaVM generated classes").newLine(); manager.getWriter().append("// TeaVM generated classes").newLine();
} }
} }
} }

View File

@ -23,7 +23,7 @@ import java.util.HashSet;
import java.util.Set; import java.util.Set;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.teavm.backend.javascript.codegen.SourceWriter; import org.teavm.backend.javascript.codegen.SourceWriter;
import org.teavm.backend.javascript.rendering.RenderingContext; import org.teavm.backend.javascript.rendering.RenderingManager;
import org.teavm.vm.BuildTarget; import org.teavm.vm.BuildTarget;
import org.teavm.vm.spi.AbstractRendererListener; import org.teavm.vm.spi.AbstractRendererListener;
@ -34,16 +34,16 @@ import org.teavm.vm.spi.AbstractRendererListener;
public class ResourcesInterceptor extends AbstractRendererListener { public class ResourcesInterceptor extends AbstractRendererListener {
private final Set<String> processed = new HashSet<>(); private final Set<String> processed = new HashSet<>();
@Override @Override
public void begin(RenderingContext context, BuildTarget buildTarget) throws IOException { public void begin(RenderingManager manager, BuildTarget buildTarget) throws IOException {
boolean hasOneResource = false; boolean hasOneResource = false;
for (String className : context.getClassSource().getClassNames()) { for (String className : manager.getClassSource().getClassNames()) {
final int lastDot = className.lastIndexOf('.'); final int lastDot = className.lastIndexOf('.');
if (lastDot == -1) { if (lastDot == -1) {
continue; continue;
} }
String packageName = className.substring(0, lastDot); String packageName = className.substring(0, lastDot);
String resourceName = packageName.replace('.', '/') + "/" + "jvm.txt"; String resourceName = packageName.replace('.', '/') + "/" + "jvm.txt";
try (InputStream input = context.getClassLoader().getResourceAsStream(resourceName)) { try (InputStream input = manager.getClassLoader().getResourceAsStream(resourceName)) {
if (input == null || !processed.add(resourceName)) { if (input == null || !processed.add(resourceName)) {
continue; continue;
} }
@ -51,7 +51,7 @@ public class ResourcesInterceptor extends AbstractRendererListener {
IOUtils.copy(input, arr); IOUtils.copy(input, arr);
String base64 = Base64.getEncoder().encodeToString(arr.toByteArray()); String base64 = Base64.getEncoder().encodeToString(arr.toByteArray());
input.close(); input.close();
final SourceWriter w = context.getWriter(); final SourceWriter w = manager.getWriter();
w.append("// Resource " + resourceName + " included by " + className).newLine(); w.append("// Resource " + resourceName + " included by " + className).newLine();
w.append("if (!window.teaVMResources) window.teaVMResources = {};").newLine(); w.append("if (!window.teaVMResources) window.teaVMResources = {};").newLine();
w.append("window.teaVMResources['" + resourceName + "'] = '"); w.append("window.teaVMResources['" + resourceName + "'] = '");
@ -60,7 +60,7 @@ public class ResourcesInterceptor extends AbstractRendererListener {
hasOneResource = true; hasOneResource = true;
} }
if (hasOneResource) { if (hasOneResource) {
context.getWriter().append("// TeaVM generated classes").newLine(); manager.getWriter().append("// TeaVM generated classes").newLine();
} }
} }
} }

View File

@ -18,7 +18,7 @@ package org.teavm.jso.impl;
import java.io.IOException; import java.io.IOException;
import java.util.Map; import java.util.Map;
import org.teavm.backend.javascript.codegen.SourceWriter; import org.teavm.backend.javascript.codegen.SourceWriter;
import org.teavm.backend.javascript.rendering.RenderingContext; import org.teavm.backend.javascript.rendering.RenderingManager;
import org.teavm.jso.impl.JSDependencyListener.ExposedClass; import org.teavm.jso.impl.JSDependencyListener.ExposedClass;
import org.teavm.model.ClassReader; import org.teavm.model.ClassReader;
import org.teavm.model.ClassReaderSource; import org.teavm.model.ClassReaderSource;
@ -41,7 +41,7 @@ class JSAliasRenderer implements RendererListener {
} }
@Override @Override
public void begin(RenderingContext context, BuildTarget buildTarget) throws IOException { public void begin(RenderingManager context, BuildTarget buildTarget) throws IOException {
writer = context.getWriter(); writer = context.getWriter();
classSource = context.getClassSource(); classSource = context.getClassSource();
} }

View File

@ -15,13 +15,13 @@
*/ */
package org.teavm.jso.impl; package org.teavm.jso.impl;
import static org.teavm.backend.javascript.rendering.RenderingUtil.escapeString;
import java.io.IOException; import java.io.IOException;
import org.teavm.ast.ConstantExpr; import org.teavm.ast.ConstantExpr;
import org.teavm.ast.Expr; import org.teavm.ast.Expr;
import org.teavm.ast.InvocationExpr; import org.teavm.ast.InvocationExpr;
import org.teavm.backend.javascript.codegen.SourceWriter; import org.teavm.backend.javascript.codegen.SourceWriter;
import org.teavm.backend.javascript.rendering.Precedence; import org.teavm.backend.javascript.rendering.Precedence;
import org.teavm.backend.javascript.rendering.Renderer;
import org.teavm.backend.javascript.spi.Generator; import org.teavm.backend.javascript.spi.Generator;
import org.teavm.backend.javascript.spi.GeneratorContext; import org.teavm.backend.javascript.spi.GeneratorContext;
import org.teavm.backend.javascript.spi.Injector; import org.teavm.backend.javascript.spi.Injector;
@ -122,7 +122,7 @@ public class JSNativeGenerator implements Injector, DependencyPlugin, Generator
if (context.getArgument(0) instanceof ConstantExpr) { if (context.getArgument(0) instanceof ConstantExpr) {
ConstantExpr constant = (ConstantExpr) context.getArgument(0); ConstantExpr constant = (ConstantExpr) context.getArgument(0);
if (constant.getValue() instanceof String) { if (constant.getValue() instanceof String) {
writer.append('"').append(Renderer.escapeString((String) constant.getValue())).append('"'); writer.append('"').append(escapeString((String) constant.getValue())).append('"');
break; break;
} }
} }

View File

@ -20,10 +20,16 @@ import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.util.Map; import java.util.Map;
import org.teavm.backend.javascript.codegen.SourceWriter; import org.teavm.backend.javascript.codegen.SourceWriter;
import org.teavm.backend.javascript.rendering.Renderer; import org.teavm.backend.javascript.rendering.RenderingUtil;
import org.teavm.backend.javascript.spi.Generator; import org.teavm.backend.javascript.spi.Generator;
import org.teavm.backend.javascript.spi.GeneratorContext; import org.teavm.backend.javascript.spi.GeneratorContext;
import org.teavm.model.*; import org.teavm.model.AnnotationReader;
import org.teavm.model.CallLocation;
import org.teavm.model.ClassReader;
import org.teavm.model.ElementModifier;
import org.teavm.model.MethodReader;
import org.teavm.model.MethodReference;
import org.teavm.model.ValueType;
import org.teavm.platform.metadata.ClassScopedMetadataGenerator; import org.teavm.platform.metadata.ClassScopedMetadataGenerator;
import org.teavm.platform.metadata.ClassScopedMetadataProvider; import org.teavm.platform.metadata.ClassScopedMetadataProvider;
import org.teavm.platform.metadata.Resource; import org.teavm.platform.metadata.Resource;
@ -80,7 +86,7 @@ public class ClassScopedMetadataProviderNativeGenerator implements Generator {
context.getClassLoader(), context.getProperties(), context); context.getClassLoader(), context.getProperties(), context);
Map<String, Resource> resourceMap = generator.generateMetadata(metadataContext, methodRef); Map<String, Resource> resourceMap = generator.generateMetadata(metadataContext, methodRef);
writer.append("var p").ws().append("=").ws().append("\"" + Renderer.escapeString("$$res_" writer.append("var p").ws().append("=").ws().append("\"" + RenderingUtil.escapeString("$$res_"
+ writer.getNaming().getFullNameFor(methodRef)) + "\"").append(";").softNewLine(); + writer.getNaming().getFullNameFor(methodRef)) + "\"").append(";").softNewLine();
for (Map.Entry<String, Resource> entry : resourceMap.entrySet()) { for (Map.Entry<String, Resource> entry : resourceMap.entrySet()) {
writer.appendClass(entry.getKey()).append("[p]").ws().append("=").ws(); writer.appendClass(entry.getKey()).append("[p]").ws().append("=").ws();

View File

@ -34,7 +34,7 @@ import java.util.Properties;
import java.util.Set; import java.util.Set;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.teavm.backend.javascript.JavaScriptTarget; import org.teavm.backend.javascript.JavaScriptTarget;
import org.teavm.backend.javascript.rendering.RenderingContext; import org.teavm.backend.javascript.rendering.RenderingManager;
import org.teavm.backend.wasm.WasmTarget; import org.teavm.backend.wasm.WasmTarget;
import org.teavm.cache.DiskCachedClassHolderSource; import org.teavm.cache.DiskCachedClassHolderSource;
import org.teavm.cache.DiskProgramCache; import org.teavm.cache.DiskProgramCache;
@ -525,11 +525,11 @@ public class TeaVMTool implements BaseTeaVMTool {
private AbstractRendererListener runtimeInjector = new AbstractRendererListener() { private AbstractRendererListener runtimeInjector = new AbstractRendererListener() {
@Override @Override
public void begin(RenderingContext context, BuildTarget buildTarget) throws IOException { public void begin(RenderingManager manager, BuildTarget buildTarget) throws IOException {
StringWriter writer = new StringWriter(); StringWriter writer = new StringWriter();
resourceToWriter("org/teavm/backend/javascript/runtime.js", writer); resourceToWriter("org/teavm/backend/javascript/runtime.js", writer);
writer.close(); writer.close();
context.getWriter().append(writer.toString()).newLine(); manager.getWriter().append(writer.toString()).newLine();
} }
}; };