mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -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) {
|
||||
TeaVMEntryPoint entryPoint = controller.getEntryPoints().get("main");
|
||||
if (entryPoint != null) {
|
||||
String mainMethod = context.getNames().forMethod(entryPoint.getReference());
|
||||
String mainMethod = context.getNames().forMethod(entryPoint.getMethod());
|
||||
writer.println(mainMethod + "(NULL);");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -235,6 +235,10 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
|
|||
MethodDependency exceptionCons = dependencyAnalyzer.linkMethod(new MethodReference(
|
||||
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(1).propagate(dependencyAnalyzer.getType("java.lang.String"));
|
||||
exceptionCons = dependencyAnalyzer.linkMethod(new MethodReference(NoSuchFieldError.class, "<init>",
|
||||
|
@ -315,26 +319,34 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
|
|||
renderingContext.addInjector(entry.getKey(), entry.getValue());
|
||||
}
|
||||
try {
|
||||
printWrapperStart(sourceWriter);
|
||||
|
||||
for (RendererListener listener : rendererListeners) {
|
||||
listener.begin(renderer, target);
|
||||
}
|
||||
int start = sourceWriter.getOffset();
|
||||
sourceWriter.append("\"use strict\";").newLine();
|
||||
|
||||
renderer.prepare(clsNodes);
|
||||
runtimeRenderer.renderRuntime();
|
||||
renderer.render(clsNodes);
|
||||
renderer.renderStringPool();
|
||||
renderer.renderStringConstants();
|
||||
renderer.renderCompatibilityStubs();
|
||||
|
||||
for (Map.Entry<? extends String, ? extends TeaVMEntryPoint> entry
|
||||
: controller.getEntryPoints().entrySet()) {
|
||||
sourceWriter.append("var ").append(entry.getKey()).ws().append("=").ws();
|
||||
MethodReference ref = entry.getValue().getReference();
|
||||
sourceWriter.append(naming.getFullNameFor(ref));
|
||||
sourceWriter.append(";").newLine();
|
||||
sourceWriter.append("").append(entry.getKey()).ws().append("=").ws();
|
||||
MethodReference ref = entry.getValue().getMethod();
|
||||
sourceWriter.append("$rt_mainStarter(").append(naming.getFullNameFor(ref));
|
||||
sourceWriter.append(");").newLine();
|
||||
}
|
||||
|
||||
for (RendererListener listener : rendererListeners) {
|
||||
listener.complete();
|
||||
}
|
||||
|
||||
printWrapperEnd(sourceWriter);
|
||||
|
||||
int totalSize = sourceWriter.getOffset() - start;
|
||||
printStats(renderer, totalSize);
|
||||
} 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) {
|
||||
if (!Boolean.parseBoolean(System.getProperty("teavm.js.stats", "false"))) {
|
||||
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) {
|
||||
sizeByClass.put(className, sizeByClass.getOrDefault(className, 0) + sz);
|
||||
}
|
||||
|
|
|
@ -397,7 +397,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
|||
module.setStartFunction(initFunction);
|
||||
|
||||
for (TeaVMEntryPoint entryPoint : controller.getEntryPoints().values()) {
|
||||
String mangledName = names.forMethod(entryPoint.getReference());
|
||||
String mangledName = names.forMethod(entryPoint.getMethod());
|
||||
WasmFunction function = module.getFunctions().get(mangledName);
|
||||
if (function != null) {
|
||||
function.setExportName(entryPoint.getPublicName());
|
||||
|
|
|
@ -645,7 +645,6 @@ public class DebugInformation {
|
|||
int[] methods;
|
||||
}
|
||||
|
||||
|
||||
class MethodTree {
|
||||
int[] data;
|
||||
int[] offsets;
|
||||
|
|
|
@ -23,6 +23,7 @@ import java.util.Collection;
|
|||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
@ -37,6 +38,7 @@ import org.teavm.dependency.DependencyInfo;
|
|||
import org.teavm.dependency.DependencyListener;
|
||||
import org.teavm.dependency.DependencyPlugin;
|
||||
import org.teavm.dependency.Linker;
|
||||
import org.teavm.dependency.MethodDependency;
|
||||
import org.teavm.diagnostics.AccumulationDiagnostics;
|
||||
import org.teavm.diagnostics.Diagnostics;
|
||||
import org.teavm.diagnostics.ProblemProvider;
|
||||
|
@ -47,12 +49,14 @@ import org.teavm.model.ClassReader;
|
|||
import org.teavm.model.ClassReaderSource;
|
||||
import org.teavm.model.ListableClassHolderSource;
|
||||
import org.teavm.model.ListableClassReaderSource;
|
||||
import org.teavm.model.MethodDescriptor;
|
||||
import org.teavm.model.MethodHolder;
|
||||
import org.teavm.model.MethodReader;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.MutableClassHolderSource;
|
||||
import org.teavm.model.Program;
|
||||
import org.teavm.model.ProgramCache;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.model.optimization.ArrayUnwrapMotion;
|
||||
import org.teavm.model.optimization.ClassInitElimination;
|
||||
import org.teavm.model.optimization.ConstantConditionElimination;
|
||||
|
@ -106,11 +110,14 @@ import org.teavm.vm.spi.TeaVMPlugin;
|
|||
* @author Alexey Andreev
|
||||
*/
|
||||
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 DependencyAnalyzer dependencyAnalyzer;
|
||||
private final AccumulationDiagnostics diagnostics = new AccumulationDiagnostics();
|
||||
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 Set<String> preservedClasses = new HashSet<>();
|
||||
private final Set<String> readonlyPreservedClasses = Collections.unmodifiableSet(preservedClasses);
|
||||
|
@ -243,58 +250,38 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
|||
return target.getPlatformTags();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Adds an entry point. TeaVM guarantees, that all methods that are required by the entry point
|
||||
* 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 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);
|
||||
}
|
||||
public void entryPoint(String className, String name) {
|
||||
if (entryPoints.containsKey(name)) {
|
||||
throw new IllegalArgumentException("Entry point with public name `" + name + "' already defined "
|
||||
+ "for class " + className);
|
||||
}
|
||||
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.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);
|
||||
}
|
||||
return entryPoint;
|
||||
entryPoints.put(name, entryPoint);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Adds an entry point. TeaVM guarantees, that all methods that are required by the entry point
|
||||
* 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 entryPoint(String className) {
|
||||
entryPoint(className, "main");
|
||||
}
|
||||
|
||||
public void preserveType(String className) {
|
||||
|
|
|
@ -15,102 +15,23 @@
|
|||
*/
|
||||
package org.teavm.vm;
|
||||
|
||||
import java.util.HashMap;
|
||||
import org.teavm.dependency.MethodDependency;
|
||||
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 {
|
||||
private String publicName;
|
||||
MethodReference reference;
|
||||
private MethodDependency method;
|
||||
private boolean async;
|
||||
String publicName;
|
||||
MethodDependency methodDep;
|
||||
|
||||
TeaVMEntryPoint(String publicName, MethodReference reference, MethodDependency method) {
|
||||
TeaVMEntryPoint(String publicName, MethodDependency methodDep) {
|
||||
this.publicName = publicName;
|
||||
this.reference = reference;
|
||||
this.method = method;
|
||||
method.use();
|
||||
}
|
||||
|
||||
public MethodReference getReference() {
|
||||
return reference;
|
||||
this.methodDep = methodDep;
|
||||
}
|
||||
|
||||
public String getPublicName() {
|
||||
return publicName;
|
||||
}
|
||||
|
||||
boolean isAsync() {
|
||||
return async;
|
||||
}
|
||||
|
||||
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;
|
||||
public MethodReference getMethod() {
|
||||
return methodDep.getReference();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -241,11 +241,6 @@ function $rt_voidcls() {
|
|||
}
|
||||
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) {
|
||||
throw $rt_exception(ex);
|
||||
}
|
||||
|
@ -406,7 +401,7 @@ function $rt_assertNotNaN(value) {
|
|||
return value;
|
||||
}
|
||||
var $rt_stdoutBuffer = "";
|
||||
function $rt_putStdout(ch) {
|
||||
var $rt_putStdout = typeof $rt_putStdoutCustom === "function" ? $rt_putStdoutCustom : function(ch) {
|
||||
if (ch === 0xA) {
|
||||
if (console) {
|
||||
console.info($rt_stdoutBuffer);
|
||||
|
@ -415,9 +410,9 @@ function $rt_putStdout(ch) {
|
|||
} else {
|
||||
$rt_stdoutBuffer += String.fromCharCode(ch);
|
||||
}
|
||||
}
|
||||
};
|
||||
var $rt_stderrBuffer = "";
|
||||
function $rt_putStderr(ch) {
|
||||
var $rt_putStderr = typeof $rt_putStderrCustom === "function" ? $rt_putStderrCustom : function(ch) {
|
||||
if (ch === 0xA) {
|
||||
if (console) {
|
||||
console.info($rt_stderrBuffer);
|
||||
|
@ -426,7 +421,7 @@ function $rt_putStderr(ch) {
|
|||
} else {
|
||||
$rt_stderrBuffer += String.fromCharCode(ch);
|
||||
}
|
||||
}
|
||||
};
|
||||
function $rt_metadata(data) {
|
||||
var i = 0;
|
||||
var packageCount = data[i++];
|
||||
|
@ -500,7 +495,7 @@ function $rt_threadStarter(f) {
|
|||
}
|
||||
}
|
||||
function $rt_mainStarter(f) {
|
||||
return function(args) {
|
||||
return function(args, callback) {
|
||||
if (!args) {
|
||||
args = [];
|
||||
}
|
||||
|
@ -508,8 +503,8 @@ function $rt_mainStarter(f) {
|
|||
for (var i = 0; i < args.length; ++i) {
|
||||
javaArgs.data[i] = $rt_str(args[i]);
|
||||
}
|
||||
$rt_threadStarter(f)(javaArgs);
|
||||
};
|
||||
$rt_startThread(function() { f.call(null, javaArgs); }, callback);
|
||||
}
|
||||
}
|
||||
var $rt_stringPool_instance;
|
||||
function $rt_stringPool(strings) {
|
||||
|
@ -617,14 +612,7 @@ function $rt_nativeThread() {
|
|||
function $rt_invalidPointer() {
|
||||
throw new Error("Invalid recorded state");
|
||||
}
|
||||
|
||||
function $dbg_repr(obj) {
|
||||
return obj.toString ? obj.toString() : "";
|
||||
}
|
||||
function $dbg_class(obj) {
|
||||
if (obj instanceof Long) {
|
||||
return "long";
|
||||
}
|
||||
var cls = obj.constructor;
|
||||
var arrayDegree = 0;
|
||||
while (cls.$meta && cls.$meta.item) {
|
||||
|
@ -649,7 +637,7 @@ function $dbg_class(obj) {
|
|||
} else if (cls === $rt_doublecls()) {
|
||||
clsName = "double";
|
||||
} else {
|
||||
clsName = cls.$meta ? cls.$meta.name : "@" + cls.name;
|
||||
clsName = cls.$meta ? (cls.$meta.name || ("a/" + cls.name)) : "@" + cls.name;
|
||||
}
|
||||
while (arrayDegree-- > 0) {
|
||||
clsName += "[]";
|
||||
|
@ -661,6 +649,9 @@ function Long(lo, hi) {
|
|||
this.lo = lo | 0;
|
||||
this.hi = hi | 0;
|
||||
}
|
||||
Long.prototype.__teavm_class__ = function() {
|
||||
return "long";
|
||||
};
|
||||
Long.prototype.toString = function() {
|
||||
var result = [];
|
||||
var n = this;
|
||||
|
@ -677,6 +668,9 @@ Long.prototype.toString = function() {
|
|||
result = result.reverse().join('');
|
||||
return positive ? result : "-" + result;
|
||||
};
|
||||
Long.prototype.valueOf = function() {
|
||||
return Long_toNumber(this);
|
||||
};
|
||||
var Long_ZERO = new Long(0, 0);
|
||||
var Long_MAX_NORMAL = 1 << 18;
|
||||
function Long_fromInt(val) {
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
<head>
|
||||
<title>Continuation-passing style demo</title>
|
||||
<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/classes.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="syntax.css">
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
function $rt_putStdout(ch) {
|
||||
if (ch == 0xA) {
|
||||
var $rt_stdoutBuffer = "";
|
||||
function $rt_putStdoutCustom(ch) {
|
||||
if (ch === 0xA) {
|
||||
var lineElem = document.createElement("div");
|
||||
var stdoutElem = document.getElementById("stdout");
|
||||
lineElem.appendChild(document.createTextNode($rt_stdoutBuffer));
|
||||
|
|
|
@ -21,7 +21,6 @@ import org.apache.commons.io.output.ByteArrayOutputStream;
|
|||
import org.junit.Test;
|
||||
import org.teavm.backend.javascript.JavaScriptTarget;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.tooling.TeaVMProblemRenderer;
|
||||
import org.teavm.tooling.TeaVMToolLog;
|
||||
import org.teavm.vm.TeaVM;
|
||||
|
@ -76,8 +75,9 @@ public class ClassValueTest {
|
|||
|
||||
private DependencyInfo runTest(String methodName) {
|
||||
TeaVM vm = new TeaVMBuilder(new JavaScriptTarget()).build();
|
||||
vm.add(new DependencyTestPatcher(getClass().getName(), methodName));
|
||||
vm.installPlugins();
|
||||
vm.entryPoint(new MethodReference(getClass().getName(), methodName, ValueType.VOID));
|
||||
vm.entryPoint(getClass().getName());
|
||||
vm.build(fileName -> new ByteArrayOutputStream(), "tmp");
|
||||
if (!vm.getProblemProvider().getSevereProblems().isEmpty()) {
|
||||
fail("Code compiled with errors:\n" + describeProblems(vm));
|
||||
|
|
|
@ -123,11 +123,12 @@ public class DependencyTest {
|
|||
return TeaVMProgressFeedback.CONTINUE;
|
||||
}
|
||||
});
|
||||
vm.add(new DependencyTestPatcher(DependencyTestData.class.getName(), testName.getMethodName()));
|
||||
vm.installPlugins();
|
||||
|
||||
MethodReference testMethod = new MethodReference(DependencyTestData.class,
|
||||
testName.getMethodName(), void.class);
|
||||
vm.entryPoint(testMethod).withValue(0, DependencyTestData.class.getName());
|
||||
vm.entryPoint(DependencyTestData.class.getName());
|
||||
vm.build(fileName -> new ByteArrayOutputStream(), "out");
|
||||
|
||||
List<Problem> problems = vm.getProblemProvider().getSevereProblems();
|
||||
|
|
|
@ -16,15 +16,18 @@
|
|||
package org.teavm.dependency;
|
||||
|
||||
public class DependencyTestData {
|
||||
public void virtualCall() {
|
||||
private DependencyTestData() {
|
||||
}
|
||||
|
||||
public static void virtualCall() {
|
||||
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);
|
||||
}
|
||||
|
||||
public void catchException() throws Exception {
|
||||
public static void catchException() throws Exception {
|
||||
try {
|
||||
throw createException(0);
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
|
@ -34,7 +37,7 @@ public class DependencyTestData {
|
|||
}
|
||||
}
|
||||
|
||||
public void propagateException() {
|
||||
public static void propagateException() {
|
||||
try {
|
||||
catchException();
|
||||
} 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 };
|
||||
MetaAssertions.assertTypes(array[0], String.class, Integer.class, Class.class);
|
||||
}
|
||||
|
||||
public void arraysPassed() {
|
||||
public static void arraysPassed() {
|
||||
Object[] array = new Object[3];
|
||||
fillArray(array);
|
||||
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);
|
||||
}
|
||||
|
||||
public void arraysRetrieved() {
|
||||
public static void arraysRetrieved() {
|
||||
Object[] array = createArray();
|
||||
MetaAssertions.assertTypes(array[0], String.class, Integer.class, Class.class);
|
||||
|
||||
|
@ -70,24 +73,24 @@ public class DependencyTestData {
|
|||
|
||||
static Object[] staticArrayField;
|
||||
|
||||
private Object[] createArray() {
|
||||
private static Object[] createArray() {
|
||||
Object[] array = new Object[3];
|
||||
fillArray(array);
|
||||
return array;
|
||||
}
|
||||
|
||||
private void fillArray(Object[] array) {
|
||||
private static void fillArray(Object[] array) {
|
||||
array[0] = "123";
|
||||
array[1] = 123;
|
||||
array[2] = String.class;
|
||||
}
|
||||
|
||||
private void fillStaticArray() {
|
||||
private static void fillStaticArray() {
|
||||
staticArrayField[0] = 42L;
|
||||
staticArrayField[0] = new RuntimeException();
|
||||
}
|
||||
|
||||
private I getI(int index) {
|
||||
private static I getI(int index) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
return new A();
|
||||
|
@ -98,7 +101,7 @@ public class DependencyTestData {
|
|||
}
|
||||
}
|
||||
|
||||
private Exception createException(int index) {
|
||||
private static Exception createException(int index) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
throw new IndexOutOfBoundsException();
|
||||
|
@ -115,21 +118,21 @@ public class DependencyTestData {
|
|||
Object foo();
|
||||
}
|
||||
|
||||
class A implements I {
|
||||
static class A implements I {
|
||||
@Override
|
||||
public Object foo() {
|
||||
return "123";
|
||||
}
|
||||
}
|
||||
|
||||
class B implements I {
|
||||
static class B implements I {
|
||||
@Override
|
||||
public Object foo() {
|
||||
return Object.class;
|
||||
}
|
||||
}
|
||||
|
||||
class C implements I {
|
||||
static class C implements I {
|
||||
@Override
|
||||
public Object foo() {
|
||||
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 org.junit.Test;
|
||||
import org.teavm.backend.javascript.JavaScriptTarget;
|
||||
import org.teavm.dependency.DependencyTestPatcher;
|
||||
import org.teavm.diagnostics.Problem;
|
||||
import org.teavm.jso.JSBody;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
@ -94,8 +95,9 @@ public class JSOTest {
|
|||
|
||||
private List<Problem> build(String methodName) {
|
||||
TeaVM vm = new TeaVMBuilder(new JavaScriptTarget()).build();
|
||||
vm.add(new DependencyTestPatcher(JSOTest.class.getName(), methodName));
|
||||
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");
|
||||
return vm.getProblemProvider().getSevereProblems();
|
||||
}
|
||||
|
|
|
@ -58,38 +58,25 @@ function appendFiles(files, index, callback, errorCallback) {
|
|||
}
|
||||
|
||||
function launchTest(callback) {
|
||||
$rt_startThread(() => {
|
||||
let thread = $rt_nativeThread();
|
||||
let instance;
|
||||
let message;
|
||||
if (thread.isResuming()) {
|
||||
instance = thread.pop();
|
||||
}
|
||||
try {
|
||||
runTest();
|
||||
} catch (e) {
|
||||
message = buildErrorMessage(e);
|
||||
main([], result => {
|
||||
if (result instanceof Error) {
|
||||
callback({
|
||||
status: "failed",
|
||||
errorMessage: buildErrorMessage(e)
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (thread.isSuspending()) {
|
||||
thread.push(instance);
|
||||
} else {
|
||||
callback({ status: "OK" });
|
||||
}
|
||||
});
|
||||
|
||||
function buildErrorMessage(e) {
|
||||
let stack = e.stack;
|
||||
let stack = "";
|
||||
if (e.$javaException && e.$javaException.constructor.$meta) {
|
||||
stack = e.$javaException.constructor.$meta.name + ": ";
|
||||
let exceptionMessage = extractException(e.$javaException);
|
||||
stack += exceptionMessage ? $rt_ustr(exceptionMessage) : "";
|
||||
stack += e.$javaException.getMessage();
|
||||
stack += "\n";
|
||||
}
|
||||
stack += "\n" + stack;
|
||||
stack += e.stack;
|
||||
return stack;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,10 +43,13 @@ import org.teavm.chromerdp.data.Response;
|
|||
import org.teavm.chromerdp.data.ScopeDTO;
|
||||
import org.teavm.chromerdp.messages.CallFunctionCommand;
|
||||
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.GetPropertiesCommand;
|
||||
import org.teavm.chromerdp.messages.GetPropertiesResponse;
|
||||
import org.teavm.chromerdp.messages.RemoveBreakpointCommand;
|
||||
import org.teavm.chromerdp.messages.RunScriptCommand;
|
||||
import org.teavm.chromerdp.messages.ScriptParsedNotification;
|
||||
import org.teavm.chromerdp.messages.SetBreakpointCommand;
|
||||
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 void receiveMessage(final String messageText) {
|
||||
private void receiveMessage(String messageText) {
|
||||
new Thread(() -> {
|
||||
try {
|
||||
JsonNode jsonMessage = mapper.readTree(messageText);
|
||||
|
@ -188,9 +208,9 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC
|
|||
for (JavaScriptDebuggerListener listener : getListeners()) {
|
||||
listener.scriptAdded(params.getUrl());
|
||||
}
|
||||
injectFunctions(params.getExecutionContextId());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void addListener(JavaScriptDebuggerListener listener) {
|
||||
listeners.put(listener, dummy);
|
||||
|
@ -203,65 +223,34 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC
|
|||
|
||||
@Override
|
||||
public void suspend() {
|
||||
if (exchange == null) {
|
||||
return;
|
||||
}
|
||||
Message message = new Message();
|
||||
message.setMethod("Debugger.pause");
|
||||
sendMessage(message);
|
||||
callMethod("Debugger.pause", void.class, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resume() {
|
||||
if (exchange == null) {
|
||||
return;
|
||||
}
|
||||
Message message = new Message();
|
||||
message.setMethod("Debugger.resume");
|
||||
sendMessage(message);
|
||||
callMethod("Debugger.resume", void.class, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stepInto() {
|
||||
if (exchange == null) {
|
||||
return;
|
||||
}
|
||||
Message message = new Message();
|
||||
message.setMethod("Debugger.stepInto");
|
||||
sendMessage(message);
|
||||
callMethod("Debugger.stepInto", void.class, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stepOut() {
|
||||
if (exchange == null) {
|
||||
return;
|
||||
}
|
||||
Message message = new Message();
|
||||
message.setMethod("Debugger.stepOut");
|
||||
sendMessage(message);
|
||||
callMethod("Debugger.stepOut", void.class, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stepOver() {
|
||||
if (exchange == null) {
|
||||
return;
|
||||
}
|
||||
Message message = new Message();
|
||||
message.setMethod("Debugger.stepOver");
|
||||
sendMessage(message);
|
||||
callMethod("Debugger.stepOver", void.class, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void continueToLocation(JavaScriptLocation location) {
|
||||
if (exchange == null) {
|
||||
return;
|
||||
}
|
||||
Message message = new Message();
|
||||
message.setMethod("Debugger.continueToLocation");
|
||||
ContinueToLocationCommand params = new ContinueToLocationCommand();
|
||||
params.setLocation(unmap(location));
|
||||
message.setParams(mapper.valueToTree(params));
|
||||
sendMessage(message);
|
||||
callMethod("Debugger.continueToLocation", void.class, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -341,12 +330,9 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC
|
|||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Removing breakpoint at {}", breakpoint.getLocation());
|
||||
}
|
||||
Message message = new Message();
|
||||
message.setMethod("Debugger.removeBreakpoint");
|
||||
RemoveBreakpointCommand params = new RemoveBreakpointCommand();
|
||||
params.setBreakpointId(breakpoint.chromeId);
|
||||
message.setParams(mapper.valueToTree(params));
|
||||
sendMessage(message);
|
||||
callMethod("Debugger.removeBreakpoint", void.class, params);
|
||||
}
|
||||
breakpoint.debugger = null;
|
||||
breakpoint.chromeId = null;
|
||||
|
@ -356,152 +342,79 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC
|
|||
}
|
||||
|
||||
private void updateBreakpoint(final RDPBreakpoint breakpoint) {
|
||||
if (exchange == null || breakpoint.chromeId != null) {
|
||||
if (breakpoint.chromeId != null) {
|
||||
return;
|
||||
}
|
||||
final Message message = new Message();
|
||||
message.setId(messageIdGenerator.incrementAndGet());
|
||||
message.setMethod("Debugger.setBreakpoint");
|
||||
SetBreakpointCommand params = new SetBreakpointCommand();
|
||||
params.setLocation(unmap(breakpoint.getLocation()));
|
||||
message.setParams(mapper.valueToTree(params));
|
||||
|
||||
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) {
|
||||
breakpointsByChromeId.remove(breakpoint.chromeId);
|
||||
}
|
||||
if (node != null) {
|
||||
SetBreakpointResponse response = mapper.reader(SetBreakpointResponse.class).readValue(node);
|
||||
|
||||
breakpoint.updating.set(true);
|
||||
try {
|
||||
SetBreakpointResponse response = callMethod("Debugger.setBreakpoint", SetBreakpointResponse.class, params);
|
||||
if (response == null) {
|
||||
breakpoint.chromeId = response.getBreakpointId();
|
||||
if (breakpoint.chromeId != null) {
|
||||
breakpointsByChromeId.put(breakpoint.chromeId, breakpoint);
|
||||
}
|
||||
} else {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Error setting breakpoint at {}, message id is {}",
|
||||
breakpoint.getLocation(), message.getId());
|
||||
logger.warn("Error setting breakpoint at {}", breakpoint.getLocation());
|
||||
}
|
||||
breakpoint.chromeId = null;
|
||||
}
|
||||
} finally {
|
||||
synchronized (breakpoint.updateMonitor) {
|
||||
breakpoint.updating.set(false);
|
||||
breakpoint.updateMonitor.notifyAll();
|
||||
}
|
||||
for (JavaScriptDebuggerListener listener : getListeners()) {
|
||||
listener.breakpointChanged(breakpoint);
|
||||
}
|
||||
});
|
||||
breakpoint.updating.set(true);
|
||||
sendMessage(message);
|
||||
}
|
||||
|
||||
for (JavaScriptDebuggerListener listener : getListeners()) {
|
||||
listener.breakpointChanged(breakpoint);
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
params.setObjectId(scopeId);
|
||||
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 {
|
||||
return read(sync);
|
||||
} catch (InterruptedException | TimeoutException e) {
|
||||
GetPropertiesResponse response = callMethod("Runtime.getProperties", GetPropertiesResponse.class, params);
|
||||
if (response == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return parseProperties(response.getResult());
|
||||
}
|
||||
|
||||
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();
|
||||
CallArgumentDTO arg = new CallArgumentDTO();
|
||||
arg.setObjectId(objectId);
|
||||
params.setObjectId(objectId);
|
||||
params.setArguments(new CallArgumentDTO[] { arg });
|
||||
params.setFunctionDeclaration("$dbg_class");
|
||||
message.setParams(mapper.valueToTree(params));
|
||||
|
||||
CompletableFuture<String> sync = setResponseHandler(message.getId(), (node, out) -> {
|
||||
if (node == null) {
|
||||
out.complete("");
|
||||
} 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>";
|
||||
}
|
||||
CallFunctionResponse response = callMethod("Runtime.callFunctionOn", CallFunctionResponse.class, params);
|
||||
RemoteObjectDTO result = response != null ? response.getResult() : null;
|
||||
return result.getValue() != null ? result.getValue().getTextValue() : null;
|
||||
}
|
||||
|
||||
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();
|
||||
CallArgumentDTO arg = new CallArgumentDTO();
|
||||
arg.setObjectId(objectId);
|
||||
params.setObjectId(objectId);
|
||||
params.setArguments(new CallArgumentDTO[] { arg });
|
||||
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 {
|
||||
String repr;
|
||||
|
||||
RepresentationWrapper(String repr) {
|
||||
super();
|
||||
this.repr = repr;
|
||||
}
|
||||
CallFunctionResponse response = callMethod("Runtime.callFunctionOn", CallFunctionResponse.class, params);
|
||||
RemoteObjectDTO result = response != null ? response.getResult() : null;
|
||||
return result.getValue() != null ? result.getValue().getTextValue() : null;
|
||||
}
|
||||
|
||||
private List<RDPLocalVariable> parseProperties(PropertyDescriptorDTO[] properties) {
|
||||
|
@ -585,6 +498,36 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC
|
|||
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")
|
||||
private <T> CompletableFuture<T> setResponseHandler(int messageId, ResponseHandler<T> handler) {
|
||||
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.JavaScriptLocation;
|
||||
|
||||
public class RDPBreakpoint implements JavaScriptBreakpoint {
|
||||
class RDPBreakpoint implements JavaScriptBreakpoint {
|
||||
volatile String chromeId;
|
||||
ChromeRDPDebugger debugger;
|
||||
private JavaScriptLocation location;
|
||||
|
|
|
@ -19,7 +19,7 @@ import java.util.Collections;
|
|||
import java.util.Map;
|
||||
import org.teavm.debugging.javascript.*;
|
||||
|
||||
public class RDPCallFrame implements JavaScriptCallFrame {
|
||||
class RDPCallFrame implements JavaScriptCallFrame {
|
||||
private JavaScriptDebugger debugger;
|
||||
private String chromeId;
|
||||
private JavaScriptLocation location;
|
||||
|
@ -27,7 +27,7 @@ public class RDPCallFrame implements JavaScriptCallFrame {
|
|||
private JavaScriptValue thisObject;
|
||||
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,
|
||||
JavaScriptValue closure) {
|
||||
this.debugger = debugger;
|
||||
|
|
|
@ -18,11 +18,11 @@ package org.teavm.chromerdp;
|
|||
import org.teavm.debugging.javascript.JavaScriptValue;
|
||||
import org.teavm.debugging.javascript.JavaScriptVariable;
|
||||
|
||||
public class RDPLocalVariable implements JavaScriptVariable {
|
||||
class RDPLocalVariable implements JavaScriptVariable {
|
||||
private String name;
|
||||
private RDPValue value;
|
||||
|
||||
public RDPLocalVariable(String name, RDPValue value) {
|
||||
RDPLocalVariable(String name, RDPValue value) {
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
}
|
||||
|
|
|
@ -21,12 +21,12 @@ import java.util.Map;
|
|||
import java.util.Set;
|
||||
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 ChromeRDPDebugger debugger;
|
||||
private String id;
|
||||
|
||||
public RDPScope(ChromeRDPDebugger debugger, String id) {
|
||||
RDPScope(ChromeRDPDebugger debugger, String id) {
|
||||
this.debugger = debugger;
|
||||
this.id = id;
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ import java.util.concurrent.atomic.AtomicReference;
|
|||
import org.teavm.debugging.javascript.JavaScriptValue;
|
||||
import org.teavm.debugging.javascript.JavaScriptVariable;
|
||||
|
||||
public class RDPValue implements JavaScriptValue {
|
||||
class RDPValue implements JavaScriptValue {
|
||||
private AtomicReference<String> representation = new AtomicReference<>();
|
||||
private AtomicReference<String> className = new AtomicReference<>();
|
||||
private String typeName;
|
||||
|
@ -30,15 +30,14 @@ public class RDPValue implements JavaScriptValue {
|
|||
private Map<String, ? extends JavaScriptVariable> properties;
|
||||
private boolean innerStructure;
|
||||
|
||||
public RDPValue(ChromeRDPDebugger debugger, String representation, String typeName, String objectId,
|
||||
RDPValue(ChromeRDPDebugger debugger, String representation, String typeName, String objectId,
|
||||
boolean innerStructure) {
|
||||
this.representation.set(representation == null && objectId == null ? "" : representation);
|
||||
this.typeName = typeName;
|
||||
this.debugger = debugger;
|
||||
this.objectId = objectId;
|
||||
this.innerStructure = innerStructure;
|
||||
properties = objectId != null ? new RDPScope(debugger, objectId)
|
||||
: Collections.<String, RDPLocalVariable>emptyMap();
|
||||
properties = objectId != null ? new RDPScope(debugger, objectId) : Collections.emptyMap();
|
||||
}
|
||||
|
||||
@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");
|
||||
* 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
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.teavm.junit;
|
||||
package org.teavm.chromerdp.messages;
|
||||
|
||||
final class ExceptionHelper {
|
||||
private ExceptionHelper() {
|
||||
}
|
||||
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
|
||||
|
||||
public static String showException(Throwable e) {
|
||||
return e.getMessage();
|
||||
}
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class RunScriptCommand {
|
||||
public String scriptId;
|
||||
}
|
|
@ -21,6 +21,7 @@ import org.codehaus.jackson.annotate.JsonIgnoreProperties;
|
|||
public class ScriptParsedNotification {
|
||||
private String scriptId;
|
||||
private String url;
|
||||
private int executionContextId;
|
||||
|
||||
public String getScriptId() {
|
||||
return scriptId;
|
||||
|
@ -37,4 +38,12 @@ public class ScriptParsedNotification {
|
|||
public void setUrl(String 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.ClassReader;
|
||||
import org.teavm.model.ClassReaderSource;
|
||||
import org.teavm.model.MethodDescriptor;
|
||||
import org.teavm.model.MethodReader;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.PreOptimizingClassHolderSource;
|
||||
|
@ -382,11 +381,7 @@ public class TeaVMTool implements BaseTeaVMTool {
|
|||
vm.add(transformer);
|
||||
}
|
||||
if (mainClass != null) {
|
||||
MethodDescriptor mainMethodDesc = new MethodDescriptor("main", String[].class, void.class);
|
||||
vm.entryPoint("main", new MethodReference(mainClass, mainMethodDesc))
|
||||
.withValue(1, "[java.lang.String")
|
||||
.withArrayValue(1, "java.lang.String")
|
||||
.async();
|
||||
vm.entryPoint(mainClass);
|
||||
}
|
||||
for (String className : classesToPreserve) {
|
||||
vm.preserveType(className);
|
||||
|
@ -418,7 +413,7 @@ public class TeaVMTool implements BaseTeaVMTool {
|
|||
|
||||
if (targetType == TeaVMTargetType.JAVASCRIPT) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -458,10 +453,6 @@ public class TeaVMTool implements BaseTeaVMTool {
|
|||
}
|
||||
|
||||
private void additionalJavaScriptOutput(Writer writer) throws IOException {
|
||||
if (mainClass != null) {
|
||||
writer.append("main = $rt_mainStarter(main);\n");
|
||||
}
|
||||
|
||||
if (debugInformationGenerated) {
|
||||
assert debugEmitter != null;
|
||||
DebugInformation debugInfo = debugEmitter.getDebugInformation();
|
||||
|
|
|
@ -60,7 +60,6 @@ import org.teavm.model.ClassHolder;
|
|||
import org.teavm.model.ClassHolderSource;
|
||||
import org.teavm.model.MethodDescriptor;
|
||||
import org.teavm.model.MethodHolder;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.PreOptimizingClassHolderSource;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.parsing.ClasspathClassHolderSource;
|
||||
|
@ -432,24 +431,21 @@ public class TeaVMTestRunner extends Runner implements Filterable {
|
|||
private CompileResult compileToJs(Method method, TeaVMTestConfiguration<JavaScriptTarget> configuration,
|
||||
File path) {
|
||||
return compileTest(method, configuration, JavaScriptTarget::new, vm -> {
|
||||
MethodReference exceptionMsg = new MethodReference(ExceptionHelper.class, "showException",
|
||||
Throwable.class, String.class);
|
||||
vm.entryPoint("runTest", new MethodReference(TestEntryPoint.class, "run", void.class)).async();
|
||||
vm.entryPoint("extractException", exceptionMsg);
|
||||
vm.entryPoint(TestEntryPoint.class.getName());
|
||||
}, path, ".js");
|
||||
}
|
||||
|
||||
private CompileResult compileToC(Method method, TeaVMTestConfiguration<CTarget> configuration,
|
||||
File path) {
|
||||
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");
|
||||
}
|
||||
|
||||
private CompileResult compileToWasm(Method method, TeaVMTestConfiguration<WasmTarget> configuration,
|
||||
File path) {
|
||||
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");
|
||||
}
|
||||
|
||||
|
|
|
@ -33,13 +33,7 @@ final class TestEntryPoint {
|
|||
|
||||
private static native boolean isExpectedException(Class<?> cls);
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
try {
|
||||
run();
|
||||
System.out.println("SUCCESS");
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace(System.out);
|
||||
System.out.println("FAILURE");
|
||||
}
|
||||
public static void main(String[] args) throws Throwable {
|
||||
run();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2016 Alexey Andreev.
|
||||
* 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.
|
||||
|
@ -15,50 +15,33 @@
|
|||
*/
|
||||
package org.teavm.junit;
|
||||
|
||||
import static org.teavm.junit.TestExceptionPlugin.GET_MESSAGE;
|
||||
import org.teavm.dependency.AbstractDependencyListener;
|
||||
import org.teavm.dependency.DependencyAgent;
|
||||
import org.teavm.dependency.DependencyNode;
|
||||
import org.teavm.dependency.MethodDependency;
|
||||
import org.teavm.model.CallLocation;
|
||||
import org.teavm.model.ClassReader;
|
||||
import org.teavm.model.ClassReaderSource;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
class TestExceptionDependency extends AbstractDependencyListener {
|
||||
private MethodReference getMessageRef = new MethodReference(ExceptionHelper.class, "showException",
|
||||
Throwable.class, String.class);
|
||||
class TestExceptionDependencyListener extends AbstractDependencyListener {
|
||||
private DependencyNode allClasses;
|
||||
|
||||
@Override
|
||||
public void started(DependencyAgent agent) {
|
||||
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
|
||||
public void classReached(DependencyAgent agent, String className, CallLocation location) {
|
||||
if (isException(agent.getClassSource(), 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));
|
||||
}
|
||||
allClasses.propagate(agent.getType(className));
|
||||
}
|
||||
}
|
|
@ -15,12 +15,58 @@
|
|||
*/
|
||||
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.TeaVMPlugin;
|
||||
|
||||
class TestExceptionPlugin implements TeaVMPlugin {
|
||||
static final MethodDescriptor GET_MESSAGE = new MethodDescriptor("getMessage", ValueType.parse(String.class));
|
||||
|
||||
@Override
|
||||
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) {
|
||||
$rt_startThread(function () {
|
||||
var thread = $rt_nativeThread();
|
||||
var instance;
|
||||
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 = {};
|
||||
makeErrorMessage(message, e);
|
||||
break loop;
|
||||
}
|
||||
if (thread.isSuspending()) {
|
||||
thread.push(instance);
|
||||
thread.push(ptr);
|
||||
return;
|
||||
}
|
||||
message = {};
|
||||
message.status = "ok";
|
||||
break loop;
|
||||
}
|
||||
function runMain(callback) {
|
||||
main([], function(result) {
|
||||
var message = {};
|
||||
if (result instanceof Error) {
|
||||
makeErrorMessage(message, result);
|
||||
} else {
|
||||
message.status = "ok";
|
||||
}
|
||||
callback.complete(JSON.stringify(message));
|
||||
});
|
||||
|
||||
function makeErrorMessage(message, e) {
|
||||
message.status = "exception";
|
||||
var stack = e.stack;
|
||||
var stack = "";
|
||||
if (e.$javaException && e.$javaException.constructor.$meta) {
|
||||
message.exception = e.$javaException.constructor.$meta.name;
|
||||
message.stack = e.$javaException.constructor.$meta.name + ": ";
|
||||
var exceptionMessage = extractException(e.$javaException);
|
||||
message.stack += exceptionMessage ? $rt_ustr(exceptionMessage) : "";
|
||||
stack = e.$javaException.constructor.$meta.name + ": ";
|
||||
stack += e.$javaException.getMessage() || "";
|
||||
stack += "\n";
|
||||
}
|
||||
message.stack += "\n" + stack;
|
||||
message.stack = stack + e.stack;
|
||||
}
|
||||
}
|
|
@ -1,52 +1,27 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>TeaVM JUnit test</title>
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript" src="test.js"></script>
|
||||
<script type="text/javascript">
|
||||
$rt_startThread(function() {
|
||||
var thread = $rt_nativeThread();
|
||||
var instance;
|
||||
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));
|
||||
});
|
||||
<head>
|
||||
<title>TeaVM JUnit test</title>
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript" src="test.js"></script>
|
||||
<script type="text/javascript">
|
||||
main([], function(result) {
|
||||
var message = result instanceof Error ? buildErrorMessage(result) : "OK";
|
||||
document.body.appendChild(document.createTextNode(message))
|
||||
});
|
||||
|
||||
function buildErrorMessage(e) {
|
||||
var stack = e.stack;
|
||||
function buildErrorMessage(e) {
|
||||
var stack = "";
|
||||
if (e.$javaException && e.$javaException.constructor.$meta) {
|
||||
stack = e.$javaException.constructor.$meta.name + ": ";
|
||||
var exceptionMessage = extractException(e.$javaException);
|
||||
stack += exceptionMessage ? $rt_ustr(exceptionMessage) : "";
|
||||
stack = e.$javaException.constructor.$meta.name + ": ";
|
||||
stack += e.$javaException.getMessage() || "";
|
||||
stack += "\n";
|
||||
}
|
||||
stack += "\n" + stack;
|
||||
stack += e.stack;
|
||||
return stack;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -14,44 +14,23 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
$rt_startThread(function() {
|
||||
var thread = $rt_nativeThread();
|
||||
var instance;
|
||||
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 = {};
|
||||
makeErrorMessage(message, e);
|
||||
break loop;
|
||||
}
|
||||
if (thread.isSuspending()) {
|
||||
thread.push(instance);
|
||||
thread.push(ptr);
|
||||
return;
|
||||
}
|
||||
message = {};
|
||||
main([], function(result) {
|
||||
var message = {};
|
||||
if (result instanceof Error) {
|
||||
makeErrorMessage(message, result);
|
||||
} else {
|
||||
message.status = "ok";
|
||||
break loop;
|
||||
}}
|
||||
}
|
||||
window.parent.postMessage(JSON.stringify(message), "*");
|
||||
});
|
||||
|
||||
function makeErrorMessage(message, e) {
|
||||
message.status = "exception";
|
||||
var stack = e.stack;
|
||||
var stack = "";
|
||||
if (e.$javaException && e.$javaException.constructor.$meta) {
|
||||
message.exception = e.$javaException.constructor.$meta.name;
|
||||
message.stack = e.$javaException.constructor.$meta.name + ": ";
|
||||
var exceptionMessage = extractException(e.$javaException);
|
||||
message.stack += exceptionMessage ? $rt_ustr(exceptionMessage) : "";
|
||||
stack = e.$javaException.constructor.$meta.name + ": ";
|
||||
stack += e.$javaException.getMessage() || "";
|
||||
stack += "\n";
|
||||
}
|
||||
message.stack += "\n" + stack;
|
||||
};
|
||||
message.stack = stack + e.stack;
|
||||
}
|
Loading…
Reference in New Issue
Block a user