mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-31 12:24:10 -08:00
Generate entire code inside wrapper IIF
This commit is contained in:
parent
fe151d525a
commit
148c07336c
|
@ -446,7 +446,7 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
|
||||||
private void generateCallToMainMethod(GenerationContext context, CodeWriter writer) {
|
private void generateCallToMainMethod(GenerationContext context, CodeWriter writer) {
|
||||||
TeaVMEntryPoint entryPoint = controller.getEntryPoints().get("main");
|
TeaVMEntryPoint entryPoint = controller.getEntryPoints().get("main");
|
||||||
if (entryPoint != null) {
|
if (entryPoint != null) {
|
||||||
String mainMethod = context.getNames().forMethod(entryPoint.getReference());
|
String mainMethod = context.getNames().forMethod(entryPoint.getMethod());
|
||||||
writer.println(mainMethod + "(NULL);");
|
writer.println(mainMethod + "(NULL);");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -235,6 +235,10 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
|
||||||
MethodDependency exceptionCons = dependencyAnalyzer.linkMethod(new MethodReference(
|
MethodDependency exceptionCons = dependencyAnalyzer.linkMethod(new MethodReference(
|
||||||
NoClassDefFoundError.class, "<init>", String.class, void.class), null);
|
NoClassDefFoundError.class, "<init>", String.class, void.class), null);
|
||||||
|
|
||||||
|
dep = dependencyAnalyzer.linkMethod(new MethodReference(Object.class, "toString", String.class), null);
|
||||||
|
dep.getVariable(0).propagate(dependencyAnalyzer.getType("java.lang.Object"));
|
||||||
|
dep.use();
|
||||||
|
|
||||||
exceptionCons.getVariable(0).propagate(dependencyAnalyzer.getType(NoClassDefFoundError.class.getName()));
|
exceptionCons.getVariable(0).propagate(dependencyAnalyzer.getType(NoClassDefFoundError.class.getName()));
|
||||||
exceptionCons.getVariable(1).propagate(dependencyAnalyzer.getType("java.lang.String"));
|
exceptionCons.getVariable(1).propagate(dependencyAnalyzer.getType("java.lang.String"));
|
||||||
exceptionCons = dependencyAnalyzer.linkMethod(new MethodReference(NoSuchFieldError.class, "<init>",
|
exceptionCons = dependencyAnalyzer.linkMethod(new MethodReference(NoSuchFieldError.class, "<init>",
|
||||||
|
@ -315,26 +319,34 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
|
||||||
renderingContext.addInjector(entry.getKey(), entry.getValue());
|
renderingContext.addInjector(entry.getKey(), entry.getValue());
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
printWrapperStart(sourceWriter);
|
||||||
|
|
||||||
for (RendererListener listener : rendererListeners) {
|
for (RendererListener listener : rendererListeners) {
|
||||||
listener.begin(renderer, target);
|
listener.begin(renderer, target);
|
||||||
}
|
}
|
||||||
int start = sourceWriter.getOffset();
|
int start = sourceWriter.getOffset();
|
||||||
sourceWriter.append("\"use strict\";").newLine();
|
|
||||||
renderer.prepare(clsNodes);
|
renderer.prepare(clsNodes);
|
||||||
runtimeRenderer.renderRuntime();
|
runtimeRenderer.renderRuntime();
|
||||||
renderer.render(clsNodes);
|
renderer.render(clsNodes);
|
||||||
renderer.renderStringPool();
|
renderer.renderStringPool();
|
||||||
renderer.renderStringConstants();
|
renderer.renderStringConstants();
|
||||||
|
renderer.renderCompatibilityStubs();
|
||||||
|
|
||||||
for (Map.Entry<? extends String, ? extends TeaVMEntryPoint> entry
|
for (Map.Entry<? extends String, ? extends TeaVMEntryPoint> entry
|
||||||
: controller.getEntryPoints().entrySet()) {
|
: controller.getEntryPoints().entrySet()) {
|
||||||
sourceWriter.append("var ").append(entry.getKey()).ws().append("=").ws();
|
sourceWriter.append("").append(entry.getKey()).ws().append("=").ws();
|
||||||
MethodReference ref = entry.getValue().getReference();
|
MethodReference ref = entry.getValue().getMethod();
|
||||||
sourceWriter.append(naming.getFullNameFor(ref));
|
sourceWriter.append("$rt_mainStarter(").append(naming.getFullNameFor(ref));
|
||||||
sourceWriter.append(";").newLine();
|
sourceWriter.append(");").newLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (RendererListener listener : rendererListeners) {
|
for (RendererListener listener : rendererListeners) {
|
||||||
listener.complete();
|
listener.complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
printWrapperEnd(sourceWriter);
|
||||||
|
|
||||||
int totalSize = sourceWriter.getOffset() - start;
|
int totalSize = sourceWriter.getOffset() - start;
|
||||||
printStats(renderer, totalSize);
|
printStats(renderer, totalSize);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
@ -342,6 +354,18 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void printWrapperStart(SourceWriter writer) throws IOException {
|
||||||
|
writer.append("\"use strict\";").newLine();
|
||||||
|
for (String key : controller.getEntryPoints().keySet()) {
|
||||||
|
writer.append("var ").append(key).append(";").softNewLine();
|
||||||
|
}
|
||||||
|
writer.append("(function()").ws().append("{").newLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void printWrapperEnd(SourceWriter writer) throws IOException {
|
||||||
|
writer.append("})();").newLine();
|
||||||
|
}
|
||||||
|
|
||||||
private void printStats(Renderer renderer, int totalSize) {
|
private void printStats(Renderer renderer, int totalSize) {
|
||||||
if (!Boolean.parseBoolean(System.getProperty("teavm.js.stats", "false"))) {
|
if (!Boolean.parseBoolean(System.getProperty("teavm.js.stats", "false"))) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -189,6 +189,40 @@ public class Renderer implements RenderingManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void renderCompatibilityStubs() throws RenderingException {
|
||||||
|
try {
|
||||||
|
renderJavaStringToString();
|
||||||
|
renderJavaObjectToString();
|
||||||
|
renderTeaVMClass();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RenderingException("IO error", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderJavaStringToString() throws IOException {
|
||||||
|
writer.appendClass("java.lang.String").append(".prototype.toString").ws().append("=").ws()
|
||||||
|
.append("function()").ws().append("{").indent().softNewLine();
|
||||||
|
writer.append("return $rt_ustr(this);").softNewLine();
|
||||||
|
writer.outdent().append("};").newLine();
|
||||||
|
writer.appendClass("java.lang.String").append(".prototype.valueOf").ws().append("=").ws()
|
||||||
|
.appendClass("java.lang.String").append(".prototype.toString;").softNewLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderJavaObjectToString() throws IOException {
|
||||||
|
writer.appendClass("java.lang.Object").append(".prototype.toString").ws().append("=").ws()
|
||||||
|
.append("function()").ws().append("{").indent().softNewLine();
|
||||||
|
writer.append("return $rt_ustr(").appendMethodBody(Object.class, "toString", String.class).append("(this));")
|
||||||
|
.softNewLine();
|
||||||
|
writer.outdent().append("};").newLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderTeaVMClass() throws IOException {
|
||||||
|
writer.appendClass("java.lang.Object").append(".prototype.__teavm_class__").ws().append("=").ws()
|
||||||
|
.append("function()").ws().append("{").indent().softNewLine();
|
||||||
|
writer.append("return $dbg_class(this);").softNewLine();
|
||||||
|
writer.outdent().append("};").newLine();
|
||||||
|
}
|
||||||
|
|
||||||
private void appendClassSize(String className, int sz) {
|
private void appendClassSize(String className, int sz) {
|
||||||
sizeByClass.put(className, sizeByClass.getOrDefault(className, 0) + sz);
|
sizeByClass.put(className, sizeByClass.getOrDefault(className, 0) + sz);
|
||||||
}
|
}
|
||||||
|
|
|
@ -397,7 +397,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
||||||
module.setStartFunction(initFunction);
|
module.setStartFunction(initFunction);
|
||||||
|
|
||||||
for (TeaVMEntryPoint entryPoint : controller.getEntryPoints().values()) {
|
for (TeaVMEntryPoint entryPoint : controller.getEntryPoints().values()) {
|
||||||
String mangledName = names.forMethod(entryPoint.getReference());
|
String mangledName = names.forMethod(entryPoint.getMethod());
|
||||||
WasmFunction function = module.getFunctions().get(mangledName);
|
WasmFunction function = module.getFunctions().get(mangledName);
|
||||||
if (function != null) {
|
if (function != null) {
|
||||||
function.setExportName(entryPoint.getPublicName());
|
function.setExportName(entryPoint.getPublicName());
|
||||||
|
|
|
@ -645,7 +645,6 @@ public class DebugInformation {
|
||||||
int[] methods;
|
int[] methods;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class MethodTree {
|
class MethodTree {
|
||||||
int[] data;
|
int[] data;
|
||||||
int[] offsets;
|
int[] offsets;
|
||||||
|
|
|
@ -23,6 +23,7 @@ import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
@ -37,6 +38,7 @@ import org.teavm.dependency.DependencyInfo;
|
||||||
import org.teavm.dependency.DependencyListener;
|
import org.teavm.dependency.DependencyListener;
|
||||||
import org.teavm.dependency.DependencyPlugin;
|
import org.teavm.dependency.DependencyPlugin;
|
||||||
import org.teavm.dependency.Linker;
|
import org.teavm.dependency.Linker;
|
||||||
|
import org.teavm.dependency.MethodDependency;
|
||||||
import org.teavm.diagnostics.AccumulationDiagnostics;
|
import org.teavm.diagnostics.AccumulationDiagnostics;
|
||||||
import org.teavm.diagnostics.Diagnostics;
|
import org.teavm.diagnostics.Diagnostics;
|
||||||
import org.teavm.diagnostics.ProblemProvider;
|
import org.teavm.diagnostics.ProblemProvider;
|
||||||
|
@ -47,12 +49,14 @@ import org.teavm.model.ClassReader;
|
||||||
import org.teavm.model.ClassReaderSource;
|
import org.teavm.model.ClassReaderSource;
|
||||||
import org.teavm.model.ListableClassHolderSource;
|
import org.teavm.model.ListableClassHolderSource;
|
||||||
import org.teavm.model.ListableClassReaderSource;
|
import org.teavm.model.ListableClassReaderSource;
|
||||||
|
import org.teavm.model.MethodDescriptor;
|
||||||
import org.teavm.model.MethodHolder;
|
import org.teavm.model.MethodHolder;
|
||||||
import org.teavm.model.MethodReader;
|
import org.teavm.model.MethodReader;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
import org.teavm.model.MutableClassHolderSource;
|
import org.teavm.model.MutableClassHolderSource;
|
||||||
import org.teavm.model.Program;
|
import org.teavm.model.Program;
|
||||||
import org.teavm.model.ProgramCache;
|
import org.teavm.model.ProgramCache;
|
||||||
|
import org.teavm.model.ValueType;
|
||||||
import org.teavm.model.optimization.ArrayUnwrapMotion;
|
import org.teavm.model.optimization.ArrayUnwrapMotion;
|
||||||
import org.teavm.model.optimization.ClassInitElimination;
|
import org.teavm.model.optimization.ClassInitElimination;
|
||||||
import org.teavm.model.optimization.ConstantConditionElimination;
|
import org.teavm.model.optimization.ConstantConditionElimination;
|
||||||
|
@ -106,11 +110,14 @@ import org.teavm.vm.spi.TeaVMPlugin;
|
||||||
* @author Alexey Andreev
|
* @author Alexey Andreev
|
||||||
*/
|
*/
|
||||||
public class TeaVM implements TeaVMHost, ServiceRepository {
|
public class TeaVM implements TeaVMHost, ServiceRepository {
|
||||||
|
private static final MethodDescriptor MAIN_METHOD_DESC = new MethodDescriptor("main",
|
||||||
|
ValueType.arrayOf(ValueType.object("java.lang.String")), ValueType.VOID);
|
||||||
|
|
||||||
private final ClassReaderSource classSource;
|
private final ClassReaderSource classSource;
|
||||||
private final DependencyAnalyzer dependencyAnalyzer;
|
private final DependencyAnalyzer dependencyAnalyzer;
|
||||||
private final AccumulationDiagnostics diagnostics = new AccumulationDiagnostics();
|
private final AccumulationDiagnostics diagnostics = new AccumulationDiagnostics();
|
||||||
private final ClassLoader classLoader;
|
private final ClassLoader classLoader;
|
||||||
private final Map<String, TeaVMEntryPoint> entryPoints = new HashMap<>();
|
private final Map<String, TeaVMEntryPoint> entryPoints = new LinkedHashMap<>();
|
||||||
private final Map<String, TeaVMEntryPoint> readonlyEntryPoints = Collections.unmodifiableMap(entryPoints);
|
private final Map<String, TeaVMEntryPoint> readonlyEntryPoints = Collections.unmodifiableMap(entryPoints);
|
||||||
private final Set<String> preservedClasses = new HashSet<>();
|
private final Set<String> preservedClasses = new HashSet<>();
|
||||||
private final Set<String> readonlyPreservedClasses = Collections.unmodifiableSet(preservedClasses);
|
private final Set<String> readonlyPreservedClasses = Collections.unmodifiableSet(preservedClasses);
|
||||||
|
@ -243,58 +250,38 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
||||||
return target.getPlatformTags();
|
return target.getPlatformTags();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public void entryPoint(String className, String name) {
|
||||||
* <p>Adds an entry point. TeaVM guarantees, that all methods that are required by the entry point
|
if (entryPoints.containsKey(name)) {
|
||||||
* will be available at run-time in browser. Also you need to specify for each parameter of entry point
|
throw new IllegalArgumentException("Entry point with public name `" + name + "' already defined "
|
||||||
* which actual types will be passed here by calling {@link TeaVMEntryPoint#withValue(int, String)}.
|
+ "for class " + className);
|
||||||
* It is highly recommended to read explanation on {@link TeaVMEntryPoint} class documentation.</p>
|
|
||||||
*
|
|
||||||
* <p>You should call this method after installing all plugins and interceptors, but before
|
|
||||||
* doing the actual build.</p>
|
|
||||||
*
|
|
||||||
* @param name the name under which this entry point will be available for JavaScript code.
|
|
||||||
* @param ref a full reference to the method which is an entry point.
|
|
||||||
* @return an entry point that you can additionally adjust.
|
|
||||||
*/
|
|
||||||
public TeaVMEntryPoint entryPoint(String name, MethodReference ref) {
|
|
||||||
if (name != null) {
|
|
||||||
if (entryPoints.containsKey(name)) {
|
|
||||||
throw new IllegalArgumentException("Entry point with public name `" + name + "' already defined "
|
|
||||||
+ "for method " + ref);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
TeaVMEntryPoint entryPoint = new TeaVMEntryPoint(name, ref, dependencyAnalyzer.linkMethod(ref, null));
|
|
||||||
|
ClassReader cls = dependencyAnalyzer.getClassSource().get(className);
|
||||||
|
if (cls == null) {
|
||||||
|
diagnostics.error(null, "There's no main class: '{{c0}}'", className);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cls.getMethod(MAIN_METHOD_DESC) == null) {
|
||||||
|
diagnostics.error(null, "Specified main class '{{c0}}' does not have method '" + MAIN_METHOD_DESC + "'");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MethodDependency mainMethod = dependencyAnalyzer.linkMethod(new MethodReference(className,
|
||||||
|
"main", ValueType.parse(String[].class), ValueType.VOID), null);
|
||||||
|
|
||||||
|
TeaVMEntryPoint entryPoint = new TeaVMEntryPoint(name, mainMethod);
|
||||||
dependencyAnalyzer.defer(() -> {
|
dependencyAnalyzer.defer(() -> {
|
||||||
dependencyAnalyzer.linkClass(ref.getClassName(), null).initClass(null);
|
dependencyAnalyzer.linkClass(className, null).initClass(null);
|
||||||
|
mainMethod.getVariable(1).propagate(dependencyAnalyzer.getType("[Ljava/lang/String;"));
|
||||||
|
mainMethod.getVariable(1).getArrayItem().propagate(dependencyAnalyzer.getType("java.lang.String"));
|
||||||
|
mainMethod.use();
|
||||||
});
|
});
|
||||||
if (name != null) {
|
entryPoints.put(name, entryPoint);
|
||||||
entryPoints.put(name, entryPoint);
|
|
||||||
}
|
|
||||||
return entryPoint;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public void entryPoint(String className) {
|
||||||
* <p>Adds an entry point. TeaVM guarantees, that all methods that are required by the entry point
|
entryPoint(className, "main");
|
||||||
* will be available at run-time in browser. Also you need to specify for each parameter of entry point
|
|
||||||
* which actual types will be passed here by calling {@link TeaVMEntryPoint#withValue(int, String)}.
|
|
||||||
* It is highly recommended to read explanation on {@link TeaVMEntryPoint} class documentation.</p>
|
|
||||||
*
|
|
||||||
* <p>You should call this method after installing all plugins and interceptors, but before
|
|
||||||
* doing the actual build.</p>
|
|
||||||
*
|
|
||||||
* @param ref a full reference to the method which is an entry point.
|
|
||||||
* @return an entry point that you can additionally adjust.
|
|
||||||
*/
|
|
||||||
public TeaVMEntryPoint entryPoint(MethodReference ref) {
|
|
||||||
return entryPoint(null, ref);
|
|
||||||
}
|
|
||||||
|
|
||||||
public TeaVMEntryPoint linkMethod(MethodReference ref) {
|
|
||||||
TeaVMEntryPoint entryPoint = new TeaVMEntryPoint("", ref, dependencyAnalyzer.linkMethod(ref, null));
|
|
||||||
dependencyAnalyzer.defer(() -> {
|
|
||||||
dependencyAnalyzer.linkClass(ref.getClassName(), null).initClass(null);
|
|
||||||
});
|
|
||||||
return entryPoint;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void preserveType(String className) {
|
public void preserveType(String className) {
|
||||||
|
|
|
@ -15,102 +15,23 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.vm;
|
package org.teavm.vm;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import org.teavm.dependency.MethodDependency;
|
import org.teavm.dependency.MethodDependency;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>An entry point to a generated VM that is used to enter the VM from a JavaScript code.
|
|
||||||
* The entry point is added by {@link TeaVM#entryPoint(String, MethodReference)}.
|
|
||||||
* Use {@link #withValue(int, String)} to specify actual types that are passed to the entry point.</p>
|
|
||||||
*
|
|
||||||
* <p>In the simple case of static method without arguments you won't deal with this class. But
|
|
||||||
* sometimes you have to. Consider the following example:</p>
|
|
||||||
*
|
|
||||||
* <pre>{@code
|
|
||||||
*static void entryPoint(Map<Object, Object> map) {
|
|
||||||
* for (Map.Entry<Object, Object> entry : map.entrySet()) {
|
|
||||||
* System.out.println(entry.getKey() + " => " + entry.getValue());
|
|
||||||
* }
|
|
||||||
*}}</pre>
|
|
||||||
*
|
|
||||||
* <p>Now you want to call this method from JavaScript, and you pass a {@link HashMap} to this method.
|
|
||||||
* Let's see how you achieve it:</p>
|
|
||||||
*
|
|
||||||
* <pre>{@code
|
|
||||||
*vm.preserveType("JavaHashMap", "java.util.HashMap");
|
|
||||||
*vm.entryPoint("initJavaHashMap", new MethodReference("java.util.HashMap",
|
|
||||||
* "<init>", ValueType.VOID));
|
|
||||||
*vm.entryPoint("putValueIntoJavaMap", new MethodReference(
|
|
||||||
* "java.util.Map", "put",
|
|
||||||
* ValueType.object("java.lang.Object"), ValueType.object("java.lang.Object"),
|
|
||||||
* ValueType.object("java.lang.Object")))
|
|
||||||
* .withValue(0, "java.util.HashMap")
|
|
||||||
* .withValue(1, "java.lang.String")
|
|
||||||
* .withValue(2, "java.lang.String");
|
|
||||||
*vm.entryPoint("entryPoint", new MethodReference(
|
|
||||||
* "fully.qualified.ClassName", "entryPoint",
|
|
||||||
* ValueType.object("java.util.Map"), ValueType.VOID))
|
|
||||||
* .withValue(1, "java.util.HashMap")
|
|
||||||
*}</pre>
|
|
||||||
*
|
|
||||||
* <p>And in JavaScript you would do the following:</p>
|
|
||||||
*
|
|
||||||
* <pre>{@code
|
|
||||||
*var map = new JavaHashMap();
|
|
||||||
*initJavaHashMap(map);
|
|
||||||
*putValueIntoJavaMap(map, $rt_str("foo"), $rt_str("bar"));
|
|
||||||
*entryPoint(map);
|
|
||||||
*}</pre>
|
|
||||||
*
|
|
||||||
* <p>If you didn't call <code>.withValue(1, "java.util.HashMap")</code>, TeaVM could not know,
|
|
||||||
* what implementation of <code>entrySet</code> method to include.</p>
|
|
||||||
*
|
|
||||||
* @author Alexey Andreev
|
|
||||||
*/
|
|
||||||
public class TeaVMEntryPoint {
|
public class TeaVMEntryPoint {
|
||||||
private String publicName;
|
String publicName;
|
||||||
MethodReference reference;
|
MethodDependency methodDep;
|
||||||
private MethodDependency method;
|
|
||||||
private boolean async;
|
|
||||||
|
|
||||||
TeaVMEntryPoint(String publicName, MethodReference reference, MethodDependency method) {
|
TeaVMEntryPoint(String publicName, MethodDependency methodDep) {
|
||||||
this.publicName = publicName;
|
this.publicName = publicName;
|
||||||
this.reference = reference;
|
this.methodDep = methodDep;
|
||||||
this.method = method;
|
|
||||||
method.use();
|
|
||||||
}
|
|
||||||
|
|
||||||
public MethodReference getReference() {
|
|
||||||
return reference;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getPublicName() {
|
public String getPublicName() {
|
||||||
return publicName;
|
return publicName;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isAsync() {
|
public MethodReference getMethod() {
|
||||||
return async;
|
return methodDep.getReference();
|
||||||
}
|
|
||||||
|
|
||||||
public TeaVMEntryPoint withValue(int argument, String type) {
|
|
||||||
if (argument > reference.parameterCount()) {
|
|
||||||
throw new IllegalArgumentException("Illegal argument #" + argument + " of " + reference.parameterCount());
|
|
||||||
}
|
|
||||||
method.getVariable(argument).propagate(method.getDependencyAgent().getType(type));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TeaVMEntryPoint withArrayValue(int argument, String type) {
|
|
||||||
if (argument > reference.parameterCount()) {
|
|
||||||
throw new IllegalArgumentException("Illegal argument #" + argument + " of " + reference.parameterCount());
|
|
||||||
}
|
|
||||||
method.getVariable(argument).getArrayItem().propagate(method.getDependencyAgent().getType(type));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TeaVMEntryPoint async() {
|
|
||||||
this.async = true;
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -241,11 +241,6 @@ function $rt_voidcls() {
|
||||||
}
|
}
|
||||||
return $rt_voidclsCache;
|
return $rt_voidclsCache;
|
||||||
}
|
}
|
||||||
function $rt_init(cls, constructor, args) {
|
|
||||||
var obj = new cls();
|
|
||||||
cls.prototype[constructor].apply(obj, args);
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
function $rt_throw(ex) {
|
function $rt_throw(ex) {
|
||||||
throw $rt_exception(ex);
|
throw $rt_exception(ex);
|
||||||
}
|
}
|
||||||
|
@ -406,7 +401,7 @@ function $rt_assertNotNaN(value) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
var $rt_stdoutBuffer = "";
|
var $rt_stdoutBuffer = "";
|
||||||
function $rt_putStdout(ch) {
|
var $rt_putStdout = typeof $rt_putStdoutCustom === "function" ? $rt_putStdoutCustom : function(ch) {
|
||||||
if (ch === 0xA) {
|
if (ch === 0xA) {
|
||||||
if (console) {
|
if (console) {
|
||||||
console.info($rt_stdoutBuffer);
|
console.info($rt_stdoutBuffer);
|
||||||
|
@ -415,9 +410,9 @@ function $rt_putStdout(ch) {
|
||||||
} else {
|
} else {
|
||||||
$rt_stdoutBuffer += String.fromCharCode(ch);
|
$rt_stdoutBuffer += String.fromCharCode(ch);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
var $rt_stderrBuffer = "";
|
var $rt_stderrBuffer = "";
|
||||||
function $rt_putStderr(ch) {
|
var $rt_putStderr = typeof $rt_putStderrCustom === "function" ? $rt_putStderrCustom : function(ch) {
|
||||||
if (ch === 0xA) {
|
if (ch === 0xA) {
|
||||||
if (console) {
|
if (console) {
|
||||||
console.info($rt_stderrBuffer);
|
console.info($rt_stderrBuffer);
|
||||||
|
@ -426,7 +421,7 @@ function $rt_putStderr(ch) {
|
||||||
} else {
|
} else {
|
||||||
$rt_stderrBuffer += String.fromCharCode(ch);
|
$rt_stderrBuffer += String.fromCharCode(ch);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
function $rt_metadata(data) {
|
function $rt_metadata(data) {
|
||||||
var i = 0;
|
var i = 0;
|
||||||
var packageCount = data[i++];
|
var packageCount = data[i++];
|
||||||
|
@ -500,7 +495,7 @@ function $rt_threadStarter(f) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function $rt_mainStarter(f) {
|
function $rt_mainStarter(f) {
|
||||||
return function(args) {
|
return function(args, callback) {
|
||||||
if (!args) {
|
if (!args) {
|
||||||
args = [];
|
args = [];
|
||||||
}
|
}
|
||||||
|
@ -508,8 +503,8 @@ function $rt_mainStarter(f) {
|
||||||
for (var i = 0; i < args.length; ++i) {
|
for (var i = 0; i < args.length; ++i) {
|
||||||
javaArgs.data[i] = $rt_str(args[i]);
|
javaArgs.data[i] = $rt_str(args[i]);
|
||||||
}
|
}
|
||||||
$rt_threadStarter(f)(javaArgs);
|
$rt_startThread(function() { f.call(null, javaArgs); }, callback);
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
var $rt_stringPool_instance;
|
var $rt_stringPool_instance;
|
||||||
function $rt_stringPool(strings) {
|
function $rt_stringPool(strings) {
|
||||||
|
@ -617,14 +612,7 @@ function $rt_nativeThread() {
|
||||||
function $rt_invalidPointer() {
|
function $rt_invalidPointer() {
|
||||||
throw new Error("Invalid recorded state");
|
throw new Error("Invalid recorded state");
|
||||||
}
|
}
|
||||||
|
|
||||||
function $dbg_repr(obj) {
|
|
||||||
return obj.toString ? obj.toString() : "";
|
|
||||||
}
|
|
||||||
function $dbg_class(obj) {
|
function $dbg_class(obj) {
|
||||||
if (obj instanceof Long) {
|
|
||||||
return "long";
|
|
||||||
}
|
|
||||||
var cls = obj.constructor;
|
var cls = obj.constructor;
|
||||||
var arrayDegree = 0;
|
var arrayDegree = 0;
|
||||||
while (cls.$meta && cls.$meta.item) {
|
while (cls.$meta && cls.$meta.item) {
|
||||||
|
@ -649,7 +637,7 @@ function $dbg_class(obj) {
|
||||||
} else if (cls === $rt_doublecls()) {
|
} else if (cls === $rt_doublecls()) {
|
||||||
clsName = "double";
|
clsName = "double";
|
||||||
} else {
|
} else {
|
||||||
clsName = cls.$meta ? cls.$meta.name : "@" + cls.name;
|
clsName = cls.$meta ? (cls.$meta.name || ("a/" + cls.name)) : "@" + cls.name;
|
||||||
}
|
}
|
||||||
while (arrayDegree-- > 0) {
|
while (arrayDegree-- > 0) {
|
||||||
clsName += "[]";
|
clsName += "[]";
|
||||||
|
@ -661,6 +649,9 @@ function Long(lo, hi) {
|
||||||
this.lo = lo | 0;
|
this.lo = lo | 0;
|
||||||
this.hi = hi | 0;
|
this.hi = hi | 0;
|
||||||
}
|
}
|
||||||
|
Long.prototype.__teavm_class__ = function() {
|
||||||
|
return "long";
|
||||||
|
};
|
||||||
Long.prototype.toString = function() {
|
Long.prototype.toString = function() {
|
||||||
var result = [];
|
var result = [];
|
||||||
var n = this;
|
var n = this;
|
||||||
|
@ -677,6 +668,9 @@ Long.prototype.toString = function() {
|
||||||
result = result.reverse().join('');
|
result = result.reverse().join('');
|
||||||
return positive ? result : "-" + result;
|
return positive ? result : "-" + result;
|
||||||
};
|
};
|
||||||
|
Long.prototype.valueOf = function() {
|
||||||
|
return Long_toNumber(this);
|
||||||
|
};
|
||||||
var Long_ZERO = new Long(0, 0);
|
var Long_ZERO = new Long(0, 0);
|
||||||
var Long_MAX_NORMAL = 1 << 18;
|
var Long_MAX_NORMAL = 1 << 18;
|
||||||
function Long_fromInt(val) {
|
function Long_fromInt(val) {
|
||||||
|
|
|
@ -18,8 +18,8 @@
|
||||||
<head>
|
<head>
|
||||||
<title>Continuation-passing style demo</title>
|
<title>Continuation-passing style demo</title>
|
||||||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
|
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
|
||||||
<script type="text/javascript" charset="utf-8" src="teavm/classes.js"></script>
|
|
||||||
<script type="text/javascript" charset="utf-8" src="teavm/stdout.js"></script>
|
<script type="text/javascript" charset="utf-8" src="teavm/stdout.js"></script>
|
||||||
|
<script type="text/javascript" charset="utf-8" src="teavm/classes.js"></script>
|
||||||
<script type="text/javascript" charset="utf-8" src="highlight.pack.js"></script>
|
<script type="text/javascript" charset="utf-8" src="highlight.pack.js"></script>
|
||||||
<link rel="stylesheet" type="text/css" href="style.css">
|
<link rel="stylesheet" type="text/css" href="style.css">
|
||||||
<link rel="stylesheet" type="text/css" href="syntax.css">
|
<link rel="stylesheet" type="text/css" href="syntax.css">
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
function $rt_putStdout(ch) {
|
var $rt_stdoutBuffer = "";
|
||||||
if (ch == 0xA) {
|
function $rt_putStdoutCustom(ch) {
|
||||||
|
if (ch === 0xA) {
|
||||||
var lineElem = document.createElement("div");
|
var lineElem = document.createElement("div");
|
||||||
var stdoutElem = document.getElementById("stdout");
|
var stdoutElem = document.getElementById("stdout");
|
||||||
lineElem.appendChild(document.createTextNode($rt_stdoutBuffer));
|
lineElem.appendChild(document.createTextNode($rt_stdoutBuffer));
|
||||||
|
|
|
@ -21,7 +21,6 @@ import org.apache.commons.io.output.ByteArrayOutputStream;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.teavm.backend.javascript.JavaScriptTarget;
|
import org.teavm.backend.javascript.JavaScriptTarget;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
import org.teavm.model.ValueType;
|
|
||||||
import org.teavm.tooling.TeaVMProblemRenderer;
|
import org.teavm.tooling.TeaVMProblemRenderer;
|
||||||
import org.teavm.tooling.TeaVMToolLog;
|
import org.teavm.tooling.TeaVMToolLog;
|
||||||
import org.teavm.vm.TeaVM;
|
import org.teavm.vm.TeaVM;
|
||||||
|
@ -76,8 +75,9 @@ public class ClassValueTest {
|
||||||
|
|
||||||
private DependencyInfo runTest(String methodName) {
|
private DependencyInfo runTest(String methodName) {
|
||||||
TeaVM vm = new TeaVMBuilder(new JavaScriptTarget()).build();
|
TeaVM vm = new TeaVMBuilder(new JavaScriptTarget()).build();
|
||||||
|
vm.add(new DependencyTestPatcher(getClass().getName(), methodName));
|
||||||
vm.installPlugins();
|
vm.installPlugins();
|
||||||
vm.entryPoint(new MethodReference(getClass().getName(), methodName, ValueType.VOID));
|
vm.entryPoint(getClass().getName());
|
||||||
vm.build(fileName -> new ByteArrayOutputStream(), "tmp");
|
vm.build(fileName -> new ByteArrayOutputStream(), "tmp");
|
||||||
if (!vm.getProblemProvider().getSevereProblems().isEmpty()) {
|
if (!vm.getProblemProvider().getSevereProblems().isEmpty()) {
|
||||||
fail("Code compiled with errors:\n" + describeProblems(vm));
|
fail("Code compiled with errors:\n" + describeProblems(vm));
|
||||||
|
|
|
@ -123,11 +123,12 @@ public class DependencyTest {
|
||||||
return TeaVMProgressFeedback.CONTINUE;
|
return TeaVMProgressFeedback.CONTINUE;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
vm.add(new DependencyTestPatcher(DependencyTestData.class.getName(), testName.getMethodName()));
|
||||||
vm.installPlugins();
|
vm.installPlugins();
|
||||||
|
|
||||||
MethodReference testMethod = new MethodReference(DependencyTestData.class,
|
MethodReference testMethod = new MethodReference(DependencyTestData.class,
|
||||||
testName.getMethodName(), void.class);
|
testName.getMethodName(), void.class);
|
||||||
vm.entryPoint(testMethod).withValue(0, DependencyTestData.class.getName());
|
vm.entryPoint(DependencyTestData.class.getName());
|
||||||
vm.build(fileName -> new ByteArrayOutputStream(), "out");
|
vm.build(fileName -> new ByteArrayOutputStream(), "out");
|
||||||
|
|
||||||
List<Problem> problems = vm.getProblemProvider().getSevereProblems();
|
List<Problem> problems = vm.getProblemProvider().getSevereProblems();
|
||||||
|
|
|
@ -16,15 +16,18 @@
|
||||||
package org.teavm.dependency;
|
package org.teavm.dependency;
|
||||||
|
|
||||||
public class DependencyTestData {
|
public class DependencyTestData {
|
||||||
public void virtualCall() {
|
private DependencyTestData() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void virtualCall() {
|
||||||
MetaAssertions.assertTypes(getI(0).foo(), String.class, Integer.class, Class.class);
|
MetaAssertions.assertTypes(getI(0).foo(), String.class, Integer.class, Class.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void instanceOf() {
|
public static void instanceOf() {
|
||||||
MetaAssertions.assertTypes((String) getI(0).foo(), String.class);
|
MetaAssertions.assertTypes((String) getI(0).foo(), String.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void catchException() throws Exception {
|
public static void catchException() throws Exception {
|
||||||
try {
|
try {
|
||||||
throw createException(0);
|
throw createException(0);
|
||||||
} catch (IndexOutOfBoundsException e) {
|
} catch (IndexOutOfBoundsException e) {
|
||||||
|
@ -34,7 +37,7 @@ public class DependencyTestData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void propagateException() {
|
public static void propagateException() {
|
||||||
try {
|
try {
|
||||||
catchException();
|
catchException();
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
|
@ -42,12 +45,12 @@ public class DependencyTestData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void arrays() {
|
public static void arrays() {
|
||||||
Object[] array = { new String("123"), new Integer(123), String.class };
|
Object[] array = { new String("123"), new Integer(123), String.class };
|
||||||
MetaAssertions.assertTypes(array[0], String.class, Integer.class, Class.class);
|
MetaAssertions.assertTypes(array[0], String.class, Integer.class, Class.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void arraysPassed() {
|
public static void arraysPassed() {
|
||||||
Object[] array = new Object[3];
|
Object[] array = new Object[3];
|
||||||
fillArray(array);
|
fillArray(array);
|
||||||
MetaAssertions.assertTypes(array[0], String.class, Integer.class, Class.class);
|
MetaAssertions.assertTypes(array[0], String.class, Integer.class, Class.class);
|
||||||
|
@ -58,7 +61,7 @@ public class DependencyTestData {
|
||||||
MetaAssertions.assertTypes(array2[0], Long.class, RuntimeException.class);
|
MetaAssertions.assertTypes(array2[0], Long.class, RuntimeException.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void arraysRetrieved() {
|
public static void arraysRetrieved() {
|
||||||
Object[] array = createArray();
|
Object[] array = createArray();
|
||||||
MetaAssertions.assertTypes(array[0], String.class, Integer.class, Class.class);
|
MetaAssertions.assertTypes(array[0], String.class, Integer.class, Class.class);
|
||||||
|
|
||||||
|
@ -70,24 +73,24 @@ public class DependencyTestData {
|
||||||
|
|
||||||
static Object[] staticArrayField;
|
static Object[] staticArrayField;
|
||||||
|
|
||||||
private Object[] createArray() {
|
private static Object[] createArray() {
|
||||||
Object[] array = new Object[3];
|
Object[] array = new Object[3];
|
||||||
fillArray(array);
|
fillArray(array);
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fillArray(Object[] array) {
|
private static void fillArray(Object[] array) {
|
||||||
array[0] = "123";
|
array[0] = "123";
|
||||||
array[1] = 123;
|
array[1] = 123;
|
||||||
array[2] = String.class;
|
array[2] = String.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fillStaticArray() {
|
private static void fillStaticArray() {
|
||||||
staticArrayField[0] = 42L;
|
staticArrayField[0] = 42L;
|
||||||
staticArrayField[0] = new RuntimeException();
|
staticArrayField[0] = new RuntimeException();
|
||||||
}
|
}
|
||||||
|
|
||||||
private I getI(int index) {
|
private static I getI(int index) {
|
||||||
switch (index) {
|
switch (index) {
|
||||||
case 0:
|
case 0:
|
||||||
return new A();
|
return new A();
|
||||||
|
@ -98,7 +101,7 @@ public class DependencyTestData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Exception createException(int index) {
|
private static Exception createException(int index) {
|
||||||
switch (index) {
|
switch (index) {
|
||||||
case 0:
|
case 0:
|
||||||
throw new IndexOutOfBoundsException();
|
throw new IndexOutOfBoundsException();
|
||||||
|
@ -115,21 +118,21 @@ public class DependencyTestData {
|
||||||
Object foo();
|
Object foo();
|
||||||
}
|
}
|
||||||
|
|
||||||
class A implements I {
|
static class A implements I {
|
||||||
@Override
|
@Override
|
||||||
public Object foo() {
|
public Object foo() {
|
||||||
return "123";
|
return "123";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class B implements I {
|
static class B implements I {
|
||||||
@Override
|
@Override
|
||||||
public Object foo() {
|
public Object foo() {
|
||||||
return Object.class;
|
return Object.class;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class C implements I {
|
static class C implements I {
|
||||||
@Override
|
@Override
|
||||||
public Object foo() {
|
public Object foo() {
|
||||||
return 123;
|
return 123;
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2018 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.dependency;
|
||||||
|
|
||||||
|
import org.teavm.diagnostics.Diagnostics;
|
||||||
|
import org.teavm.model.AccessLevel;
|
||||||
|
import org.teavm.model.BasicBlock;
|
||||||
|
import org.teavm.model.ClassHolder;
|
||||||
|
import org.teavm.model.ClassHolderTransformer;
|
||||||
|
import org.teavm.model.ClassReaderSource;
|
||||||
|
import org.teavm.model.ElementModifier;
|
||||||
|
import org.teavm.model.MethodHolder;
|
||||||
|
import org.teavm.model.MethodReference;
|
||||||
|
import org.teavm.model.Program;
|
||||||
|
import org.teavm.model.ValueType;
|
||||||
|
import org.teavm.model.instructions.ExitInstruction;
|
||||||
|
import org.teavm.model.instructions.InvocationType;
|
||||||
|
import org.teavm.model.instructions.InvokeInstruction;
|
||||||
|
|
||||||
|
public class DependencyTestPatcher implements ClassHolderTransformer {
|
||||||
|
private String className;
|
||||||
|
private String methodName;
|
||||||
|
|
||||||
|
public DependencyTestPatcher(String className, String methodName) {
|
||||||
|
this.className = className;
|
||||||
|
this.methodName = methodName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void transformClass(ClassHolder cls, ClassReaderSource innerSource, Diagnostics diagnostics) {
|
||||||
|
if (cls.getName().equals(className)) {
|
||||||
|
MethodHolder method = new MethodHolder("main", ValueType.parse(String[].class), ValueType.VOID);
|
||||||
|
method.setLevel(AccessLevel.PUBLIC);
|
||||||
|
method.getModifiers().add(ElementModifier.STATIC);
|
||||||
|
|
||||||
|
Program program = new Program();
|
||||||
|
program.createVariable();
|
||||||
|
program.createVariable();
|
||||||
|
BasicBlock block = program.createBasicBlock();
|
||||||
|
method.setProgram(program);
|
||||||
|
|
||||||
|
InvokeInstruction invoke = new InvokeInstruction();
|
||||||
|
invoke.setType(InvocationType.SPECIAL);
|
||||||
|
invoke.setMethod(new MethodReference(className, methodName, ValueType.VOID));
|
||||||
|
block.add(invoke);
|
||||||
|
|
||||||
|
block.add(new ExitInstruction());
|
||||||
|
|
||||||
|
cls.addMethod(method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,6 +22,7 @@ import java.io.ByteArrayOutputStream;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.teavm.backend.javascript.JavaScriptTarget;
|
import org.teavm.backend.javascript.JavaScriptTarget;
|
||||||
|
import org.teavm.dependency.DependencyTestPatcher;
|
||||||
import org.teavm.diagnostics.Problem;
|
import org.teavm.diagnostics.Problem;
|
||||||
import org.teavm.jso.JSBody;
|
import org.teavm.jso.JSBody;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
|
@ -94,8 +95,9 @@ public class JSOTest {
|
||||||
|
|
||||||
private List<Problem> build(String methodName) {
|
private List<Problem> build(String methodName) {
|
||||||
TeaVM vm = new TeaVMBuilder(new JavaScriptTarget()).build();
|
TeaVM vm = new TeaVMBuilder(new JavaScriptTarget()).build();
|
||||||
|
vm.add(new DependencyTestPatcher(JSOTest.class.getName(), methodName));
|
||||||
vm.installPlugins();
|
vm.installPlugins();
|
||||||
vm.entryPoint("org/teavm/metaprogramming/test", new MethodReference(JSOTest.class, methodName, void.class));
|
vm.entryPoint(JSOTest.class.getName());
|
||||||
vm.build(name -> new ByteArrayOutputStream(), "tmp");
|
vm.build(name -> new ByteArrayOutputStream(), "tmp");
|
||||||
return vm.getProblemProvider().getSevereProblems();
|
return vm.getProblemProvider().getSevereProblems();
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,38 +58,25 @@ function appendFiles(files, index, callback, errorCallback) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function launchTest(callback) {
|
function launchTest(callback) {
|
||||||
$rt_startThread(() => {
|
main([], result => {
|
||||||
let thread = $rt_nativeThread();
|
if (result instanceof Error) {
|
||||||
let instance;
|
|
||||||
let message;
|
|
||||||
if (thread.isResuming()) {
|
|
||||||
instance = thread.pop();
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
runTest();
|
|
||||||
} catch (e) {
|
|
||||||
message = buildErrorMessage(e);
|
|
||||||
callback({
|
callback({
|
||||||
status: "failed",
|
status: "failed",
|
||||||
errorMessage: buildErrorMessage(e)
|
errorMessage: buildErrorMessage(e)
|
||||||
});
|
});
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (thread.isSuspending()) {
|
|
||||||
thread.push(instance);
|
|
||||||
} else {
|
} else {
|
||||||
callback({ status: "OK" });
|
callback({ status: "OK" });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function buildErrorMessage(e) {
|
function buildErrorMessage(e) {
|
||||||
let stack = e.stack;
|
let stack = "";
|
||||||
if (e.$javaException && e.$javaException.constructor.$meta) {
|
if (e.$javaException && e.$javaException.constructor.$meta) {
|
||||||
stack = e.$javaException.constructor.$meta.name + ": ";
|
stack = e.$javaException.constructor.$meta.name + ": ";
|
||||||
let exceptionMessage = extractException(e.$javaException);
|
stack += e.$javaException.getMessage();
|
||||||
stack += exceptionMessage ? $rt_ustr(exceptionMessage) : "";
|
stack += "\n";
|
||||||
}
|
}
|
||||||
stack += "\n" + stack;
|
stack += e.stack;
|
||||||
return stack;
|
return stack;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,10 +43,13 @@ import org.teavm.chromerdp.data.Response;
|
||||||
import org.teavm.chromerdp.data.ScopeDTO;
|
import org.teavm.chromerdp.data.ScopeDTO;
|
||||||
import org.teavm.chromerdp.messages.CallFunctionCommand;
|
import org.teavm.chromerdp.messages.CallFunctionCommand;
|
||||||
import org.teavm.chromerdp.messages.CallFunctionResponse;
|
import org.teavm.chromerdp.messages.CallFunctionResponse;
|
||||||
|
import org.teavm.chromerdp.messages.CompileScriptCommand;
|
||||||
|
import org.teavm.chromerdp.messages.CompileScriptResponse;
|
||||||
import org.teavm.chromerdp.messages.ContinueToLocationCommand;
|
import org.teavm.chromerdp.messages.ContinueToLocationCommand;
|
||||||
import org.teavm.chromerdp.messages.GetPropertiesCommand;
|
import org.teavm.chromerdp.messages.GetPropertiesCommand;
|
||||||
import org.teavm.chromerdp.messages.GetPropertiesResponse;
|
import org.teavm.chromerdp.messages.GetPropertiesResponse;
|
||||||
import org.teavm.chromerdp.messages.RemoveBreakpointCommand;
|
import org.teavm.chromerdp.messages.RemoveBreakpointCommand;
|
||||||
|
import org.teavm.chromerdp.messages.RunScriptCommand;
|
||||||
import org.teavm.chromerdp.messages.ScriptParsedNotification;
|
import org.teavm.chromerdp.messages.ScriptParsedNotification;
|
||||||
import org.teavm.chromerdp.messages.SetBreakpointCommand;
|
import org.teavm.chromerdp.messages.SetBreakpointCommand;
|
||||||
import org.teavm.chromerdp.messages.SetBreakpointResponse;
|
import org.teavm.chromerdp.messages.SetBreakpointResponse;
|
||||||
|
@ -107,9 +110,26 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void injectFunctions(int contextId) {
|
||||||
|
callMethod("Runtime.enable", void.class, null);
|
||||||
|
|
||||||
|
CompileScriptCommand compileParams = new CompileScriptCommand();
|
||||||
|
compileParams.expression = "$dbg_class = function(obj) { return typeof obj === 'object' && obj != null "
|
||||||
|
+ "? obj.__teavm_class__() : null };";
|
||||||
|
compileParams.sourceURL = "file://fake";
|
||||||
|
compileParams.persistScript = true;
|
||||||
|
compileParams.executionContextId = contextId;
|
||||||
|
CompileScriptResponse response = callMethod("Runtime.compileScript", CompileScriptResponse.class,
|
||||||
|
compileParams);
|
||||||
|
|
||||||
|
RunScriptCommand runParams = new RunScriptCommand();
|
||||||
|
runParams.scriptId = response.scriptId;
|
||||||
|
callMethod("Runtime.runScript", void.class, runParams);
|
||||||
|
}
|
||||||
|
|
||||||
private ChromeRDPExchangeListener exchangeListener = this::receiveMessage;
|
private ChromeRDPExchangeListener exchangeListener = this::receiveMessage;
|
||||||
|
|
||||||
private void receiveMessage(final String messageText) {
|
private void receiveMessage(String messageText) {
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
JsonNode jsonMessage = mapper.readTree(messageText);
|
JsonNode jsonMessage = mapper.readTree(messageText);
|
||||||
|
@ -188,9 +208,9 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC
|
||||||
for (JavaScriptDebuggerListener listener : getListeners()) {
|
for (JavaScriptDebuggerListener listener : getListeners()) {
|
||||||
listener.scriptAdded(params.getUrl());
|
listener.scriptAdded(params.getUrl());
|
||||||
}
|
}
|
||||||
|
injectFunctions(params.getExecutionContextId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addListener(JavaScriptDebuggerListener listener) {
|
public void addListener(JavaScriptDebuggerListener listener) {
|
||||||
listeners.put(listener, dummy);
|
listeners.put(listener, dummy);
|
||||||
|
@ -203,65 +223,34 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void suspend() {
|
public void suspend() {
|
||||||
if (exchange == null) {
|
callMethod("Debugger.pause", void.class, null);
|
||||||
return;
|
|
||||||
}
|
|
||||||
Message message = new Message();
|
|
||||||
message.setMethod("Debugger.pause");
|
|
||||||
sendMessage(message);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void resume() {
|
public void resume() {
|
||||||
if (exchange == null) {
|
callMethod("Debugger.resume", void.class, null);
|
||||||
return;
|
|
||||||
}
|
|
||||||
Message message = new Message();
|
|
||||||
message.setMethod("Debugger.resume");
|
|
||||||
sendMessage(message);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stepInto() {
|
public void stepInto() {
|
||||||
if (exchange == null) {
|
callMethod("Debugger.stepInto", void.class, null);
|
||||||
return;
|
|
||||||
}
|
|
||||||
Message message = new Message();
|
|
||||||
message.setMethod("Debugger.stepInto");
|
|
||||||
sendMessage(message);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stepOut() {
|
public void stepOut() {
|
||||||
if (exchange == null) {
|
callMethod("Debugger.stepOut", void.class, null);
|
||||||
return;
|
|
||||||
}
|
|
||||||
Message message = new Message();
|
|
||||||
message.setMethod("Debugger.stepOut");
|
|
||||||
sendMessage(message);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stepOver() {
|
public void stepOver() {
|
||||||
if (exchange == null) {
|
callMethod("Debugger.stepOver", void.class, null);
|
||||||
return;
|
|
||||||
}
|
|
||||||
Message message = new Message();
|
|
||||||
message.setMethod("Debugger.stepOver");
|
|
||||||
sendMessage(message);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void continueToLocation(JavaScriptLocation location) {
|
public void continueToLocation(JavaScriptLocation location) {
|
||||||
if (exchange == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Message message = new Message();
|
|
||||||
message.setMethod("Debugger.continueToLocation");
|
|
||||||
ContinueToLocationCommand params = new ContinueToLocationCommand();
|
ContinueToLocationCommand params = new ContinueToLocationCommand();
|
||||||
params.setLocation(unmap(location));
|
params.setLocation(unmap(location));
|
||||||
message.setParams(mapper.valueToTree(params));
|
callMethod("Debugger.continueToLocation", void.class, params);
|
||||||
sendMessage(message);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -341,12 +330,9 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC
|
||||||
if (logger.isInfoEnabled()) {
|
if (logger.isInfoEnabled()) {
|
||||||
logger.info("Removing breakpoint at {}", breakpoint.getLocation());
|
logger.info("Removing breakpoint at {}", breakpoint.getLocation());
|
||||||
}
|
}
|
||||||
Message message = new Message();
|
|
||||||
message.setMethod("Debugger.removeBreakpoint");
|
|
||||||
RemoveBreakpointCommand params = new RemoveBreakpointCommand();
|
RemoveBreakpointCommand params = new RemoveBreakpointCommand();
|
||||||
params.setBreakpointId(breakpoint.chromeId);
|
params.setBreakpointId(breakpoint.chromeId);
|
||||||
message.setParams(mapper.valueToTree(params));
|
callMethod("Debugger.removeBreakpoint", void.class, params);
|
||||||
sendMessage(message);
|
|
||||||
}
|
}
|
||||||
breakpoint.debugger = null;
|
breakpoint.debugger = null;
|
||||||
breakpoint.chromeId = null;
|
breakpoint.chromeId = null;
|
||||||
|
@ -356,152 +342,79 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateBreakpoint(final RDPBreakpoint breakpoint) {
|
private void updateBreakpoint(final RDPBreakpoint breakpoint) {
|
||||||
if (exchange == null || breakpoint.chromeId != null) {
|
if (breakpoint.chromeId != null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final Message message = new Message();
|
|
||||||
message.setId(messageIdGenerator.incrementAndGet());
|
|
||||||
message.setMethod("Debugger.setBreakpoint");
|
|
||||||
SetBreakpointCommand params = new SetBreakpointCommand();
|
SetBreakpointCommand params = new SetBreakpointCommand();
|
||||||
params.setLocation(unmap(breakpoint.getLocation()));
|
params.setLocation(unmap(breakpoint.getLocation()));
|
||||||
message.setParams(mapper.valueToTree(params));
|
|
||||||
if (logger.isInfoEnabled()) {
|
if (logger.isInfoEnabled()) {
|
||||||
logger.info("Setting breakpoint at {}, message id is ", breakpoint.getLocation(), message.getId());
|
logger.info("Setting breakpoint at {}", breakpoint.getLocation());
|
||||||
}
|
}
|
||||||
setResponseHandler(message.getId(), (node, out) -> {
|
|
||||||
if (breakpoint.chromeId != null) {
|
breakpoint.updating.set(true);
|
||||||
breakpointsByChromeId.remove(breakpoint.chromeId);
|
try {
|
||||||
}
|
SetBreakpointResponse response = callMethod("Debugger.setBreakpoint", SetBreakpointResponse.class, params);
|
||||||
if (node != null) {
|
if (response == null) {
|
||||||
SetBreakpointResponse response = mapper.reader(SetBreakpointResponse.class).readValue(node);
|
|
||||||
breakpoint.chromeId = response.getBreakpointId();
|
breakpoint.chromeId = response.getBreakpointId();
|
||||||
if (breakpoint.chromeId != null) {
|
if (breakpoint.chromeId != null) {
|
||||||
breakpointsByChromeId.put(breakpoint.chromeId, breakpoint);
|
breakpointsByChromeId.put(breakpoint.chromeId, breakpoint);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (logger.isWarnEnabled()) {
|
if (logger.isWarnEnabled()) {
|
||||||
logger.warn("Error setting breakpoint at {}, message id is {}",
|
logger.warn("Error setting breakpoint at {}", breakpoint.getLocation());
|
||||||
breakpoint.getLocation(), message.getId());
|
|
||||||
}
|
}
|
||||||
breakpoint.chromeId = null;
|
breakpoint.chromeId = null;
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
synchronized (breakpoint.updateMonitor) {
|
synchronized (breakpoint.updateMonitor) {
|
||||||
breakpoint.updating.set(false);
|
breakpoint.updating.set(false);
|
||||||
breakpoint.updateMonitor.notifyAll();
|
breakpoint.updateMonitor.notifyAll();
|
||||||
}
|
}
|
||||||
for (JavaScriptDebuggerListener listener : getListeners()) {
|
}
|
||||||
listener.breakpointChanged(breakpoint);
|
|
||||||
}
|
for (JavaScriptDebuggerListener listener : getListeners()) {
|
||||||
});
|
listener.breakpointChanged(breakpoint);
|
||||||
breakpoint.updating.set(true);
|
}
|
||||||
sendMessage(message);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
List<RDPLocalVariable> getScope(String scopeId) {
|
List<RDPLocalVariable> getScope(String scopeId) {
|
||||||
if (exchange == null) {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
Message message = new Message();
|
|
||||||
message.setId(messageIdGenerator.incrementAndGet());
|
|
||||||
message.setMethod("Runtime.getProperties");
|
|
||||||
GetPropertiesCommand params = new GetPropertiesCommand();
|
GetPropertiesCommand params = new GetPropertiesCommand();
|
||||||
params.setObjectId(scopeId);
|
params.setObjectId(scopeId);
|
||||||
params.setOwnProperties(true);
|
params.setOwnProperties(true);
|
||||||
message.setParams(mapper.valueToTree(params));
|
|
||||||
CompletableFuture<List<RDPLocalVariable>> sync = setResponseHandler(message.getId(), (node, out) -> {
|
|
||||||
if (node == null) {
|
|
||||||
out.complete(Collections.emptyList());
|
|
||||||
} else {
|
|
||||||
GetPropertiesResponse response = mapper.reader(GetPropertiesResponse.class).readValue(node);
|
|
||||||
out.complete(parseProperties(response.getResult()));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
sendMessage(message);
|
|
||||||
|
|
||||||
try {
|
GetPropertiesResponse response = callMethod("Runtime.getProperties", GetPropertiesResponse.class, params);
|
||||||
return read(sync);
|
if (response == null) {
|
||||||
} catch (InterruptedException | TimeoutException e) {
|
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return parseProperties(response.getResult());
|
||||||
}
|
}
|
||||||
|
|
||||||
String getClassName(String objectId) {
|
String getClassName(String objectId) {
|
||||||
if (exchange == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
Message message = new Message();
|
|
||||||
message.setId(messageIdGenerator.incrementAndGet());
|
|
||||||
message.setMethod("Runtime.callFunctionOn");
|
|
||||||
CallFunctionCommand params = new CallFunctionCommand();
|
CallFunctionCommand params = new CallFunctionCommand();
|
||||||
CallArgumentDTO arg = new CallArgumentDTO();
|
CallArgumentDTO arg = new CallArgumentDTO();
|
||||||
arg.setObjectId(objectId);
|
arg.setObjectId(objectId);
|
||||||
params.setObjectId(objectId);
|
params.setObjectId(objectId);
|
||||||
params.setArguments(new CallArgumentDTO[] { arg });
|
params.setArguments(new CallArgumentDTO[] { arg });
|
||||||
params.setFunctionDeclaration("$dbg_class");
|
params.setFunctionDeclaration("$dbg_class");
|
||||||
message.setParams(mapper.valueToTree(params));
|
|
||||||
|
|
||||||
CompletableFuture<String> sync = setResponseHandler(message.getId(), (node, out) -> {
|
CallFunctionResponse response = callMethod("Runtime.callFunctionOn", CallFunctionResponse.class, params);
|
||||||
if (node == null) {
|
RemoteObjectDTO result = response != null ? response.getResult() : null;
|
||||||
out.complete("");
|
return result.getValue() != null ? result.getValue().getTextValue() : null;
|
||||||
} else {
|
|
||||||
CallFunctionResponse response = mapper.reader(CallFunctionResponse.class).readValue(node);
|
|
||||||
RemoteObjectDTO result = response.getResult();
|
|
||||||
out.complete(result.getValue() != null ? result.getValue().getTextValue() : "");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
sendMessage(message);
|
|
||||||
try {
|
|
||||||
String result = read(sync);
|
|
||||||
return result.isEmpty() ? null : result;
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
return null;
|
|
||||||
} catch (TimeoutException e) {
|
|
||||||
return "<timed out>";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String getRepresentation(String objectId) {
|
String getRepresentation(String objectId) {
|
||||||
if (exchange == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
Message message = new Message();
|
|
||||||
message.setId(messageIdGenerator.incrementAndGet());
|
|
||||||
message.setMethod("Runtime.callFunctionOn");
|
|
||||||
CallFunctionCommand params = new CallFunctionCommand();
|
CallFunctionCommand params = new CallFunctionCommand();
|
||||||
CallArgumentDTO arg = new CallArgumentDTO();
|
CallArgumentDTO arg = new CallArgumentDTO();
|
||||||
arg.setObjectId(objectId);
|
arg.setObjectId(objectId);
|
||||||
params.setObjectId(objectId);
|
params.setObjectId(objectId);
|
||||||
params.setArguments(new CallArgumentDTO[] { arg });
|
params.setArguments(new CallArgumentDTO[] { arg });
|
||||||
params.setFunctionDeclaration("$dbg_repr");
|
params.setFunctionDeclaration("$dbg_repr");
|
||||||
message.setParams(mapper.valueToTree(params));
|
|
||||||
CompletableFuture<RepresentationWrapper> sync = setResponseHandler(message.getId(), (node, out) -> {
|
|
||||||
if (node == null) {
|
|
||||||
out.complete(new RepresentationWrapper(null));
|
|
||||||
} else {
|
|
||||||
CallFunctionResponse response = mapper.reader(CallFunctionResponse.class).readValue(node);
|
|
||||||
RemoteObjectDTO result = response.getResult();
|
|
||||||
out.complete(new RepresentationWrapper(result.getValue() != null
|
|
||||||
? result.getValue().getTextValue() : null));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
sendMessage(message);
|
|
||||||
try {
|
|
||||||
RepresentationWrapper result = read(sync);
|
|
||||||
return result.repr;
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
return null;
|
|
||||||
} catch (TimeoutException e) {
|
|
||||||
return "<timed out>";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class RepresentationWrapper {
|
CallFunctionResponse response = callMethod("Runtime.callFunctionOn", CallFunctionResponse.class, params);
|
||||||
String repr;
|
RemoteObjectDTO result = response != null ? response.getResult() : null;
|
||||||
|
return result.getValue() != null ? result.getValue().getTextValue() : null;
|
||||||
RepresentationWrapper(String repr) {
|
|
||||||
super();
|
|
||||||
this.repr = repr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<RDPLocalVariable> parseProperties(PropertyDescriptorDTO[] properties) {
|
private List<RDPLocalVariable> parseProperties(PropertyDescriptorDTO[] properties) {
|
||||||
|
@ -585,6 +498,36 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC
|
||||||
return dto;
|
return dto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private <R> R callMethod(String method, Class<R> returnType, Object params) {
|
||||||
|
if (exchange == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Message message = new Message();
|
||||||
|
message.setId(messageIdGenerator.incrementAndGet());
|
||||||
|
message.setMethod(method);
|
||||||
|
if (params != null) {
|
||||||
|
message.setParams(mapper.valueToTree(params));
|
||||||
|
}
|
||||||
|
|
||||||
|
CompletableFuture<R> sync = setResponseHandler(message.getId(), (node, out) -> {
|
||||||
|
if (node == null) {
|
||||||
|
out.complete(null);
|
||||||
|
} else {
|
||||||
|
R response = returnType != void.class ? mapper.reader(returnType).readValue(node) : null;
|
||||||
|
out.complete(response);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
sendMessage(message);
|
||||||
|
try {
|
||||||
|
return read(sync);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
return null;
|
||||||
|
} catch (TimeoutException e) {
|
||||||
|
logger.warn("Chrome debug protocol: timed out", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private <T> CompletableFuture<T> setResponseHandler(int messageId, ResponseHandler<T> handler) {
|
private <T> CompletableFuture<T> setResponseHandler(int messageId, ResponseHandler<T> handler) {
|
||||||
CompletableFuture<T> future = new CompletableFuture<>();
|
CompletableFuture<T> future = new CompletableFuture<>();
|
||||||
|
|
|
@ -20,7 +20,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import org.teavm.debugging.javascript.JavaScriptBreakpoint;
|
import org.teavm.debugging.javascript.JavaScriptBreakpoint;
|
||||||
import org.teavm.debugging.javascript.JavaScriptLocation;
|
import org.teavm.debugging.javascript.JavaScriptLocation;
|
||||||
|
|
||||||
public class RDPBreakpoint implements JavaScriptBreakpoint {
|
class RDPBreakpoint implements JavaScriptBreakpoint {
|
||||||
volatile String chromeId;
|
volatile String chromeId;
|
||||||
ChromeRDPDebugger debugger;
|
ChromeRDPDebugger debugger;
|
||||||
private JavaScriptLocation location;
|
private JavaScriptLocation location;
|
||||||
|
|
|
@ -19,7 +19,7 @@ import java.util.Collections;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import org.teavm.debugging.javascript.*;
|
import org.teavm.debugging.javascript.*;
|
||||||
|
|
||||||
public class RDPCallFrame implements JavaScriptCallFrame {
|
class RDPCallFrame implements JavaScriptCallFrame {
|
||||||
private JavaScriptDebugger debugger;
|
private JavaScriptDebugger debugger;
|
||||||
private String chromeId;
|
private String chromeId;
|
||||||
private JavaScriptLocation location;
|
private JavaScriptLocation location;
|
||||||
|
@ -27,7 +27,7 @@ public class RDPCallFrame implements JavaScriptCallFrame {
|
||||||
private JavaScriptValue thisObject;
|
private JavaScriptValue thisObject;
|
||||||
private JavaScriptValue closure;
|
private JavaScriptValue closure;
|
||||||
|
|
||||||
public RDPCallFrame(JavaScriptDebugger debugger, String chromeId, JavaScriptLocation location,
|
RDPCallFrame(JavaScriptDebugger debugger, String chromeId, JavaScriptLocation location,
|
||||||
Map<String, ? extends JavaScriptVariable> variables, JavaScriptValue thisObject,
|
Map<String, ? extends JavaScriptVariable> variables, JavaScriptValue thisObject,
|
||||||
JavaScriptValue closure) {
|
JavaScriptValue closure) {
|
||||||
this.debugger = debugger;
|
this.debugger = debugger;
|
||||||
|
|
|
@ -18,11 +18,11 @@ package org.teavm.chromerdp;
|
||||||
import org.teavm.debugging.javascript.JavaScriptValue;
|
import org.teavm.debugging.javascript.JavaScriptValue;
|
||||||
import org.teavm.debugging.javascript.JavaScriptVariable;
|
import org.teavm.debugging.javascript.JavaScriptVariable;
|
||||||
|
|
||||||
public class RDPLocalVariable implements JavaScriptVariable {
|
class RDPLocalVariable implements JavaScriptVariable {
|
||||||
private String name;
|
private String name;
|
||||||
private RDPValue value;
|
private RDPValue value;
|
||||||
|
|
||||||
public RDPLocalVariable(String name, RDPValue value) {
|
RDPLocalVariable(String name, RDPValue value) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,12 +21,12 @@ import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
public class RDPScope extends AbstractMap<String, RDPLocalVariable> {
|
class RDPScope extends AbstractMap<String, RDPLocalVariable> {
|
||||||
private AtomicReference<Map<String, RDPLocalVariable>> backingMap = new AtomicReference<>();
|
private AtomicReference<Map<String, RDPLocalVariable>> backingMap = new AtomicReference<>();
|
||||||
private ChromeRDPDebugger debugger;
|
private ChromeRDPDebugger debugger;
|
||||||
private String id;
|
private String id;
|
||||||
|
|
||||||
public RDPScope(ChromeRDPDebugger debugger, String id) {
|
RDPScope(ChromeRDPDebugger debugger, String id) {
|
||||||
this.debugger = debugger;
|
this.debugger = debugger;
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ import java.util.concurrent.atomic.AtomicReference;
|
||||||
import org.teavm.debugging.javascript.JavaScriptValue;
|
import org.teavm.debugging.javascript.JavaScriptValue;
|
||||||
import org.teavm.debugging.javascript.JavaScriptVariable;
|
import org.teavm.debugging.javascript.JavaScriptVariable;
|
||||||
|
|
||||||
public class RDPValue implements JavaScriptValue {
|
class RDPValue implements JavaScriptValue {
|
||||||
private AtomicReference<String> representation = new AtomicReference<>();
|
private AtomicReference<String> representation = new AtomicReference<>();
|
||||||
private AtomicReference<String> className = new AtomicReference<>();
|
private AtomicReference<String> className = new AtomicReference<>();
|
||||||
private String typeName;
|
private String typeName;
|
||||||
|
@ -30,15 +30,14 @@ public class RDPValue implements JavaScriptValue {
|
||||||
private Map<String, ? extends JavaScriptVariable> properties;
|
private Map<String, ? extends JavaScriptVariable> properties;
|
||||||
private boolean innerStructure;
|
private boolean innerStructure;
|
||||||
|
|
||||||
public RDPValue(ChromeRDPDebugger debugger, String representation, String typeName, String objectId,
|
RDPValue(ChromeRDPDebugger debugger, String representation, String typeName, String objectId,
|
||||||
boolean innerStructure) {
|
boolean innerStructure) {
|
||||||
this.representation.set(representation == null && objectId == null ? "" : representation);
|
this.representation.set(representation == null && objectId == null ? "" : representation);
|
||||||
this.typeName = typeName;
|
this.typeName = typeName;
|
||||||
this.debugger = debugger;
|
this.debugger = debugger;
|
||||||
this.objectId = objectId;
|
this.objectId = objectId;
|
||||||
this.innerStructure = innerStructure;
|
this.innerStructure = innerStructure;
|
||||||
properties = objectId != null ? new RDPScope(debugger, objectId)
|
properties = objectId != null ? new RDPScope(debugger, objectId) : Collections.emptyMap();
|
||||||
: Collections.<String, RDPLocalVariable>emptyMap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2018 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.chromerdp.messages;
|
||||||
|
|
||||||
|
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
|
||||||
|
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
public class CompileScriptCommand {
|
||||||
|
public String expression;
|
||||||
|
public String sourceURL;
|
||||||
|
public boolean persistScript;
|
||||||
|
public int executionContextId;
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2018 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.chromerdp.messages;
|
||||||
|
|
||||||
|
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
|
||||||
|
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
public class CompileScriptResponse {
|
||||||
|
public String scriptId;
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2016 Alexey Andreev.
|
* Copyright 2018 Alexey Andreev.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -13,13 +13,11 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.teavm.junit;
|
package org.teavm.chromerdp.messages;
|
||||||
|
|
||||||
final class ExceptionHelper {
|
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
|
||||||
private ExceptionHelper() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String showException(Throwable e) {
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
return e.getMessage();
|
public class RunScriptCommand {
|
||||||
}
|
public String scriptId;
|
||||||
}
|
}
|
|
@ -21,6 +21,7 @@ import org.codehaus.jackson.annotate.JsonIgnoreProperties;
|
||||||
public class ScriptParsedNotification {
|
public class ScriptParsedNotification {
|
||||||
private String scriptId;
|
private String scriptId;
|
||||||
private String url;
|
private String url;
|
||||||
|
private int executionContextId;
|
||||||
|
|
||||||
public String getScriptId() {
|
public String getScriptId() {
|
||||||
return scriptId;
|
return scriptId;
|
||||||
|
@ -37,4 +38,12 @@ public class ScriptParsedNotification {
|
||||||
public void setUrl(String url) {
|
public void setUrl(String url) {
|
||||||
this.url = url;
|
this.url = url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getExecutionContextId() {
|
||||||
|
return executionContextId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExecutionContextId(int executionContextId) {
|
||||||
|
this.executionContextId = executionContextId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,6 @@ import org.teavm.model.ClassHolderSource;
|
||||||
import org.teavm.model.ClassHolderTransformer;
|
import org.teavm.model.ClassHolderTransformer;
|
||||||
import org.teavm.model.ClassReader;
|
import org.teavm.model.ClassReader;
|
||||||
import org.teavm.model.ClassReaderSource;
|
import org.teavm.model.ClassReaderSource;
|
||||||
import org.teavm.model.MethodDescriptor;
|
|
||||||
import org.teavm.model.MethodReader;
|
import org.teavm.model.MethodReader;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
import org.teavm.model.PreOptimizingClassHolderSource;
|
import org.teavm.model.PreOptimizingClassHolderSource;
|
||||||
|
@ -382,11 +381,7 @@ public class TeaVMTool implements BaseTeaVMTool {
|
||||||
vm.add(transformer);
|
vm.add(transformer);
|
||||||
}
|
}
|
||||||
if (mainClass != null) {
|
if (mainClass != null) {
|
||||||
MethodDescriptor mainMethodDesc = new MethodDescriptor("main", String[].class, void.class);
|
vm.entryPoint(mainClass);
|
||||||
vm.entryPoint("main", new MethodReference(mainClass, mainMethodDesc))
|
|
||||||
.withValue(1, "[java.lang.String")
|
|
||||||
.withArrayValue(1, "java.lang.String")
|
|
||||||
.async();
|
|
||||||
}
|
}
|
||||||
for (String className : classesToPreserve) {
|
for (String className : classesToPreserve) {
|
||||||
vm.preserveType(className);
|
vm.preserveType(className);
|
||||||
|
@ -418,7 +413,7 @@ public class TeaVMTool implements BaseTeaVMTool {
|
||||||
|
|
||||||
if (targetType == TeaVMTargetType.JAVASCRIPT) {
|
if (targetType == TeaVMTargetType.JAVASCRIPT) {
|
||||||
try (OutputStream output = new FileOutputStream(new File(targetDirectory, outputName), true)) {
|
try (OutputStream output = new FileOutputStream(new File(targetDirectory, outputName), true)) {
|
||||||
try (Writer writer = new OutputStreamWriter(output, "UTF-8")) {
|
try (Writer writer = new OutputStreamWriter(output, StandardCharsets.UTF_8)) {
|
||||||
additionalJavaScriptOutput(writer);
|
additionalJavaScriptOutput(writer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -458,10 +453,6 @@ public class TeaVMTool implements BaseTeaVMTool {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void additionalJavaScriptOutput(Writer writer) throws IOException {
|
private void additionalJavaScriptOutput(Writer writer) throws IOException {
|
||||||
if (mainClass != null) {
|
|
||||||
writer.append("main = $rt_mainStarter(main);\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (debugInformationGenerated) {
|
if (debugInformationGenerated) {
|
||||||
assert debugEmitter != null;
|
assert debugEmitter != null;
|
||||||
DebugInformation debugInfo = debugEmitter.getDebugInformation();
|
DebugInformation debugInfo = debugEmitter.getDebugInformation();
|
||||||
|
|
|
@ -60,7 +60,6 @@ import org.teavm.model.ClassHolder;
|
||||||
import org.teavm.model.ClassHolderSource;
|
import org.teavm.model.ClassHolderSource;
|
||||||
import org.teavm.model.MethodDescriptor;
|
import org.teavm.model.MethodDescriptor;
|
||||||
import org.teavm.model.MethodHolder;
|
import org.teavm.model.MethodHolder;
|
||||||
import org.teavm.model.MethodReference;
|
|
||||||
import org.teavm.model.PreOptimizingClassHolderSource;
|
import org.teavm.model.PreOptimizingClassHolderSource;
|
||||||
import org.teavm.model.ValueType;
|
import org.teavm.model.ValueType;
|
||||||
import org.teavm.parsing.ClasspathClassHolderSource;
|
import org.teavm.parsing.ClasspathClassHolderSource;
|
||||||
|
@ -432,24 +431,21 @@ public class TeaVMTestRunner extends Runner implements Filterable {
|
||||||
private CompileResult compileToJs(Method method, TeaVMTestConfiguration<JavaScriptTarget> configuration,
|
private CompileResult compileToJs(Method method, TeaVMTestConfiguration<JavaScriptTarget> configuration,
|
||||||
File path) {
|
File path) {
|
||||||
return compileTest(method, configuration, JavaScriptTarget::new, vm -> {
|
return compileTest(method, configuration, JavaScriptTarget::new, vm -> {
|
||||||
MethodReference exceptionMsg = new MethodReference(ExceptionHelper.class, "showException",
|
vm.entryPoint(TestEntryPoint.class.getName());
|
||||||
Throwable.class, String.class);
|
|
||||||
vm.entryPoint("runTest", new MethodReference(TestEntryPoint.class, "run", void.class)).async();
|
|
||||||
vm.entryPoint("extractException", exceptionMsg);
|
|
||||||
}, path, ".js");
|
}, path, ".js");
|
||||||
}
|
}
|
||||||
|
|
||||||
private CompileResult compileToC(Method method, TeaVMTestConfiguration<CTarget> configuration,
|
private CompileResult compileToC(Method method, TeaVMTestConfiguration<CTarget> configuration,
|
||||||
File path) {
|
File path) {
|
||||||
return compileTest(method, configuration, CTarget::new, vm -> {
|
return compileTest(method, configuration, CTarget::new, vm -> {
|
||||||
vm.entryPoint("main", new MethodReference(TestEntryPoint.class, "main", String[].class, void.class));
|
vm.entryPoint(TestNativeEntryPoint.class.getName());
|
||||||
}, path, ".c");
|
}, path, ".c");
|
||||||
}
|
}
|
||||||
|
|
||||||
private CompileResult compileToWasm(Method method, TeaVMTestConfiguration<WasmTarget> configuration,
|
private CompileResult compileToWasm(Method method, TeaVMTestConfiguration<WasmTarget> configuration,
|
||||||
File path) {
|
File path) {
|
||||||
return compileTest(method, configuration, WasmTarget::new, vm -> {
|
return compileTest(method, configuration, WasmTarget::new, vm -> {
|
||||||
vm.entryPoint("main", new MethodReference(TestEntryPoint.class, "main", String[].class, void.class));
|
vm.entryPoint(TestNativeEntryPoint.class.getName());
|
||||||
}, path, ".wasm");
|
}, path, ".wasm");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,13 +33,7 @@ final class TestEntryPoint {
|
||||||
|
|
||||||
private static native boolean isExpectedException(Class<?> cls);
|
private static native boolean isExpectedException(Class<?> cls);
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Throwable {
|
||||||
try {
|
run();
|
||||||
run();
|
|
||||||
System.out.println("SUCCESS");
|
|
||||||
} catch (Throwable e) {
|
|
||||||
e.printStackTrace(System.out);
|
|
||||||
System.out.println("FAILURE");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2016 Alexey Andreev.
|
* Copyright 2018 Alexey Andreev.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -15,50 +15,33 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.junit;
|
package org.teavm.junit;
|
||||||
|
|
||||||
|
import static org.teavm.junit.TestExceptionPlugin.GET_MESSAGE;
|
||||||
import org.teavm.dependency.AbstractDependencyListener;
|
import org.teavm.dependency.AbstractDependencyListener;
|
||||||
import org.teavm.dependency.DependencyAgent;
|
import org.teavm.dependency.DependencyAgent;
|
||||||
import org.teavm.dependency.DependencyNode;
|
import org.teavm.dependency.DependencyNode;
|
||||||
import org.teavm.dependency.MethodDependency;
|
import org.teavm.dependency.MethodDependency;
|
||||||
import org.teavm.model.CallLocation;
|
import org.teavm.model.CallLocation;
|
||||||
import org.teavm.model.ClassReader;
|
|
||||||
import org.teavm.model.ClassReaderSource;
|
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
|
|
||||||
class TestExceptionDependency extends AbstractDependencyListener {
|
class TestExceptionDependencyListener extends AbstractDependencyListener {
|
||||||
private MethodReference getMessageRef = new MethodReference(ExceptionHelper.class, "showException",
|
|
||||||
Throwable.class, String.class);
|
|
||||||
private DependencyNode allClasses;
|
private DependencyNode allClasses;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void started(DependencyAgent agent) {
|
public void started(DependencyAgent agent) {
|
||||||
allClasses = agent.createNode();
|
allClasses = agent.createNode();
|
||||||
|
allClasses.addConsumer(c -> {
|
||||||
|
if (agent.getClassSource().isSuperType("java.lang.Throwable", c.getName()).orElse(false)) {
|
||||||
|
MethodDependency methodDep = agent.linkMethod(new MethodReference(c.getName(), GET_MESSAGE), null);
|
||||||
|
methodDep.getVariable(0).propagate(c);
|
||||||
|
methodDep.use();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
agent.linkClass("java.lang.Throwable", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void classReached(DependencyAgent agent, String className, CallLocation location) {
|
public void classReached(DependencyAgent agent, String className, CallLocation location) {
|
||||||
if (isException(agent.getClassSource(), className)) {
|
allClasses.propagate(agent.getType(className));
|
||||||
allClasses.propagate(agent.getType(className));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isException(ClassReaderSource classSource, String className) {
|
|
||||||
while (className != null) {
|
|
||||||
if (className.equals("java.lang.Throwable")) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
ClassReader cls = classSource.get(className);
|
|
||||||
if (cls == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
className = cls.getParent();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void methodReached(DependencyAgent agent, MethodDependency method, CallLocation location) {
|
|
||||||
if (method.getReference().equals(getMessageRef)) {
|
|
||||||
allClasses.connect(method.getVariable(1));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -15,12 +15,58 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.junit;
|
package org.teavm.junit;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import org.teavm.backend.javascript.TeaVMJavaScriptHost;
|
||||||
|
import org.teavm.backend.javascript.codegen.SourceWriter;
|
||||||
|
import org.teavm.backend.javascript.rendering.RenderingManager;
|
||||||
|
import org.teavm.model.MethodDescriptor;
|
||||||
|
import org.teavm.model.ValueType;
|
||||||
|
import org.teavm.vm.BuildTarget;
|
||||||
|
import org.teavm.vm.spi.AbstractRendererListener;
|
||||||
import org.teavm.vm.spi.TeaVMHost;
|
import org.teavm.vm.spi.TeaVMHost;
|
||||||
import org.teavm.vm.spi.TeaVMPlugin;
|
import org.teavm.vm.spi.TeaVMPlugin;
|
||||||
|
|
||||||
class TestExceptionPlugin implements TeaVMPlugin {
|
class TestExceptionPlugin implements TeaVMPlugin {
|
||||||
|
static final MethodDescriptor GET_MESSAGE = new MethodDescriptor("getMessage", ValueType.parse(String.class));
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void install(TeaVMHost host) {
|
public void install(TeaVMHost host) {
|
||||||
host.add(new TestExceptionDependency());
|
host.add(new TestExceptionDependencyListener());
|
||||||
|
|
||||||
|
TeaVMJavaScriptHost jsHost = host.getExtension(TeaVMJavaScriptHost.class);
|
||||||
|
if (jsHost != null) {
|
||||||
|
install(jsHost);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void install(TeaVMJavaScriptHost host) {
|
||||||
|
host.addVirtualMethods((context, methodRef) -> {
|
||||||
|
if (!methodRef.getDescriptor().equals(GET_MESSAGE)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return context.getClassSource().isSuperType("java.lang.Throwable", methodRef.getClassName()).orElse(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
host.add(new AbstractRendererListener() {
|
||||||
|
RenderingManager manager;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void begin(RenderingManager manager, BuildTarget buildTarget) throws IOException {
|
||||||
|
this.manager = manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void complete() throws IOException {
|
||||||
|
renderExceptionMessage(manager.getWriter());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderExceptionMessage(SourceWriter writer) throws IOException {
|
||||||
|
writer.appendClass("java.lang.Throwable").append(".prototype.getMessage").ws().append("=").ws()
|
||||||
|
.append("function()").ws().append("{").indent().softNewLine();
|
||||||
|
writer.append("return $rt_ustr(this.").appendMethod("getMessage", String.class).append("());")
|
||||||
|
.softNewLine();
|
||||||
|
writer.outdent().append("};").newLine();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2018 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.junit;
|
||||||
|
|
||||||
|
final class TestNativeEntryPoint {
|
||||||
|
private TestNativeEntryPoint() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
try {
|
||||||
|
TestEntryPoint.run();
|
||||||
|
System.out.println("SUCCESS");
|
||||||
|
} catch (Throwable e) {
|
||||||
|
e.printStackTrace(System.out);
|
||||||
|
System.out.println("FAILURE");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,45 +1,22 @@
|
||||||
function main(callback) {
|
function runMain(callback) {
|
||||||
$rt_startThread(function () {
|
main([], function(result) {
|
||||||
var thread = $rt_nativeThread();
|
var message = {};
|
||||||
var instance;
|
if (result instanceof Error) {
|
||||||
var ptr = 0;
|
makeErrorMessage(message, result);
|
||||||
var message;
|
} else {
|
||||||
if (thread.isResuming()) {
|
message.status = "ok";
|
||||||
ptr = thread.pop();
|
|
||||||
instance = thread.pop();
|
|
||||||
}
|
|
||||||
loop: while (true) {
|
|
||||||
switch (ptr) {
|
|
||||||
case 0:
|
|
||||||
try {
|
|
||||||
runTest();
|
|
||||||
} catch (e) {
|
|
||||||
message = {};
|
|
||||||
makeErrorMessage(message, e);
|
|
||||||
break loop;
|
|
||||||
}
|
|
||||||
if (thread.isSuspending()) {
|
|
||||||
thread.push(instance);
|
|
||||||
thread.push(ptr);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
message = {};
|
|
||||||
message.status = "ok";
|
|
||||||
break loop;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
callback.complete(JSON.stringify(message));
|
callback.complete(JSON.stringify(message));
|
||||||
});
|
});
|
||||||
|
|
||||||
function makeErrorMessage(message, e) {
|
function makeErrorMessage(message, e) {
|
||||||
message.status = "exception";
|
message.status = "exception";
|
||||||
var stack = e.stack;
|
var stack = "";
|
||||||
if (e.$javaException && e.$javaException.constructor.$meta) {
|
if (e.$javaException && e.$javaException.constructor.$meta) {
|
||||||
message.exception = e.$javaException.constructor.$meta.name;
|
stack = e.$javaException.constructor.$meta.name + ": ";
|
||||||
message.stack = e.$javaException.constructor.$meta.name + ": ";
|
stack += e.$javaException.getMessage() || "";
|
||||||
var exceptionMessage = extractException(e.$javaException);
|
stack += "\n";
|
||||||
message.stack += exceptionMessage ? $rt_ustr(exceptionMessage) : "";
|
|
||||||
}
|
}
|
||||||
message.stack += "\n" + stack;
|
message.stack = stack + e.stack;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,52 +1,27 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>TeaVM JUnit test</title>
|
<title>TeaVM JUnit test</title>
|
||||||
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
|
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<script type="text/javascript" src="test.js"></script>
|
<script type="text/javascript" src="test.js"></script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$rt_startThread(function() {
|
main([], function(result) {
|
||||||
var thread = $rt_nativeThread();
|
var message = result instanceof Error ? buildErrorMessage(result) : "OK";
|
||||||
var instance;
|
document.body.appendChild(document.createTextNode(message))
|
||||||
var ptr = 0;
|
});
|
||||||
var message;
|
|
||||||
if (thread.isResuming()) {
|
|
||||||
ptr = thread.pop();
|
|
||||||
instance = thread.pop();
|
|
||||||
}
|
|
||||||
loop: while (true) {
|
|
||||||
switch (ptr) {
|
|
||||||
case 0:
|
|
||||||
try {
|
|
||||||
runTest();
|
|
||||||
} catch (e) {
|
|
||||||
message = buildErrorMessage(e);
|
|
||||||
break loop;
|
|
||||||
}
|
|
||||||
if (thread.isSuspending()) {
|
|
||||||
thread.push(instance);
|
|
||||||
thread.push(ptr);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
message = "OK";
|
|
||||||
break loop;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
document.body.appendChild(document.createTextNode(message));
|
|
||||||
});
|
|
||||||
|
|
||||||
function buildErrorMessage(e) {
|
function buildErrorMessage(e) {
|
||||||
var stack = e.stack;
|
var stack = "";
|
||||||
if (e.$javaException && e.$javaException.constructor.$meta) {
|
if (e.$javaException && e.$javaException.constructor.$meta) {
|
||||||
stack = e.$javaException.constructor.$meta.name + ": ";
|
stack = e.$javaException.constructor.$meta.name + ": ";
|
||||||
var exceptionMessage = extractException(e.$javaException);
|
stack += e.$javaException.getMessage() || "";
|
||||||
stack += exceptionMessage ? $rt_ustr(exceptionMessage) : "";
|
stack += "\n";
|
||||||
}
|
}
|
||||||
stack += "\n" + stack;
|
stack += e.stack;
|
||||||
return stack;
|
return stack;
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
|
@ -14,44 +14,23 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
$rt_startThread(function() {
|
main([], function(result) {
|
||||||
var thread = $rt_nativeThread();
|
var message = {};
|
||||||
var instance;
|
if (result instanceof Error) {
|
||||||
var ptr = 0;
|
makeErrorMessage(message, result);
|
||||||
var message;
|
} else {
|
||||||
if (thread.isResuming()) {
|
|
||||||
ptr = thread.pop();
|
|
||||||
instance = thread.pop();
|
|
||||||
}
|
|
||||||
loop: while (true) { switch (ptr) {
|
|
||||||
case 0:
|
|
||||||
try {
|
|
||||||
runTest();
|
|
||||||
} catch (e) {
|
|
||||||
message = {};
|
|
||||||
makeErrorMessage(message, e);
|
|
||||||
break loop;
|
|
||||||
}
|
|
||||||
if (thread.isSuspending()) {
|
|
||||||
thread.push(instance);
|
|
||||||
thread.push(ptr);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
message = {};
|
|
||||||
message.status = "ok";
|
message.status = "ok";
|
||||||
break loop;
|
}
|
||||||
}}
|
|
||||||
window.parent.postMessage(JSON.stringify(message), "*");
|
window.parent.postMessage(JSON.stringify(message), "*");
|
||||||
});
|
});
|
||||||
|
|
||||||
function makeErrorMessage(message, e) {
|
function makeErrorMessage(message, e) {
|
||||||
message.status = "exception";
|
message.status = "exception";
|
||||||
var stack = e.stack;
|
var stack = "";
|
||||||
if (e.$javaException && e.$javaException.constructor.$meta) {
|
if (e.$javaException && e.$javaException.constructor.$meta) {
|
||||||
message.exception = e.$javaException.constructor.$meta.name;
|
stack = e.$javaException.constructor.$meta.name + ": ";
|
||||||
message.stack = e.$javaException.constructor.$meta.name + ": ";
|
stack += e.$javaException.getMessage() || "";
|
||||||
var exceptionMessage = extractException(e.$javaException);
|
stack += "\n";
|
||||||
message.stack += exceptionMessage ? $rt_ustr(exceptionMessage) : "";
|
|
||||||
}
|
}
|
||||||
message.stack += "\n" + stack;
|
message.stack = stack + e.stack;
|
||||||
};
|
}
|
Loading…
Reference in New Issue
Block a user