JS: rewrite more natives with templates, get rid of runtime aliases in minification mode

This commit is contained in:
Alexey Andreev 2023-10-30 21:30:49 +01:00
parent 2756fe4384
commit 32ee8943c1
37 changed files with 745 additions and 646 deletions

View File

@ -16,10 +16,10 @@
package org.teavm.classlib.impl;
import java.io.IOException;
import java.util.Collection;
import org.teavm.backend.javascript.codegen.SourceWriter;
import org.teavm.backend.javascript.spi.Generator;
import org.teavm.backend.javascript.spi.GeneratorContext;
import org.teavm.backend.javascript.templating.JavaScriptTemplateFactory;
import org.teavm.model.MethodDescriptor;
import org.teavm.model.MethodReference;
@ -28,39 +28,31 @@ public class ServiceLoaderJSSupport implements Generator {
@Override
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException {
ServiceLoaderInformation information = context.getService(ServiceLoaderInformation.class);
writer.append("if (!").appendClass("java.util.ServiceLoader").append(".$$services$$) {").indent()
.softNewLine();
writer.appendClass("java.util.ServiceLoader").append(".$$services$$ = true;").softNewLine();
for (String serviceType : information.serviceTypes()) {
writer.appendClass(serviceType).append(".$$serviceList$$ = [");
Collection<? extends String> implementations = information.serviceImplementations(serviceType);
boolean first = true;
for (String implName : implementations) {
if (context.getClassSource().getClassNames().contains(implName)) {
if (!first) {
writer.append(", ");
var templateFactory = new JavaScriptTemplateFactory(context.getClassLoader(), context.getClassSource());
var template = templateFactory.createFromResource("org/teavm/classlib/java/util/ServiceLoader.js");
var information = context.getService(ServiceLoaderInformation.class);
var fragment = template.builder("loadServices")
.withContext(context)
.withFragment("fillServices", (w, precedence) -> {
for (var serviceType : information.serviceTypes()) {
writer.appendClass(serviceType).append(".$$serviceList$$ = [");
var implementations = information.serviceImplementations(serviceType);
boolean first = true;
for (var implName : implementations) {
if (context.getClassSource().getClassNames().contains(implName)) {
if (!first) {
writer.append(",").ws();
}
first = false;
writer.append("[").appendClass(implName).append(",").ws()
.appendMethodBody(new MethodReference(implName, INIT_METHOD))
.append("]");
}
}
writer.append("];").softNewLine();
}
first = false;
writer.append("[").appendClass(implName).append(", ").appendMethodBody(
new MethodReference(implName, INIT_METHOD))
.append("]");
}
}
writer.append("];").softNewLine();
}
writer.outdent().append("}").softNewLine();
String param = context.getParameterName(1);
writer.append("var cls = " + param + ";").softNewLine();
writer.append("if (!cls.$$serviceList$$) {").indent().softNewLine();
writer.append("return $rt_createArray($rt_objcls(), 0);").softNewLine();
writer.outdent().append("}").softNewLine();
writer.append("var result = $rt_createArray($rt_objcls(), cls.$$serviceList$$.length);").softNewLine();
writer.append("for (var i = 0; i < result.data.length; ++i) {").indent().softNewLine();
writer.append("var serviceDesc = cls.$$serviceList$$[i];").softNewLine();
writer.append("result.data[i] = new serviceDesc[0]();").softNewLine();
writer.append("serviceDesc[1](result.data[i]);").softNewLine();
writer.outdent().append("}").softNewLine();
writer.append("return result;").softNewLine();
})
.build();
fragment.write(writer, 0);
}
}

View File

@ -122,7 +122,7 @@ public class JSStringInjector implements Injector, Function<ProviderContext, Inj
var writer = context.getWriter();
context.writeExpr(context.getArgument(0));
writer.append(".").appendField(NATIVE_FIELD).ws().append("=").ws();
writer.append("$rt_charArrayToString").append("(");
writer.appendFunction("$rt_charArrayToString").append("(");
context.writeExpr(context.getArgument(1));
writer.append(".data,").ws();
context.writeExpr(context.getArgument(2));
@ -135,7 +135,7 @@ public class JSStringInjector implements Injector, Function<ProviderContext, Inj
var writer = context.getWriter();
context.writeExpr(context.getArgument(0));
writer.append(".").appendField(NATIVE_FIELD).ws().append("=").ws();
writer.append("$rt_fullArrayToString").append("(");
writer.appendFunction("$rt_fullArrayToString").append("(");
context.writeExpr(context.getArgument(1));
writer.append(".data)");
}
@ -156,7 +156,7 @@ public class JSStringInjector implements Injector, Function<ProviderContext, Inj
private void copyCharsToArray(InjectorContext context) throws IOException {
var writer = context.getWriter();
writer.append("$rt_stringToCharArray").append("(");
writer.appendFunction("$rt_stringToCharArray").append("(");
context.writeExpr(context.getArgument(0));
writer.append(".").appendField(NATIVE_FIELD);
writer.append(",").ws();
@ -183,7 +183,7 @@ public class JSStringInjector implements Injector, Function<ProviderContext, Inj
private void fastCharArray(InjectorContext context) throws IOException {
var writer = context.getWriter();
writer.append("$rt_fastStringToCharArray").append("(");
writer.appendFunction("$rt_fastStringToCharArray").append("(");
context.writeExpr(context.getArgument(0));
writer.append(".").appendField(NATIVE_FIELD);
writer.append(")");

View File

@ -55,7 +55,7 @@ public class ClassGenerator implements Generator, Injector, DependencyPlugin {
public void generate(InjectorContext context, MethodReference methodRef) throws IOException {
switch (methodRef.getName()) {
case "newEmptyInstance":
context.getWriter().append("new (");
context.getWriter().append("new").ws().append("(");
context.writeExpr(context.getArgument(0), Precedence.MEMBER_ACCESS);
context.getWriter().append('.').appendField(platformClassField);
context.getWriter().append(")");

View File

@ -75,7 +75,7 @@ public class ClassLoaderNativeGenerator implements Injector {
dataChars[i] = (char) dataBytes[i];
}
RenderingUtil.writeString(writer, resource);
writer.ws().append(':').ws();
writer.append(':').ws();
RenderingUtil.writeString(writer, new String(dataChars));
}
}

View File

@ -31,7 +31,8 @@ public class DoubleGenerator implements Injector {
context.getWriter().append(')');
return;
}
context.getWriter().append("$rt_").append(methodRef.getName()).append("(");
var functionName = "$rt_" + methodRef.getName();
context.getWriter().appendFunction(functionName).append("(");
context.writeExpr(context.getArgument(0));
context.getWriter().append(")");
}

View File

@ -25,26 +25,23 @@ public class IntegerNativeGenerator implements Injector {
public void generate(InjectorContext context, MethodReference methodRef) throws IOException {
switch (methodRef.getName()) {
case "divideUnsigned":
context.getWriter().append("$rt_udiv(");
context.writeExpr(context.getArgument(0));
context.getWriter().append(",").ws();
context.writeExpr(context.getArgument(1));
context.getWriter().append(")");
generateRuntimeCall(context, "$rt_udiv");
break;
case "remainderUnsigned":
context.getWriter().append("$rt_umod(");
context.writeExpr(context.getArgument(0));
context.getWriter().append(",").ws();
context.writeExpr(context.getArgument(1));
context.getWriter().append(")");
generateRuntimeCall(context, "$rt_umod");
break;
case "compareUnsigned":
context.getWriter().append("$rt_ucmp(");
context.writeExpr(context.getArgument(0));
context.getWriter().append(",").ws();
context.writeExpr(context.getArgument(1));
context.getWriter().append(")");
generateRuntimeCall(context, "$rt_ucmp");
break;
}
}
private void generateRuntimeCall(InjectorContext context, String name) throws IOException {
context.getWriter().appendFunction(name).append("(");
context.writeExpr(context.getArgument(0));
context.getWriter().append(",").ws();
context.writeExpr(context.getArgument(1));
context.getWriter().append(")");
}
}

View File

@ -31,12 +31,12 @@ public class MathNativeGenerator implements Generator {
if (name.equals("signum")) {
name = "sign";
}
function(context, writer, "Math." + name, methodRef.parameterCount());
function(context, writer, name, methodRef.parameterCount());
}
private void function(GeneratorContext context, SourceWriter writer, String name, int paramCount)
throws IOException {
writer.append("return ").append(name).append("(");
writer.append("return ").append("$rt_globals.Math").append(".").append(name).append("(");
for (int i = 0; i < paramCount; ++i) {
if (i > 0) {
writer.append(",").ws();

View File

@ -0,0 +1,111 @@
/*
* Copyright 2023 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.classlib.java.lang.reflect;
import java.util.HashSet;
import java.util.Set;
import org.teavm.dependency.DependencyAgent;
import org.teavm.dependency.DependencyPlugin;
import org.teavm.dependency.MethodDependency;
import org.teavm.model.MethodReference;
import org.teavm.model.ValueType;
public class ArrayDependencyPlugin implements DependencyPlugin {
private static final String[] primitives = { "Byte", "Short", "Char", "Int", "Long", "Float", "Double",
"Boolean" };
private static final String[] primitiveWrappers = { "Byte", "Short", "Character", "Integer", "Long",
"Float", "Double", "Boolean" };
private static final ValueType[] primitiveTypes = { ValueType.BYTE, ValueType.SHORT, ValueType.CHARACTER,
ValueType.INTEGER, ValueType.LONG, ValueType.FLOAT, ValueType.DOUBLE, ValueType.BOOLEAN };
private Set<MethodReference> reachedMethods = new HashSet<>();
@Override
public void methodReached(DependencyAgent agent, MethodDependency method) {
if (!reachedMethods.add(method.getReference())) {
return;
}
switch (method.getReference().getName()) {
case "getLength":
reachGetLength(agent, method);
break;
case "newInstance":
method.getVariable(1).getClassValueNode().addConsumer(t -> {
String arrayTypeName;
if (t.getName().startsWith("[")) {
arrayTypeName = t.getName();
} else if (t.getName().startsWith("~")) {
arrayTypeName = t.getName().substring(1);
} else {
arrayTypeName = ValueType.object(t.getName()).toString();
}
if (!arrayTypeName.startsWith("[[[")) {
method.getResult().propagate(agent.getType("[" + arrayTypeName));
}
});
break;
case "getImpl":
reachGet(agent, method);
break;
case "setImpl":
reachSet(agent, method);
break;
}
}
private void reachGetLength(DependencyAgent agent, MethodDependency method) {
method.getVariable(1).addConsumer(type -> {
if (!type.getName().startsWith("[")) {
MethodReference cons = new MethodReference(IllegalArgumentException.class, "<init>", void.class);
agent.linkMethod(cons).use();
}
});
}
private void reachGet(DependencyAgent agent, MethodDependency method) {
method.getVariable(1).getArrayItem().connect(method.getResult());
method.getVariable(1).addConsumer(type -> {
if (type.getName().startsWith("[")) {
String typeName = type.getName().substring(1);
for (int i = 0; i < primitiveTypes.length; ++i) {
if (primitiveTypes[i].toString().equals(typeName)) {
String wrapper = "java.lang." + primitiveWrappers[i];
MethodReference methodRef = new MethodReference(wrapper, "valueOf",
primitiveTypes[i], ValueType.object(wrapper));
agent.linkMethod(methodRef).use();
method.getResult().propagate(agent.getType("java.lang." + primitiveWrappers[i]));
}
}
}
});
}
private void reachSet(DependencyAgent agent, MethodDependency method) {
method.getVariable(3).connect(method.getVariable(1).getArrayItem());
method.getVariable(1).addConsumer(type -> {
if (type.getName().startsWith("[")) {
String typeName = type.getName().substring(1);
for (int i = 0; i < primitiveTypes.length; ++i) {
if (primitiveTypes[i].toString().equals(typeName)) {
String wrapper = "java.lang." + primitiveWrappers[i];
MethodReference methodRef = new MethodReference(wrapper,
primitives[i].toLowerCase() + "Value", primitiveTypes[i]);
agent.linkMethod(methodRef).use();
}
}
}
});
}
}

View File

@ -16,190 +16,22 @@
package org.teavm.classlib.java.lang.reflect;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import org.teavm.backend.javascript.codegen.SourceWriter;
import org.teavm.backend.javascript.spi.Generator;
import org.teavm.backend.javascript.spi.GeneratorContext;
import org.teavm.dependency.DependencyAgent;
import org.teavm.dependency.DependencyPlugin;
import org.teavm.dependency.MethodDependency;
import org.teavm.model.ClassReader;
import org.teavm.backend.javascript.templating.JavaScriptTemplate;
import org.teavm.backend.javascript.templating.JavaScriptTemplateFactory;
import org.teavm.model.MethodReference;
import org.teavm.model.ValueType;
public class ArrayNativeGenerator implements Generator, DependencyPlugin {
private static final String[] primitives = { "Byte", "Short", "Char", "Int", "Long", "Float", "Double",
"Boolean" };
private static final String[] primitiveWrappers = { "Byte", "Short", "Character", "Integer", "Long",
"Float", "Double", "Boolean" };
private static final ValueType[] primitiveTypes = { ValueType.BYTE, ValueType.SHORT, ValueType.CHARACTER,
ValueType.INTEGER, ValueType.LONG, ValueType.FLOAT, ValueType.DOUBLE, ValueType.BOOLEAN };
public class ArrayNativeGenerator implements Generator {
private JavaScriptTemplate template;
private Set<MethodReference> reachedMethods = new HashSet<>();
@Override
public void methodReached(DependencyAgent agent, MethodDependency method) {
if (!reachedMethods.add(method.getReference())) {
return;
}
switch (method.getReference().getName()) {
case "getLength":
reachGetLength(agent, method);
break;
case "newInstance":
method.getVariable(1).getClassValueNode().addConsumer(t -> {
String arrayTypeName;
if (t.getName().startsWith("[")) {
arrayTypeName = t.getName();
} else if (t.getName().startsWith("~")) {
arrayTypeName = t.getName().substring(1);
} else {
arrayTypeName = ValueType.object(t.getName()).toString();
}
if (!arrayTypeName.startsWith("[[[")) {
method.getResult().propagate(agent.getType("[" + arrayTypeName));
}
});
break;
case "getImpl":
reachGet(agent, method);
break;
case "setImpl":
reachSet(agent, method);
break;
}
public ArrayNativeGenerator(JavaScriptTemplateFactory templateFactory) throws IOException {
template = templateFactory.createFromResource("org/teavm/classlib/java/lang/reflect/Array.js");
}
@Override
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException {
switch (methodRef.getName()) {
case "getLength":
generateGetLength(context, writer);
break;
case "newInstanceImpl":
generateNewInstance(context, writer);
break;
case "getImpl":
generateGet(context, writer);
break;
case "setImpl":
generateSet(context, writer);
break;
}
}
private void generateGetLength(GeneratorContext context, SourceWriter writer) throws IOException {
String array = context.getParameterName(1);
writer.append("if (" + array + " === null || " + array + ".constructor.$meta.item === undefined) {")
.softNewLine().indent();
MethodReference cons = new MethodReference("java.lang.IllegalArgumentException", "<init>", ValueType.VOID);
writer.append("$rt_throw(").appendInit(cons).append("());").softNewLine();
writer.outdent().append("}").softNewLine();
writer.append("return " + array + ".data.length;").softNewLine();
}
private void reachGetLength(DependencyAgent agent, MethodDependency method) {
method.getVariable(1).addConsumer(type -> {
if (!type.getName().startsWith("[")) {
MethodReference cons = new MethodReference(IllegalArgumentException.class, "<init>", void.class);
agent.linkMethod(cons).use();
}
});
}
private void generateNewInstance(GeneratorContext context, SourceWriter writer) throws IOException {
String type = context.getParameterName(1);
String length = context.getParameterName(2);
writer.append("if (").append(type).append(".$meta.primitive) {").softNewLine().indent();
for (String primitive : primitives) {
writer.append("if (" + type + " == $rt_" + primitive.toLowerCase() + "cls) {").indent().softNewLine();
writer.append("return $rt_create" + primitive + "Array(" + length + ");").softNewLine();
writer.outdent().append("}").softNewLine();
}
writer.outdent().append("} else {").indent().softNewLine();
writer.append("return $rt_createArray(" + type + ", " + length + ")").softNewLine();
writer.outdent().append("}").softNewLine();
}
private void generateGet(GeneratorContext context, SourceWriter writer) throws IOException {
String array = context.getParameterName(1);
writer.append("var item = " + array + ".data[" + context.getParameterName(2) + "];").softNewLine();
writer.append("var type = " + array + ".constructor.$meta.item;").softNewLine();
for (int i = 0; i < primitives.length; ++i) {
String wrapper = "java.lang." + primitiveWrappers[i];
MethodReference methodRef = new MethodReference(wrapper, "valueOf",
primitiveTypes[i], ValueType.object(wrapper));
ClassReader cls = context.getClassSource().get(methodRef.getClassName());
if (cls == null || cls.getMethod(methodRef.getDescriptor()) == null) {
continue;
}
writer.append("if (type === $rt_" + primitives[i].toLowerCase() + "cls) {").indent().softNewLine();
writer.append("return ").appendMethodBody(methodRef).append("(item);").softNewLine();
writer.outdent().append("} else ");
}
writer.append("{").indent().softNewLine();
writer.append("return item;").softNewLine();
writer.outdent().append("}").softNewLine();
}
private void generateSet(GeneratorContext context, SourceWriter writer) throws IOException {
String array = context.getParameterName(1);
String item = context.getParameterName(3);
writer.append("var type = " + array + ".constructor.$meta.item;").softNewLine();
boolean first = true;
for (int i = 0; i < primitives.length; ++i) {
String wrapper = "java.lang." + primitiveWrappers[i];
MethodReference methodRef = new MethodReference(wrapper, primitives[i].toLowerCase() + "Value",
primitiveTypes[i]);
ClassReader cls = context.getClassSource().get(methodRef.getClassName());
if (cls == null || cls.getMethod(methodRef.getDescriptor()) == null) {
continue;
}
if (!first) {
writer.append(" else ");
}
first = false;
writer.append("if (type === $rt_" + primitives[i].toLowerCase() + "cls) {").indent().softNewLine();
writer.append(item + " = ").appendMethodBody(methodRef).append("(" + item + ");").softNewLine();
writer.outdent().append("}");
}
writer.softNewLine();
writer.append(array + ".data[" + context.getParameterName(2) + "] = " + item + ";").softNewLine();
}
private void reachGet(DependencyAgent agent, MethodDependency method) {
method.getVariable(1).getArrayItem().connect(method.getResult());
method.getVariable(1).addConsumer(type -> {
if (type.getName().startsWith("[")) {
String typeName = type.getName().substring(1);
for (int i = 0; i < primitiveTypes.length; ++i) {
if (primitiveTypes[i].toString().equals(typeName)) {
String wrapper = "java.lang." + primitiveWrappers[i];
MethodReference methodRef = new MethodReference(wrapper, "valueOf",
primitiveTypes[i], ValueType.object(wrapper));
agent.linkMethod(methodRef).use();
method.getResult().propagate(agent.getType("java.lang." + primitiveWrappers[i]));
}
}
}
});
}
private void reachSet(DependencyAgent agent, MethodDependency method) {
method.getVariable(3).connect(method.getVariable(1).getArrayItem());
method.getVariable(1).addConsumer(type -> {
if (type.getName().startsWith("[")) {
String typeName = type.getName().substring(1);
for (int i = 0; i < primitiveTypes.length; ++i) {
if (primitiveTypes[i].toString().equals(typeName)) {
String wrapper = "java.lang." + primitiveWrappers[i];
MethodReference methodRef = new MethodReference(wrapper,
primitives[i].toLowerCase() + "Value", primitiveTypes[i]);
agent.linkMethod(methodRef).use();
}
}
}
});
template.builder(methodRef.getName()).withContext(context).build().write(writer, 0);
}
}

View File

@ -33,7 +33,7 @@ import org.teavm.runtime.RuntimeObject;
public final class TArray extends TObject {
@GeneratedBy(ArrayNativeGenerator.class)
@PluggableDependency(ArrayNativeGenerator.class)
@PluggableDependency(ArrayDependencyPlugin.class)
@DelegateTo("getLengthLowLevel")
@NoSideEffects
public static native int getLength(TObject array) throws TIllegalArgumentException;
@ -48,7 +48,7 @@ public final class TArray extends TObject {
return array.size;
}
@PluggableDependency(ArrayNativeGenerator.class)
@PluggableDependency(ArrayDependencyPlugin.class)
public static TObject newInstance(Class<?> componentType, int length) throws TNegativeArraySizeException {
if (componentType == null) {
throw new TNullPointerException();
@ -89,12 +89,12 @@ public final class TArray extends TObject {
}
@GeneratedBy(ArrayNativeGenerator.class)
@PluggableDependency(ArrayNativeGenerator.class)
@PluggableDependency(ArrayDependencyPlugin.class)
@NoSideEffects
private static native TObject getImpl(TObject array, int index);
@GeneratedBy(ArrayNativeGenerator.class)
@PluggableDependency(ArrayNativeGenerator.class)
@PluggableDependency(ArrayDependencyPlugin.class)
@NoSideEffects
private static native void setImpl(TObject array, int index, TObject value);
}

View File

@ -0,0 +1,33 @@
/*
* Copyright 2023 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.
*/
function init() {
this[teavm_javaField("java.lang.ref.ReferenceQueue", "inner")] = [];
if (teavm_javaMethodExists("java.lang.ref.ReferenceQueue", "reportNext(Ljava/lang/ref/Reference;)Z")) {
this[teavm_javaField("java.lang.ref.ReferenceQueue", "registry")] =
new (teavm_globals.FinalizationRegistry)(ref => {
if (!teavm_javaMethod("java.lang.ref.ReferenceQueue",
"reportNext(Ljava/lang/ref/Reference;)Z")(this, ref)) {
this[teavm_javaField("java.lang.ref.ReferenceQueue", "inner")].push(ref);
}
});
}
}
function poll() {
var value = this[teavm_javaField("java.lang.ref.ReferenceQueue", "inner")];
return typeof value !== 'undefined' ? value : null;
}

View File

@ -0,0 +1,41 @@
/*
* Copyright 2023 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.
*/
function init(target, queue) {
let supported = typeof teavm_globals.WeakRef !== 'undefined';
let value = supported ? new teavm_globals.WeakRef(target) : target;
this[teavm_javaField("java.lang.ref.WeakReference", "value")] = value;
if (queue !== null && supported) {
let registry = queue[teavm_javaField("java.lang.ref.ReferenceQueue", "registry")];
if (registry !== null) {
registry.register(target, this);
}
}
}
function get() {
let value = this[teavm_javaField("java.lang.ref.WeakReference", "value")];
if (typeof teavm_globals.WeakRef !== 'undefined') {
if (value === null) {
return null;
}
let result = value.deref();
return typeof result !== 'undefined' ? result : null;
}
return value;
}
function clear() {
this[teavm_javaField("java.lang.ref.WeakReference", "value")] = null;
}

View File

@ -0,0 +1,86 @@
/*
* Copyright 2023 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.
*/
function getLength(array) {
if (array === null || array.constructor.$meta.item === 'undefined') {
$rt_throw(teavm_javaConstructor("java.lang.IllegalArgumentException", "()V")());
}
return array.data.length;
}
function newInstanceImpl(type, length) {
if (type.$meta.primitive) {
switch (type) {
case $rt_booleanArrayCls: return $rt_createBooleanArray(length);
case $rt_byteArrayCls: return $rt_createByteArray(length);
case $rt_shortArrayCls: return $rt_createShortArray(length);
case $rt_charArrayCls: return $rt_createCharArray(length);
case $rt_intArrayCls: return $rt_createIntArray(length);
case $rt_longArrayCls: return $rt_createLongArray(length);
case $rt_floatArrayCls: return $rt_createFloatArray(length);
case $rt_doubleArrayCls: return $rt_createDoubleArray(length);
}
}
return $rt_createArray(type, length);
}
function getImpl(array, index) {
var item = array.data[index];
var type = array.constructor.$meta.item;
if (teavm_javaMethodExists("java.lang.Boolean", "valueOf(Z)Ljava/lang/Boolean;") && type === $rt_booleancls) {
return teavm_javaMethod("java.lang.Boolean", "valueOf(Z)Ljava/lang/Boolean;")(item);
} else if (teavm_javaMethodExists("java.lang.Byte", "valueOf(B)Ljava/lang/Byte;") && type === $rt_bytecls) {
return teavm_javaMethod("java.lang.Byte", "valueOf(B)Ljava/lang/Byte;")(item);
} else if (teavm_javaMethodExists("java.lang.Short", "valueOf(S)Ljava/lang/Short;") && type === $rt_shortcls) {
return teavm_javaMethod("java.lang.Short", "valueOf(S)Ljava/lang/Short;")(item);
} else if (teavm_javaMethodExists("java.lang.Character", "valueOf(C)Ljava/lang/Character;")
&& type === $rt_charcls) {
return teavm_javaMethod("java.lang.Character", "valueOf(C)Ljava/lang/Character;")(item);
} else if (teavm_javaMethodExists("java.lang.Integer", "valueOf(I)Ljava/lang/Integer;") && type === $rt_intcls) {
return teavm_javaMethod("java.lang.Integer", "valueOf(I)Ljava/lang/Integer;")(item);
} else if (teavm_javaMethodExists("java.lang.Long", "valueOf(J)Ljava/lang/Long;") && type === $rt_longcls) {
return teavm_javaMethod("java.lang.Long", "valueOf(J)Ljava/lang/Long;")(item);
} else if (teavm_javaMethodExists("java.lang.Float", "valueOf(F)Ljava/lang/Float;") && type === $rt_floatcls) {
return teavm_javaMethod("java.lang.Float", "valueOf(F)Ljava/lang/Float;")(item);
} else if (teavm_javaMethodExists("java.lang.Double", "valueOf(D)Ljava/lang/Double;") && type === $rt_doublecls) {
return teavm_javaMethod("java.lang.Double", "valueOf(D)Ljava/lang/Double;")(item);
} else {
return item;
}
}
function setImpl(array, index, value) {
var type = array.constructor.$meta.item;
if (teavm_javaMethodExists("java.lang.Boolean", "booleanValue()Z") && type === $rt_booleancls) {
array.data[index] = teavm_javaMethod("java.lang.Boolean", "booleanValue()Z")(value);
} else if (teavm_javaMethodExists("java.lang.Byte", "byteValue()B") && type === $rt_booleancls) {
array.data[index] = teavm_javaMethod("java.lang.Byte", "byteValue()B")(value);
} else if (teavm_javaMethodExists("java.lang.Short", "shortValue()S") && type === $rt_shortcls) {
array.data[index] = teavm_javaMethod("java.lang.Short", "shortValue()S")(value);
} else if (teavm_javaMethodExists("java.lang.Character", "charValue()C") && type === $rt_charcls) {
array.data[index] = teavm_javaMethod("java.lang.Character", "charValue()C")(value);
} else if (teavm_javaMethodExists("java.lang.Integer", "intValue()I") && type === $rt_intcls) {
array.data[index] = teavm_javaMethod("java.lang.Integer", "intValue()I")(value);
} else if (teavm_javaMethodExists("java.lang.Long", "longValue()J") && type === $rt_longcls) {
array.data[index] = teavm_javaMethod("java.lang.Long", "longValue()J")(value);
} else if (teavm_javaMethodExists("java.lang.Float", "floatValue()F") && type === $rt_floatcls) {
array.data[index] = teavm_javaMethod("java.lang.Float", "floatValue()F")(value);
} else if (teavm_javaMethodExists("java.lang.Double", "doubleValue()D") && type === $rt_floatcls) {
array.data[index] = teavm_javaMethod("java.lang.Double", "doubleValue()D")(value);
} else {
array.data[index] = value;
}
}

View File

@ -0,0 +1,38 @@
/*
* Copyright 2023 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.
*/
function loadServices(cls) {
let serviceLoader = teavm_javaClass("java.util.ServiceLoader");
if (!serviceLoader.$$services$$) {
serviceLoader.$$services$$ = true;
teavm_fragment("fillServices");
}
let serviceList = cls.$$serviceList$$;
if (!serviceList) {
return $rt_createArray($rt_objcls(), 0);
}
let result = $rt_createArray($rt_objcls(), serviceList.length);
for (let i = 0; i < serviceList.length; ++i) {
let serviceDesc = serviceList[i];
let instance = new serviceDesc[0]();
serviceDesc[1](instance);
result.data[i] = instance;
}
return result;
}

View File

@ -171,7 +171,10 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
public void setController(TeaVMTargetController controller) {
this.controller = controller;
var weakRefGenerator = new WeakReferenceGenerator();
templateFactory = new JavaScriptTemplateFactory(controller.getClassLoader(),
controller.getDependencyInfo().getClassSource());
var weakRefGenerator = new WeakReferenceGenerator(templateFactory);
methodGenerators.put(new MethodReference(WeakReference.class, "<init>", Object.class,
ReferenceQueue.class, void.class), weakRefGenerator);
methodGenerators.put(new MethodReference(WeakReference.class, "get", Object.class), weakRefGenerator);
@ -180,9 +183,6 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
var refQueueGenerator = new ReferenceQueueGenerator();
methodGenerators.put(new MethodReference(ReferenceQueue.class, "<init>", void.class), refQueueGenerator);
methodGenerators.put(new MethodReference(ReferenceQueue.class, "poll", Reference.class), refQueueGenerator);
templateFactory = new JavaScriptTemplateFactory(controller.getClassLoader(),
controller.getDependencyInfo().getClassSource());
}
@Override
@ -480,7 +480,6 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
if (renderer.isLongLibraryUsed()) {
runtimeRenderer.renderHandWrittenRuntime("long.js");
renderer.renderLongRuntimeAliases();
}
if (renderer.isThreadLibraryUsed()) {
runtimeRenderer.renderHandWrittenRuntime("thread.js");
@ -491,10 +490,10 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
for (var entry : controller.getEntryPoints().entrySet()) {
sourceWriter.append("$rt_exports.").append(entry.getKey()).ws().append("=").ws();
var ref = entry.getValue().getMethod();
sourceWriter.append("$rt_mainStarter(").appendMethodBody(ref);
sourceWriter.appendFunction("$rt_mainStarter").append("(").appendMethodBody(ref);
sourceWriter.append(");").newLine();
sourceWriter.append("$rt_exports.").append(entry.getKey()).append(".").append("javaException")
.ws().append("=").ws().append("$rt_javaException;").newLine();
.ws().append("=").ws().appendFunction("$rt_javaException").append(";").newLine();
}
for (var listener : rendererListeners) {

View File

@ -16,56 +16,33 @@
package org.teavm.backend.javascript.intrinsics.ref;
import java.io.IOException;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import org.teavm.backend.javascript.codegen.SourceWriter;
import org.teavm.backend.javascript.spi.Generator;
import org.teavm.backend.javascript.spi.GeneratorContext;
import org.teavm.model.FieldReference;
import org.teavm.backend.javascript.templating.JavaScriptTemplate;
import org.teavm.backend.javascript.templating.JavaScriptTemplateFactory;
import org.teavm.model.MethodReference;
public class ReferenceQueueGenerator implements Generator {
private static final FieldReference INNER_FIELD = new FieldReference(ReferenceQueue.class.getName(), "inner");
private static final FieldReference REGISTRY_FIELD = new FieldReference(ReferenceQueue.class.getName(),
"registry");
private static final MethodReference REPORT_METHOD = new MethodReference(ReferenceQueue.class,
"reportNext", Reference.class, boolean.class);
private JavaScriptTemplate template;
@Override
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException {
ensureTemplate(context);
switch (methodRef.getName()) {
case "<init>":
generateInitMethod(context, writer);
template.builder("init").withContext(context).build().write(writer, 0);
break;
case "poll":
generatePollMethod(context, writer);
template.builder("poll").withContext(context).build().write(writer, 0);
break;
}
}
private void generateInitMethod(GeneratorContext context, SourceWriter writer) throws IOException {
writer.append(context.getParameterName(0)).append(".").appendField(INNER_FIELD).ws().append("=")
.ws().append("[];").softNewLine();
if (context.getDependency().getMethod(REPORT_METHOD) != null) {
generateFinalizationRegistry(context, writer);
private void ensureTemplate(GeneratorContext context) throws IOException {
if (template == null) {
template = new JavaScriptTemplateFactory(context.getClassLoader(), context.getClassSource())
.createFromResource("org/teavm/classlib/java/lang/ref/ReferenceQueue.js");
}
}
private void generateFinalizationRegistry(GeneratorContext context, SourceWriter writer) throws IOException {
writer.append(context.getParameterName(0)).append(".").appendField(REGISTRY_FIELD).ws().append("=")
.ws().append("new $rt_globals.FinalizationRegistry(ref").ws().append("=>").appendBlockStart();
writer.appendIf().append("!").appendMethodBody(REPORT_METHOD).append("(")
.append(context.getParameterName(0)).append(",").ws().append("ref))").ws();
writer.append(context.getParameterName(0)).append(".").appendField(INNER_FIELD)
.append(".push(ref)").softNewLine();
writer.appendBlockEnd().append(");").softNewLine();
}
private void generatePollMethod(GeneratorContext context, SourceWriter writer) throws IOException {
writer.append("var value").ws().append("=").ws().append(context.getParameterName(0))
.append(".").appendField(INNER_FIELD).append(".shift();").softNewLine();
writer.append("return typeof value").ws().append("!==").ws().append("'undefined'").ws()
.append("?").ws().append("value").ws().append(":").ws().append("null;").softNewLine();
}
}

View File

@ -16,82 +16,34 @@
package org.teavm.backend.javascript.intrinsics.ref;
import java.io.IOException;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import org.teavm.backend.javascript.codegen.SourceWriter;
import org.teavm.backend.javascript.spi.Generator;
import org.teavm.backend.javascript.spi.GeneratorContext;
import org.teavm.model.FieldReference;
import org.teavm.backend.javascript.templating.JavaScriptTemplate;
import org.teavm.backend.javascript.templating.JavaScriptTemplateFactory;
import org.teavm.model.MethodReference;
public class WeakReferenceGenerator implements Generator {
private JavaScriptTemplate template;
public WeakReferenceGenerator(JavaScriptTemplateFactory templateFactory) {
try {
template = templateFactory.createFromResource("org/teavm/classlib/java/lang/ref/WeakReference.js");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException {
switch (methodRef.getName()) {
case "<init>":
generateConstructor(context, writer);
template.builder("init").withContext(context).build().write(writer, 0);
break;
case "get":
generateGet(context, writer);
break;
case "clear":
generateClear(context, writer);
template.builder(methodRef.getName()).withContext(context).build().write(writer, 0);
break;
}
}
private void generateConstructor(GeneratorContext context, SourceWriter writer) throws IOException {
writer.append("var supported").ws().append("=").ws();
isSupported(writer).append(";").softNewLine();
writer.append("var value").ws().append("=").ws().append("supported").ws()
.append("?").ws().append("new $rt_globals.WeakRef(")
.append(context.getParameterName(1)).append(")").ws();
writer.append(":").ws().append(context.getParameterName(0)).append(";").softNewLine();
writer.append(context.getParameterName(0)).append(".")
.appendField(new FieldReference(WeakReference.class.getName(), "value"))
.ws().append("=").ws().append("value;").softNewLine();
writer.appendIf().append(context.getParameterName(2)).ws().append("!==").ws().append("null")
.ws().append("&&").ws().append("supported)")
.appendBlockStart();
writer.append("var registry").ws().append("=").ws()
.append(context.getParameterName(2)).append(".")
.appendField(new FieldReference(ReferenceQueue.class.getName(), "registry")).append(";")
.softNewLine();
writer.appendIf().append("registry").ws().append("!==").ws().append("null)").ws();
writer.append("registry.register(").append(context.getParameterName(1))
.append(",").ws().append(context.getParameterName(0)).append(");").softNewLine();
writer.appendBlockEnd();
}
private void generateGet(GeneratorContext context, SourceWriter writer) throws IOException {
writer.append("var value").ws().append("=").ws().append(context.getParameterName(0)).append(".")
.appendField(new FieldReference(WeakReference.class.getName(), "value"))
.append(";").softNewLine();
writer.appendIf();
isSupported(writer).append(")").appendBlockStart();
writer.appendIf().append("value").ws().append("===").ws().append("null)")
.ws().append("return null;").softNewLine();
writer.append("var result").ws().append("=").ws().append("value.deref();").softNewLine();
writer.append("return typeof result").ws().append("!==").ws().append("'undefined'")
.ws().append("?").ws().append("result").ws().append(":").ws().append("null;").softNewLine();
writer.appendElse();
writer.append("return value;").softNewLine();
writer.appendBlockEnd();
}
private void generateClear(GeneratorContext context, SourceWriter writer) throws IOException {
writer.append(context.getParameterName(0)).append(".")
.appendField(new FieldReference(WeakReference.class.getName(), "value")).ws();
writer.append("=").ws().append("null;").softNewLine();
}
private SourceWriter isSupported(SourceWriter writer) throws IOException {
return writer.append("typeof ").append("$rt_globals.WeakRef").ws().append("!==").ws()
.append("'undefined'");
}
}

View File

@ -28,7 +28,7 @@ public class DefaultGlobalNameWriter implements Function<String, NameEmitter> {
@Override
public NameEmitter apply(String s) {
if (s.startsWith("$rt_") || s.startsWith("Long_") || s.equals("Long")) {
return prec -> writer.append(s);
return prec -> writer.appendFunction(s);
}
return prec -> writer.append("$rt_globals").append('.').append(s);
}

View File

@ -183,7 +183,7 @@ public class Renderer implements RenderingManager {
}
try {
int start = writer.getOffset();
writer.append("$rt_stringPool([");
writer.appendFunction("$rt_stringPool").append("([");
for (int i = 0; i < context.getStringPool().size(); ++i) {
if (i > 0) {
writer.append(',').ws();
@ -223,9 +223,9 @@ public class Renderer implements RenderingManager {
}
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.appendClass("java.lang.String").append(".prototype.toString").ws().append("=").ws().append("()")
.ws().append("=>").ws().append("{").indent().softNewLine();
writer.append("return ").appendFunction("$rt_ustr").append("(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();
@ -233,8 +233,9 @@ public class Renderer implements RenderingManager {
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));")
.append("()").ws().append("=>").ws().append("{").indent().softNewLine();
writer.append("return ").appendFunction("$rt_ustr").append("(")
.appendMethodBody(Object.class, "toString", String.class).append("(this));")
.softNewLine();
writer.outdent().append("};").newLine();
}
@ -242,7 +243,7 @@ public class Renderer implements RenderingManager {
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.append("return ").appendFunction("$dbg_class").append("(this);").softNewLine();
writer.outdent().append("};").newLine();
}
@ -250,42 +251,6 @@ public class Renderer implements RenderingManager {
sizeByClass.put(className, sizeByClass.getOrDefault(className, 0) + sz);
}
private void renderCommonRuntimeAliases() throws IOException {
renderRuntimeAliases("$rt_throw", "$rt_compare", "$rt_nullCheck", "$rt_cls", "$rt_createArray",
"$rt_isInstance", "$rt_nativeThread", "$rt_suspending", "$rt_resuming", "$rt_invalidPointer",
"$rt_s", "$rt_eraseClinit", "$rt_imul", "$rt_wrapException", "$rt_checkBounds",
"$rt_checkUpperBound", "$rt_checkLowerBound", "$rt_wrapFunction0", "$rt_wrapFunction1",
"$rt_wrapFunction2", "$rt_wrapFunction3", "$rt_wrapFunction4",
"$rt_classWithoutFields", "$rt_createArrayFromData", "$rt_createCharArrayFromData",
"$rt_createByteArrayFromData", "$rt_createShortArrayFromData", "$rt_createIntArrayFromData",
"$rt_createBooleanArrayFromData", "$rt_createFloatArrayFromData", "$rt_createDoubleArrayFromData",
"$rt_createLongArrayFromData", "$rt_createBooleanArray", "$rt_createByteArray",
"$rt_createShortArray", "$rt_createCharArray", "$rt_createIntArray", "$rt_createLongArray",
"$rt_createFloatArray", "$rt_createDoubleArray", "$rt_compare",
"$rt_castToClass", "$rt_castToInterface", "$rt_equalDoubles",
"$rt_str", "Long_toNumber", "Long_fromInt", "Long_fromNumber", "Long_create", "Long_ZERO",
"$rt_intern", "$rt_substring", "$rt_ustr",
"Long_hi", "Long_lo");
}
public void renderLongRuntimeAliases() throws IOException {
renderRuntimeAliases("Long_add", "Long_sub", "Long_mul", "Long_div", "Long_rem", "Long_or", "Long_and",
"Long_xor", "Long_shl", "Long_shr", "Long_shru", "Long_compare", "Long_eq", "Long_ne",
"Long_lt", "Long_le", "Long_gt", "Long_ge", "Long_not", "Long_neg");
}
private void renderRuntimeAliases(String... names) throws IOException {
boolean first = true;
for (String name : names) {
if (!first) {
writer.softNewLine();
}
first = false;
writer.append("var ").appendFunction(name).ws().append('=').ws().append(name).append(";").softNewLine();
}
writer.newLine();
}
public void prepare(List<PreparedClass> classes) {
if (minifying) {
NamingOrderer orderer = new NamingOrderer();
@ -300,13 +265,6 @@ public class Renderer implements RenderingManager {
}
public boolean render(List<PreparedClass> classes) throws RenderingException {
if (minifying) {
try {
renderCommonRuntimeAliases();
} catch (IOException e) {
throw new RenderingException(e);
}
}
int index = 0;
for (PreparedClass cls : classes) {
int start = writer.getOffset();
@ -527,7 +485,7 @@ public class Renderer implements RenderingManager {
int start = writer.getOffset();
try {
writer.append("$rt_packages([");
writer.appendFunction("$rt_packages").append("([");
ObjectIntMap<String> packageIndexes = generatePackageMetadata(classes, metadataRequirements);
writer.append("]);").newLine();
@ -545,7 +503,7 @@ public class Renderer implements RenderingManager {
private void renderClassMetadataPortion(List<PreparedClass> classes, ObjectIntMap<String> packageIndexes,
ClassMetadataRequirements metadataRequirements) throws IOException {
writer.append("$rt_metadata([");
writer.appendFunction("$rt_metadata").append("([");
boolean first = true;
for (PreparedClass cls : classes) {
if (!first) {

View File

@ -305,40 +305,40 @@ public abstract class RenderingContext {
}
for (int i = 0; i < arrayCount; ++i) {
writer.append("$rt_arraycls(");
writer.appendFunction("$rt_arraycls").append("(");
}
if (type instanceof ValueType.Object) {
ValueType.Object objType = (ValueType.Object) type;
writer.appendClass(objType.getClassName());
} else if (type instanceof ValueType.Void) {
writer.append("$rt_voidcls");
writer.appendFunction("$rt_voidcls");
} else if (type instanceof ValueType.Primitive) {
ValueType.Primitive primitiveType = (ValueType.Primitive) type;
switch (primitiveType.getKind()) {
case BOOLEAN:
writer.append("$rt_booleancls");
writer.appendFunction("$rt_booleancls");
break;
case CHARACTER:
writer.append("$rt_charcls");
writer.appendFunction("$rt_charcls");
break;
case BYTE:
writer.append("$rt_bytecls");
writer.appendFunction("$rt_bytecls");
break;
case SHORT:
writer.append("$rt_shortcls");
writer.appendFunction("$rt_shortcls");
break;
case INTEGER:
writer.append("$rt_intcls");
writer.appendFunction("$rt_intcls");
break;
case LONG:
writer.append("$rt_longcls");
writer.appendFunction("$rt_longcls");
break;
case FLOAT:
writer.append("$rt_floatcls");
writer.appendFunction("$rt_floatcls");
break;
case DOUBLE:
writer.append("$rt_doublecls");
writer.appendFunction("$rt_doublecls");
break;
default:
throw new IllegalArgumentException("The type is not renderable");

View File

@ -1414,32 +1414,32 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
if (type instanceof ValueType.Primitive) {
switch (((ValueType.Primitive) type).getKind()) {
case BOOLEAN:
writer.append("$rt_createBooleanMultiArray(");
writer.appendFunction("$rt_createBooleanMultiArray").append("(");
break;
case BYTE:
writer.append("$rt_createByteMultiArray(");
writer.appendFunction("$rt_createByteMultiArray").append("(");
break;
case SHORT:
writer.append("$rt_createShortMultiArray(");
writer.appendFunction("$rt_createShortMultiArray").append("(");
break;
case INTEGER:
writer.append("$rt_createIntMultiArray(");
writer.appendFunction("$rt_createIntMultiArray").append("(");
break;
case LONG:
writer.append("$rt_createLongMultiArray(");
writer.appendFunction("$rt_createLongMultiArray").append("(");
break;
case FLOAT:
writer.append("$rt_createFloatMultiArray(");
writer.appendFunction("$rt_createFloatMultiArray").append("(");
break;
case DOUBLE:
writer.append("$rt_createDoubleMultiArray(");
writer.appendFunction("$rt_createDoubleMultiArray").append("(");
break;
case CHARACTER:
writer.append("$rt_createCharMultiArray(");
writer.appendFunction("$rt_createCharMultiArray").append("(");
break;
}
} else {
writer.append("$rt_createMultiArray(");
writer.appendFunction("$rt_createMultiArray").append("(");
context.typeToClsString(writer, type);
writer.append(",").ws();
}

View File

@ -16,6 +16,7 @@
package org.teavm.backend.javascript.templating;
import java.util.HashMap;
import java.util.Map;
import java.util.function.IntFunction;
import org.mozilla.javascript.ast.AstNode;
import org.mozilla.javascript.ast.FunctionNode;
@ -42,6 +43,7 @@ public class JavaScriptTemplate {
public static class FragmentBuilder {
private FunctionNode node;
private IntFunction<SourceFragment> parameters;
private Map<String, SourceFragment> fragments = new HashMap<>();
private FragmentBuilder(FunctionNode node) {
this.node = node;
@ -53,7 +55,12 @@ public class JavaScriptTemplate {
}
public FragmentBuilder withContext(GeneratorContext context) {
return withParameters(param -> (writer, precedence) -> writer.append(context.getParameterName(param + 1)));
return withParameters(param -> (writer, precedence) -> writer.append(context.getParameterName(param)));
}
public FragmentBuilder withFragment(String name, SourceFragment fragment) {
fragments.put(name, fragment);
return this;
}
public SourceFragment build() {
@ -62,13 +69,16 @@ public class JavaScriptTemplate {
for (var i = 0; i < node.getParams().size(); ++i) {
var param = node.getParams().get(i);
if (param instanceof Name) {
nameParameters.put(((Name) param).getIdentifier(), intParameters.apply(i));
nameParameters.put(((Name) param).getIdentifier(), intParameters.apply(i + 1));
}
}
var thisFragment = parameters.apply(0);
var body = node.getBody();
return (writer, precedence) -> {
var astWriter = new TemplatingAstWriter(writer, nameParameters, node);
for (var entry : fragments.entrySet()) {
astWriter.setFragment(entry.getKey(), entry.getValue());
}
if (node.getSymbolTable() != null) {
for (var name : node.getSymbolTable().keySet()) {
astWriter.currentScopes.put(name, node);

View File

@ -16,6 +16,7 @@
package org.teavm.backend.javascript.templating;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.mozilla.javascript.ast.ElementGet;
import org.mozilla.javascript.ast.FunctionCall;
@ -34,6 +35,7 @@ import org.teavm.model.MethodReference;
public class TemplatingAstWriter extends AstWriter {
private Map<String, SourceFragment> names;
private Scope scope;
private Map<String, SourceFragment> fragments = new HashMap<>();
public TemplatingAstWriter(SourceWriter writer, Map<String, SourceFragment> names, Scope scope) {
super(writer, new DefaultGlobalNameWriter(writer));
@ -49,6 +51,10 @@ public class TemplatingAstWriter extends AstWriter {
}
}
public void setFragment(String name, SourceFragment fragment) {
fragments.put(name, fragment);
}
@Override
protected boolean intrinsic(FunctionCall node, int precedence) throws IOException {
if (node.getTarget() instanceof Name) {
@ -70,6 +76,8 @@ public class TemplatingAstWriter extends AstWriter {
return writeJavaConstructor(node);
case "teavm_javaClassInit":
return writeJavaClassInit(node);
case "teavm_fragment":
return writeFragment(node);
default:
return false;
}
@ -129,6 +137,19 @@ public class TemplatingAstWriter extends AstWriter {
return true;
}
private boolean writeFragment(FunctionCall node) throws IOException {
if (node.getArguments().size() != 1) {
return false;
}
var fragmentArg = node.getArguments().get(0);
if (!(fragmentArg instanceof StringLiteral)) {
return false;
}
var fragment = fragments.get(((StringLiteral) fragmentArg).getValue());
fragment.write(writer, AstWriter.PRECEDENCE_COMMA + 1);
return true;
}
@Override
protected void print(ElementGet node) throws IOException {
if (node.getElement() instanceof FunctionCall) {
@ -209,7 +230,7 @@ public class TemplatingAstWriter extends AstWriter {
return;
}
}
if (definingScope == null && scope != null) {
if (definingScope == null) {
writer.appendFunction(node.getIdentifier());
return;
}

View File

@ -18,11 +18,11 @@
var $rt_intern
if (teavm_javaMethodExists("java.lang.String", "intern()Ljava/lang/String;")) {
$rt_intern = function() {
var map = Object.create(null);
var map = teavm_globals.Object.create(null);
var get;
if (typeof WeakRef !== 'undefined') {
var registry = new FinalizationRegistry(value => {
if (typeof teavm_globals.WeakRef !== 'undefined') {
var registry = new teavm_globals.FinalizationRegistry(value => {
delete map[value];
});
@ -32,7 +32,7 @@ if (teavm_javaMethodExists("java.lang.String", "intern()Ljava/lang/String;")) {
var result = typeof ref !== 'undefined' ? ref.deref() : void 0;
if (typeof result !== 'object') {
result = str;
map[key] = new WeakRef(result);
map[key] = new teavm_globals.WeakRef(result);
registry.register(result, key);
}
return result;

View File

@ -41,7 +41,7 @@ var Long_shr;
var Long_shru;
var Long_not;
if (typeof BigInt !== 'function') {
if (typeof teavm_globals.BigInt !== 'function') {
Long_eq = function(a, b) {
return a.hi === b.hi && a.lo === b.lo;
}
@ -267,7 +267,7 @@ if (typeof BigInt !== 'function') {
function Long_divRem(a, b) {
if (b.lo === 0 && b.hi === 0) {
throw new Error("Division by zero");
throw new teavm_globals.Error("Division by zero");
}
var positive = Long_isNegative(a) === Long_isNegative(b);
if (Long_isNegative(a)) {
@ -286,7 +286,7 @@ if (typeof BigInt !== 'function') {
function Long_udivRem(a, b) {
if (b.lo === 0 && b.hi === 0) {
throw new Error("Division by zero");
throw new teavm_globals.Error("Division by zero");
}
a = new LongInt(a.lo, a.hi, 0);
b = new LongInt(b.lo, b.hi, 0);
@ -599,79 +599,81 @@ if (typeof BigInt !== 'function') {
}
Long_add = function(a, b) {
return BigInt.asIntN(64, a + b);
return teavm_globals.BigInt.asIntN(64, a + b);
}
Long_inc = function(a) {
return BigInt.asIntN(64, a + 1);
return teavm_globals.BigInt.asIntN(64, a + 1);
}
Long_dec = function(a) {
return BigInt.asIntN(64, a - 1);
return teavm_globals.BigInt.asIntN(64, a - 1);
}
Long_neg = function(a) {
return BigInt.asIntN(64, -a);
return teavm_globals.BigInt.asIntN(64, -a);
}
Long_sub = function(a, b) {
return BigInt.asIntN(64, a - b);
return teavm_globals.BigInt.asIntN(64, a - b);
}
Long_compare = function(a, b) {
return a < b ? -1 : a > b ? 1 : 0;
}
Long_ucompare = function(a, b) {
a = BigInt.asUintN(64, a);
b = BigInt.asUintN(64, b);
a = teavm_globals.BigInt.asUintN(64, a);
b = teavm_globals.BigInt.asUintN(64, b);
return a < b ? -1 : a > b ? 1 : 0;
}
Long_mul = function(a, b) {
return BigInt.asIntN(64, a * b);
return teavm_globals.BigInt.asIntN(64, a * b);
}
Long_div = function(a, b) {
return BigInt.asIntN(64, a / b);
return teavm_globals.BigInt.asIntN(64, a / b);
}
Long_udiv = function(a, b) {
return BigInt.asIntN(64, BigInt.asUintN(64, a) / BigInt.asUintN(64, b));
return teavm_globals.BigInt.asIntN(64, teavm_globals.BigInt.asUintN(64, a) /
teavm_globals.BigInt.asUintN(64, b));
}
Long_rem = function(a, b) {
return BigInt.asIntN(64, a % b);
return teavm_globals.BigInt.asIntN(64, a % b);
}
Long_urem = function(a, b) {
return BigInt.asIntN(64, BigInt.asUintN(64, a) % BigInt.asUintN(64, b));
return teavm_globals.BigInt.asIntN(64, teavm_globals.BigInt.asUintN(64, a) %
teavm_globals.BigInt.asUintN(64, b));
}
Long_and = function(a, b) {
return BigInt.asIntN(64, a & b);
return teavm_globals.BigInt.asIntN(64, a & b);
}
Long_or = function(a, b) {
return BigInt.asIntN(64, a | b);
return teavm_globals.BigInt.asIntN(64, a | b);
}
Long_xor = function(a, b) {
return BigInt.asIntN(64, a ^ b);
return teavm_globals.BigInt.asIntN(64, a ^ b);
}
Long_shl = function(a, b) {
return BigInt.asIntN(64, a << BigInt(b & 63));
return teavm_globals.BigInt.asIntN(64, a << teavm_globals.BigInt(b & 63));
}
Long_shr = function(a, b) {
return BigInt.asIntN(64, a >> BigInt(b & 63));
return teavm_globals.BigInt.asIntN(64, a >> teavm_globals.BigInt(b & 63));
}
Long_shru = function(a, b) {
return BigInt.asIntN(64, BigInt.asUintN(64, a) >> BigInt(b & 63));
return teavm_globals.BigInt.asIntN(64, teavm_globals.BigInt.asUintN(64, a) >> teavm_globals.BigInt(b & 63));
}
Long_not = function(a) {
return BigInt.asIntN(64, ~a);
return teavm_globals.BigInt.asIntN(64, ~a);
}
}

View File

@ -57,7 +57,7 @@ function $rt_castToClass(obj, cls) {
return obj;
}
function $rt_createArray(cls, sz) {
var data = new Array(sz);
var data = new teavm_globals.Array(sz);
data.fill(null);
return new ($rt_arraycls(cls))(data);
}
@ -68,13 +68,13 @@ function $rt_wrapArray(cls, data) {
return new ($rt_arraycls(cls))(data);
}
function $rt_createUnfilledArray(cls, sz) {
return new ($rt_arraycls(cls))(new Array(sz));
return new ($rt_arraycls(cls))(new teavm_globals.Array(sz));
}
var $rt_createLongArray;
var $rt_createLongArrayFromData;
if (typeof BigInt64Array !== 'function') {
if (typeof teavm_globals.BigInt64Array !== 'function') {
$rt_createLongArray = function(sz) {
var data = new Array(sz);
var data = new teavm_globals.Array(sz);
var arr = new $rt_longArrayCls(data);
data.fill(Long_ZERO);
return arr;
@ -84,69 +84,69 @@ if (typeof BigInt64Array !== 'function') {
}
} else {
$rt_createLongArray = function (sz) {
return new $rt_longArrayCls(new BigInt64Array(sz));
return new $rt_longArrayCls(new teavm_globals.BigInt64Array(sz));
}
$rt_createLongArrayFromData = function(data) {
var buffer = new BigInt64Array(data.length);
var buffer = new teavm_globals.BigInt64Array(data.length);
buffer.set(data);
return new $rt_longArrayCls(buffer);
}
}
function $rt_createCharArray(sz) {
return new $rt_charArrayCls(new Uint16Array(sz));
return new $rt_charArrayCls(new teavm_globals.Uint16Array(sz));
}
function $rt_createCharArrayFromData(data) {
var buffer = new Uint16Array(data.length);
var buffer = new teavm_globals.Uint16Array(data.length);
buffer.set(data);
return new $rt_charArrayCls(buffer);
}
function $rt_createByteArray(sz) {
return new $rt_byteArrayCls(new Int8Array(sz));
return new $rt_byteArrayCls(new teavm_globals.Int8Array(sz));
}
function $rt_createByteArrayFromData(data) {
var buffer = new Int8Array(data.length);
var buffer = new teavm_globals.Int8Array(data.length);
buffer.set(data);
return new $rt_byteArrayCls(buffer);
}
function $rt_createShortArray(sz) {
return new $rt_shortArrayCls(new Int16Array(sz));
return new $rt_shortArrayCls(new teavm_globals.Int16Array(sz));
}
function $rt_createShortArrayFromData(data) {
var buffer = new Int16Array(data.length);
var buffer = new teavm_globals.Int16Array(data.length);
buffer.set(data);
return new $rt_shortArrayCls(buffer);
}
function $rt_createIntArray(sz) {
return new $rt_intArrayCls(new Int32Array(sz));
return new $rt_intArrayCls(new teavm_globals.Int32Array(sz));
}
function $rt_createIntArrayFromData(data) {
var buffer = new Int32Array(data.length);
var buffer = new teavm_globals.Int32Array(data.length);
buffer.set(data);
return new $rt_intArrayCls(buffer);
}
function $rt_createBooleanArray(sz) {
return new $rt_booleanArrayCls(new Int8Array(sz));
return new $rt_booleanArrayCls(new teavm_globals.Int8Array(sz));
}
function $rt_createBooleanArrayFromData(data) {
var buffer = new Int8Array(data.length);
var buffer = new teavm_globals.Int8Array(data.length);
buffer.set(data);
return new $rt_booleanArrayCls(buffer);
}
function $rt_createFloatArray(sz) {
return new $rt_floatArrayCls(new Float32Array(sz));
return new $rt_floatArrayCls(new teavm_globals.Float32Array(sz));
}
function $rt_createFloatArrayFromData(data) {
var buffer = new Float32Array(data.length);
var buffer = new teavm_globals.Float32Array(data.length);
buffer.set(data);
return new $rt_floatArrayCls(buffer);
}
function $rt_createDoubleArray(sz) {
return new $rt_doubleArrayCls(new Float64Array(sz));
return new $rt_doubleArrayCls(new teavm_globals.Float64Array(sz));
}
function $rt_createDoubleArrayFromData(data) {
var buffer = new Float64Array(data.length);
var buffer = new teavm_globals.Float64Array(data.length);
buffer.set(data);
return new $rt_doubleArrayCls(buffer);
}
@ -158,7 +158,7 @@ function $rt_arraycls(cls) {
$rt_objcls().call(this);
this.data = data;
}
JavaArray.prototype = Object.create($rt_objcls().prototype);
JavaArray.prototype = teavm_globals.Object.create($rt_objcls().prototype);
JavaArray.prototype.type = cls;
JavaArray.prototype.constructor = JavaArray;
JavaArray.prototype.toString = function() {
@ -239,16 +239,16 @@ var $rt_voidcls = $rt_createPrimitiveCls("void", "V");
function $rt_throw(ex) {
throw $rt_exception(ex);
}
var $rt_javaExceptionProp = Symbol("javaException")
var $rt_javaExceptionProp = teavm_globals.Symbol("javaException")
function $rt_exception(ex) {
var err = ex.$jsException;
if (!err) {
var javaCause = $rt_throwableCause(ex);
var jsCause = javaCause !== null ? javaCause.$jsException : undefined;
var cause = typeof jsCause === "object" ? { cause : jsCause } : undefined;
var jsCause = javaCause !== null ? javaCause.$jsException : void 0;
var cause = typeof jsCause === "object" ? { cause : jsCause } : void 0;
err = new JavaError("Java exception thrown", cause);
if (typeof Error.captureStackTrace === "function") {
Error.captureStackTrace(err);
if (typeof teavm_globals.Error.captureStackTrace === "function") {
teavm_globals.Error.captureStackTrace(err);
}
err[$rt_javaExceptionProp] = ex;
ex.$jsException = err;
@ -293,7 +293,7 @@ function $rt_createMultiArray(cls, dimensions) {
return $rt_createArray(cls, dimensions[first]);
}
}
var arrays = new Array($rt_primitiveArrayCount(dimensions, first));
var arrays = new teavm_globals.Array($rt_primitiveArrayCount(dimensions, first));
var firstDim = dimensions[first] | 0;
for (i = 0; i < arrays.length; i = (i + 1) | 0) {
arrays[i] = $rt_createArray(cls, firstDim);
@ -301,7 +301,7 @@ function $rt_createMultiArray(cls, dimensions) {
return $rt_createMultiArrayImpl(cls, arrays, dimensions, first);
}
function $rt_createByteMultiArray(dimensions) {
var arrays = new Array($rt_primitiveArrayCount(dimensions, 0));
var arrays = new teavm_globals.Array($rt_primitiveArrayCount(dimensions, 0));
if (arrays.length === 0) {
return $rt_createMultiArray($rt_bytecls, dimensions);
}
@ -312,7 +312,7 @@ function $rt_createByteMultiArray(dimensions) {
return $rt_createMultiArrayImpl($rt_bytecls, arrays, dimensions);
}
function $rt_createCharMultiArray(dimensions) {
var arrays = new Array($rt_primitiveArrayCount(dimensions, 0));
var arrays = new teavm_globals.Array($rt_primitiveArrayCount(dimensions, 0));
if (arrays.length === 0) {
return $rt_createMultiArray($rt_charcls, dimensions);
}
@ -323,7 +323,7 @@ function $rt_createCharMultiArray(dimensions) {
return $rt_createMultiArrayImpl($rt_charcls, arrays, dimensions, 0);
}
function $rt_createBooleanMultiArray(dimensions) {
var arrays = new Array($rt_primitiveArrayCount(dimensions, 0));
var arrays = new teavm_globals.Array($rt_primitiveArrayCount(dimensions, 0));
if (arrays.length === 0) {
return $rt_createMultiArray($rt_booleancls, dimensions);
}
@ -334,7 +334,7 @@ function $rt_createBooleanMultiArray(dimensions) {
return $rt_createMultiArrayImpl($rt_booleancls, arrays, dimensions, 0);
}
function $rt_createShortMultiArray(dimensions) {
var arrays = new Array($rt_primitiveArrayCount(dimensions, 0));
var arrays = new teavm_globals.Array($rt_primitiveArrayCount(dimensions, 0));
if (arrays.length === 0) {
return $rt_createMultiArray($rt_shortcls, dimensions);
}
@ -345,7 +345,7 @@ function $rt_createShortMultiArray(dimensions) {
return $rt_createMultiArrayImpl($rt_shortcls, arrays, dimensions, 0);
}
function $rt_createIntMultiArray(dimensions) {
var arrays = new Array($rt_primitiveArrayCount(dimensions, 0));
var arrays = new teavm_globals.Array($rt_primitiveArrayCount(dimensions, 0));
if (arrays.length === 0) {
return $rt_createMultiArray($rt_intcls, dimensions);
}
@ -356,7 +356,7 @@ function $rt_createIntMultiArray(dimensions) {
return $rt_createMultiArrayImpl($rt_intcls, arrays, dimensions, 0);
}
function $rt_createLongMultiArray(dimensions) {
var arrays = new Array($rt_primitiveArrayCount(dimensions, 0));
var arrays = new teavm_globals.Array($rt_primitiveArrayCount(dimensions, 0));
if (arrays.length === 0) {
return $rt_createMultiArray($rt_longcls, dimensions);
}
@ -367,7 +367,7 @@ function $rt_createLongMultiArray(dimensions) {
return $rt_createMultiArrayImpl($rt_longcls, arrays, dimensions, 0);
}
function $rt_createFloatMultiArray(dimensions) {
var arrays = new Array($rt_primitiveArrayCount(dimensions, 0));
var arrays = new teavm_globals.Array($rt_primitiveArrayCount(dimensions, 0));
if (arrays.length === 0) {
return $rt_createMultiArray($rt_floatcls, dimensions);
}
@ -378,7 +378,7 @@ function $rt_createFloatMultiArray(dimensions) {
return $rt_createMultiArrayImpl($rt_floatcls, arrays, dimensions, 0);
}
function $rt_createDoubleMultiArray(dimensions) {
var arrays = new Array($rt_primitiveArrayCount(dimensions, 0));
var arrays = new teavm_globals.Array($rt_primitiveArrayCount(dimensions, 0));
if (arrays.length === 0) {
return $rt_createMultiArray($rt_doublecls, dimensions);
}
@ -477,7 +477,7 @@ var $rt_putStderr = typeof $rt_putStderrCustom === "function"
var $rt_packageData = null;
function $rt_packages(data) {
var i = 0;
var packages = new Array(data.length);
var packages = new teavm_globals.Array(data.length);
for (var j = 0; j < data.length; ++j) {
var prefixIndex = data[i++];
var prefix = prefixIndex >= 0 ? packages[prefixIndex] : "";
@ -508,7 +508,7 @@ function $rt_metadata(data) {
m.supertypes = data[i++];
if (m.superclass) {
m.supertypes.push(m.superclass);
cls.prototype = Object.create(m.superclass.prototype);
cls.prototype = teavm_globals.Object.create(m.superclass.prototype);
} else {
cls.prototype = {};
}
@ -583,7 +583,7 @@ function $rt_wrapFunction4(f) {
}
function $rt_threadStarter(f) {
return function() {
var args = Array.prototype.slice.apply(arguments);
var args = teavm_globals.Array.prototype.slice.apply(arguments);
$rt_startThread(function() {
f.apply(this, args);
});
@ -604,7 +604,7 @@ function $rt_mainStarter(f) {
var $rt_stringPool_instance;
function $rt_stringPool(strings) {
$rt_stringClassInit();
$rt_stringPool_instance = new Array(strings.length);
$rt_stringPool_instance = new teavm_globals.Array(strings.length);
for (var i = 0; i < strings.length; ++i) {
$rt_stringPool_instance[i] = $rt_intern($rt_str(strings[i]));
}
@ -616,15 +616,15 @@ function $rt_eraseClinit(target) {
return target.$clinit = function() {};
}
var $rt_numberConversionBuffer = new ArrayBuffer(16);
var $rt_numberConversionView = new DataView($rt_numberConversionBuffer);
var $rt_numberConversionFloatArray = new Float32Array($rt_numberConversionBuffer);
var $rt_numberConversionDoubleArray = new Float64Array($rt_numberConversionBuffer);
var $rt_numberConversionIntArray = new Int32Array($rt_numberConversionBuffer);
var $rt_numberConversionBuffer = new teavm_globals.ArrayBuffer(16);
var $rt_numberConversionView = new teavm_globals.DataView($rt_numberConversionBuffer);
var $rt_numberConversionFloatArray = new teavm_globals.Float32Array($rt_numberConversionBuffer);
var $rt_numberConversionDoubleArray = new teavm_globals.Float64Array($rt_numberConversionBuffer);
var $rt_numberConversionIntArray = new teavm_globals.Int32Array($rt_numberConversionBuffer);
var $rt_doubleToRawLongBits;
var $rt_longBitsToDouble;
if (typeof BigInt !== 'function') {
if (typeof teavm_globals.BigInt !== 'function') {
$rt_doubleToRawLongBits = function(n) {
$rt_numberConversionView.setFloat64(0, n, true);
return new Long($rt_numberConversionView.getInt32(0, true), $rt_numberConversionView.getInt32(4, true));
@ -634,21 +634,23 @@ if (typeof BigInt !== 'function') {
$rt_numberConversionView.setInt32(4, n.hi, true);
return $rt_numberConversionView.getFloat64(0, true);
}
} else if (typeof BigInt64Array !== 'function') {
} else if (typeof teavm_globals.BigInt64Array !== 'function') {
$rt_doubleToRawLongBits = function(n) {
$rt_numberConversionView.setFloat64(0, n, true);
var lo = $rt_numberConversionView.getInt32(0, true);
var hi = $rt_numberConversionView.getInt32(4, true);
return BigInt.asIntN(64, BigInt.asUintN(32, BigInt(lo)) | (BigInt(hi) << BigInt(32)));
return teavm_globals.BigInt.asIntN(64, teavm_globals.BigInt.asUintN(32, teavm_globals.BigInt(lo))
| (teavm_globals.BigInt(hi) << teavm_globals.BigInt(32)));
}
$rt_longBitsToDouble = function(n) {
$rt_numberConversionView.setFloat64(0, n, true);
var lo = $rt_numberConversionView.getInt32(0, true);
var hi = $rt_numberConversionView.getInt32(4, true);
return BigInt.asIntN(64, BigInt.asUintN(32, BigInt(lo)) | (BigInt(hi) << BigInt(32)));
return teavm_globals.BigInt.asIntN(64, teavm_globals.BigInt.asUintN(32, teavm_globals.BigInt(lo))
| (teavm_globals.BigInt(hi) << teavm_globals.BigInt(32)));
}
} else {
var $rt_numberConversionLongArray = new BigInt64Array($rt_numberConversionBuffer);
var $rt_numberConversionLongArray = new teavm_globals.BigInt64Array($rt_numberConversionBuffer);
$rt_doubleToRawLongBits = function(n) {
$rt_numberConversionDoubleArray[0] = n;
return $rt_numberConversionLongArray[0];
@ -679,14 +681,14 @@ function $rt_equalDoubles(a, b) {
var JavaError;
if (typeof Reflect === 'object') {
var defaultMessage = Symbol("defaultMessage");
var defaultMessage = teavm_globals.Symbol("defaultMessage");
JavaError = function JavaError(message, cause) {
var self = Reflect.construct(Error, [undefined, cause], JavaError);
Object.setPrototypeOf(self, JavaError.prototype);
var self = teavm_globals.Reflect.construct(teavm_globals.Error, [void 0, cause], JavaError);
teavm_globals.Object.setPrototypeOf(self, JavaError.prototype);
self[defaultMessage] = message;
return self;
}
JavaError.prototype = Object.create(Error.prototype, {
JavaError.prototype = teavm_globals.Object.create(teavm_globals.Error.prototype, {
constructor: {
configurable: true,
writable: true,
@ -710,11 +712,13 @@ if (typeof Reflect === 'object') {
}
});
} else {
JavaError = Error;
JavaError = teavm_globals.Error;
}
function $rt_javaException(e) {
return e instanceof Error && typeof e[$rt_javaExceptionProp] === 'object' ? e[$rt_javaExceptionProp] : null;
return e instanceof teavm_globals.Error && typeof e[$rt_javaExceptionProp] === 'object'
? e[$rt_javaExceptionProp]
: null;
}
function $rt_jsException(e) {
return typeof e.$jsException === 'object' ? e.$jsException : null;
@ -785,7 +789,7 @@ var Long_fromNumber;
var Long_toNumber;
var Long_hi;
var Long_lo;
if (typeof BigInt !== "function") {
if (typeof teavm_globals.BigInt !== "function") {
Long.prototype.toString = function() {
var result = [];
var n = this;
@ -796,7 +800,7 @@ if (typeof BigInt !== "function") {
var radix = new Long(10, 0);
do {
var divRem = Long_divRem(n, radix);
result.push(String.fromCharCode(48 + divRem[1].lo));
result.push(teavm_globals.String.fromCharCode(48 + divRem[1].lo));
n = divRem[0];
} while (n.lo !== 0 || n.hi !== 0);
result = result.reverse().join('');
@ -830,28 +834,29 @@ if (typeof BigInt !== "function") {
return val.lo;
}
} else {
Long_ZERO = BigInt(0);
Long_ZERO = teavm_globals.BigInt(0);
Long_create = function(lo, hi) {
return BigInt.asIntN(64, BigInt.asUintN(64, BigInt(lo))
| BigInt.asUintN(64, (BigInt(hi) << BigInt(32))));
return teavm_globals.BigInt.asIntN(64, teavm_globals.BigInt.asUintN(64, teavm_globals.BigInt(lo))
| teavm_globals.BigInt.asUintN(64, (teavm_globals.BigInt(hi) << teavm_globals.BigInt(32))));
}
Long_fromInt = function(val) {
return BigInt.asIntN(64, BigInt(val | 0));
return teavm_globals.BigInt.asIntN(64, teavm_globals.BigInt(val | 0));
}
Long_fromNumber = function(val) {
return BigInt.asIntN(64, BigInt(val >= 0 ? Math.floor(val) : Math.ceil(val)));
return teavm_globals.BigInt.asIntN(64, teavm_globals.BigInt(
val >= 0 ? teavm_globals.Math.floor(val) : teavm_globals.Math.ceil(val)));
}
Long_toNumber = function(val) {
return Number(val);
return teavm_globals.Number(val);
}
Long_hi = function(val) {
return Number(BigInt.asIntN(64, val >> BigInt(32))) | 0;
return teavm_globals.Number(teavm_globals.BigInt.asIntN(64, val >> teavm_globals.BigInt(32))) | 0;
}
Long_lo = function(val) {
return Number(BigInt.asIntN(32, val)) | 0;
return teavm_globals.Number(teavm_globals.BigInt.asIntN(32, val)) | 0;
}
}
var $rt_imul = Math.imul || function(a, b) {
var $rt_imul = teavm_globals.Math.imul || function(a, b) {
var ah = (a >>> 16) & 0xFFFF;
var al = a & 0xFFFF;
var bh = (b >>> 16) & 0xFFFF;
@ -902,8 +907,8 @@ function $rt_charArrayToString(array, offset, count) {
var result = "";
var limit = offset + count;
for (var i = offset; i < limit; i = (i + 1024) | 0) {
var next = Math.min(limit, (i + 1024) | 0);
result += String.fromCharCode.apply(null, array.subarray(i, next));
var next = teavm_globals.Math.min(limit, (i + 1024) | 0);
result += teavm_globals.String.fromCharCode.apply(null, array.subarray(i, next));
}
return result;
}
@ -916,7 +921,7 @@ function $rt_stringToCharArray(string, begin, dst, dstBegin, count) {
}
}
function $rt_fastStringToCharArray(string) {
var array = new Uint16Array(string.length);
var array = new teavm_globals.Uint16Array(string.length);
for (var i = 0; i < array.length; ++i) {
array[i] = string.charCodeAt(i);
}

View File

@ -24,7 +24,7 @@ function $rt_startThread(runner, callback) {
}
if (typeof callback !== 'undefined') {
callback(result);
} else if (result instanceof Error) {
} else if (result instanceof teavm_globals.Error) {
throw result;
}
}

View File

@ -46,14 +46,14 @@ TeaVMThread.prototype.suspend = function(callback) {
};
TeaVMThread.prototype.start = function(callback) {
if (this.status !== 3) {
throw new Error("Thread already started");
throw new teavm_globals.Error("Thread already started");
}
if ($rt_currentNativeThread !== null) {
throw new Error("Another thread is running");
throw new teavm_globals.Error("Another thread is running");
}
this.status = 0;
this.completeCallback = callback ? callback : function(result) {
if (result instanceof Error) {
this.completeCallback = callback ? callback : (result) => {
if (result instanceof teavm_globals.Error) {
throw result;
}
};
@ -61,7 +61,7 @@ TeaVMThread.prototype.start = function(callback) {
};
TeaVMThread.prototype.resume = function() {
if ($rt_currentNativeThread !== null) {
throw new Error("Another thread is running");
throw new teavm_globals.Error("Another thread is running");
}
this.status = 2;
this.run();
@ -80,9 +80,7 @@ TeaVMThread.prototype.run = function() {
var self = this;
var callback = this.suspendCallback;
this.suspendCallback = null;
callback(function() {
self.resume();
});
callback(() => self.resume());
} else if (this.status === 0) {
this.completeCallback(result);
}
@ -99,7 +97,7 @@ function $rt_resuming() {
function $rt_suspend(callback) {
var nativeThread = $rt_nativeThread();
if (nativeThread === null) {
throw new Error("Suspension point reached from non-threading context (perhaps, from native JS method).");
throw new teavm_globals.Error("Suspension point reached from non-threading context (perhaps, from native JS method).");
}
return nativeThread.suspend(callback);
}
@ -111,5 +109,5 @@ function $rt_nativeThread() {
return $rt_currentNativeThread;
}
function $rt_invalidPointer() {
throw new Error("Invalid recorded state");
throw new teavm_globals.Error("Invalid recorded state");
}

View File

@ -25,12 +25,12 @@ public class JSExceptionsGenerator implements Injector {
public void generate(InjectorContext context, MethodReference methodRef) throws IOException {
switch (methodRef.getName()) {
case "getJavaException":
context.getWriter().append("$rt_javaException(");
context.getWriter().appendFunction("$rt_javaException").append("(");
context.writeExpr(context.getArgument(0));
context.getWriter().append(")");
break;
case "getJSException":
context.getWriter().append("$rt_jsException(");
context.getWriter().appendFunction("$rt_jsException").append("(");
context.writeExpr(context.getArgument(0));
context.getWriter().append(")");
break;

View File

@ -44,7 +44,7 @@ public class JSWrapperGenerator implements Injector, DependencyPlugin {
context.getWriter().append("(");
}
context.writeExpr(context.getArgument(0));
context.getWriter().append(" instanceof ").append("$rt_objcls").append("()");
context.getWriter().append(" instanceof ").appendFunction("$rt_objcls").append("()");
if (context.getPrecedence().ordinal() >= Precedence.COMPARISON.ordinal()) {
context.getWriter().append(")");
}

View File

@ -21,6 +21,8 @@ import org.teavm.backend.javascript.spi.Generator;
import org.teavm.backend.javascript.spi.GeneratorContext;
import org.teavm.backend.javascript.spi.VirtualMethodContributor;
import org.teavm.backend.javascript.spi.VirtualMethodContributorContext;
import org.teavm.backend.javascript.templating.JavaScriptTemplate;
import org.teavm.backend.javascript.templating.JavaScriptTemplateFactory;
import org.teavm.dependency.DependencyAgent;
import org.teavm.dependency.DependencyPlugin;
import org.teavm.dependency.MethodDependency;
@ -36,53 +38,30 @@ import org.teavm.model.ValueType;
public class AsyncMethodGenerator implements Generator, DependencyPlugin, VirtualMethodContributor {
private static final MethodDescriptor completeMethod = new MethodDescriptor("complete", Object.class, void.class);
private static final MethodDescriptor errorMethod = new MethodDescriptor("error", Throwable.class, void.class);
private JavaScriptTemplate template;
@Override
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException {
MethodReference asyncRef = getAsyncReference(context.getClassSource(), methodRef);
writer.append("var thread").ws().append('=').ws().append("$rt_nativeThread();").softNewLine();
writer.append("var javaThread").ws().append('=').ws().append("$rt_getThread();").softNewLine();
writer.append("if").ws().append("(thread.isResuming())").ws().append("{").indent().softNewLine();
writer.append("thread.status").ws().append("=").ws().append("0;").softNewLine();
writer.append("var result").ws().append("=").ws().append("thread.attribute;").softNewLine();
writer.append("if").ws().append("(result instanceof Error)").ws().append("{").indent().softNewLine();
writer.append("throw result;").softNewLine();
writer.outdent().append("}").softNewLine();
writer.append("return result;").softNewLine();
writer.outdent().append("}").softNewLine();
writer.append("var callback").ws().append("=").ws().append("function()").ws().append("{};").softNewLine();
writer.append("callback.").appendMethod(completeMethod).ws().append("=").ws()
.append("function(val)").ws().append("{").indent().softNewLine();
writer.append("thread.attribute").ws().append('=').ws().append("val;").softNewLine();
writer.append("$rt_setThread(javaThread);").softNewLine();
writer.append("thread.resume();").softNewLine();
writer.outdent().append("};").softNewLine();
writer.append("callback.").appendMethod(errorMethod).ws().append("=").ws()
.append("function(e)").ws().append("{").indent().softNewLine();
writer.append("thread.attribute").ws().append('=').ws().append("$rt_exception(e);").softNewLine();
writer.append("$rt_setThread(javaThread);").softNewLine();
writer.append("thread.resume();").softNewLine();
writer.outdent().append("};").softNewLine();
writer.append("callback").ws().append("=").ws().appendMethodBody(AsyncCallbackWrapper.class, "create",
AsyncCallback.class, AsyncCallbackWrapper.class).append("(callback);").softNewLine();
writer.append("thread.suspend(function()").ws().append("{").indent().softNewLine();
writer.append("try").ws().append("{").indent().softNewLine();
writer.appendMethodBody(asyncRef).append('(');
ClassReader cls = context.getClassSource().get(methodRef.getClassName());
MethodReader method = cls.getMethod(methodRef.getDescriptor());
int start = method.hasModifier(ElementModifier.STATIC) ? 1 : 0;
for (int i = start; i <= methodRef.parameterCount(); ++i) {
writer.append(context.getParameterName(i));
writer.append(',').ws();
if (template == null) {
var templateFactory = new JavaScriptTemplateFactory(context.getClassLoader(), context.getClassSource());
template = templateFactory.createFromResource("org/teavm/platform/plugin/Async.js");
}
writer.append("callback);").softNewLine();
writer.outdent().append("}").ws().append("catch($e)").ws().append("{").indent().softNewLine();
writer.append("callback.").appendMethod(errorMethod).append("($rt_exception($e));")
.softNewLine();
writer.outdent().append("}").softNewLine();
writer.outdent().append("});").softNewLine();
writer.append("return null;").softNewLine();
MethodReference asyncRef = getAsyncReference(context.getClassSource(), methodRef);
template.builder("asyncMethod")
.withContext(context)
.withFragment("callMethod", (w, p) -> {
w.appendMethodBody(asyncRef).append('(');
ClassReader cls = context.getClassSource().get(methodRef.getClassName());
MethodReader method = cls.getMethod(methodRef.getDescriptor());
int start = method.hasModifier(ElementModifier.STATIC) ? 1 : 0;
for (int i = start; i <= methodRef.parameterCount(); ++i) {
w.append(context.getParameterName(i));
w.append(',').ws();
}
w.append("callback);").softNewLine();
})
.build()
.write(writer, 0);
}
private MethodReference getAsyncReference(ClassReaderSource classSource, MethodReference methodRef) {

View File

@ -22,6 +22,8 @@ import org.teavm.backend.javascript.spi.Generator;
import org.teavm.backend.javascript.spi.GeneratorContext;
import org.teavm.backend.javascript.spi.Injector;
import org.teavm.backend.javascript.spi.InjectorContext;
import org.teavm.backend.javascript.templating.JavaScriptTemplate;
import org.teavm.backend.javascript.templating.JavaScriptTemplateFactory;
import org.teavm.dependency.DependencyAgent;
import org.teavm.dependency.DependencyPlugin;
import org.teavm.dependency.MethodDependency;
@ -36,6 +38,8 @@ import org.teavm.platform.PlatformClass;
import org.teavm.platform.PlatformRunnable;
public class PlatformGenerator implements Generator, Injector, DependencyPlugin {
private JavaScriptTemplate template;
@Override
public void methodReached(DependencyAgent agent, MethodDependency method) {
switch (method.getReference().getName()) {
@ -90,37 +94,37 @@ public class PlatformGenerator implements Generator, Injector, DependencyPlugin
@Override
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException {
switch (methodRef.getName()) {
case "newInstanceImpl":
generateNewInstance(context, writer);
break;
case "prepareNewInstance":
generatePrepareNewInstance(context, writer);
break;
case "lookupClass":
generateLookup(context, writer);
break;
case "clone":
generateClone(context, writer);
break;
case "startThread":
generateSchedule(context, writer, false);
break;
case "schedule":
generateSchedule(context, writer, true);
break;
case "getEnumConstants":
generateEnumConstants(context, writer);
break;
case "getAnnotations":
generateAnnotations(context, writer);
break;
default:
generateWithTemplate(context, writer, methodRef);
break;
}
}
private void generateWithTemplate(GeneratorContext context, SourceWriter writer, MethodReference methodRef)
throws IOException {
if (template == null) {
template = new JavaScriptTemplateFactory(context.getClassLoader(), context.getClassSource())
.createFromResource("org/teavm/platform/plugin/Platform.js");
}
template.builder(methodRef.getName()).withContext(context).build().write(writer, 0);
}
private void generatePrepareNewInstance(GeneratorContext context, SourceWriter writer) throws IOException {
MethodDependencyInfo newInstanceMethod = context.getDependency().getMethod(
new MethodReference(Platform.class, "newInstanceImpl", PlatformClass.class, Object.class));
writer.append("var c").ws().append("=").ws().append("'$$constructor$$';").softNewLine();
writer.append("let c").ws().append("=").ws().append("'$$constructor$$';").softNewLine();
if (newInstanceMethod != null) {
for (String clsName : newInstanceMethod.getResult().getTypes()) {
ClassReader cls = context.getClassSource().get(clsName);
@ -136,71 +140,21 @@ public class PlatformGenerator implements Generator, Injector, DependencyPlugin
}
}
private void generateNewInstance(GeneratorContext context, SourceWriter writer) throws IOException {
String cls = context.getParameterName(1);
writer.append("if").ws().append("($rt_resuming())").ws().append("{").indent().softNewLine();
writer.append("var $r = $rt_nativeThread().pop();").softNewLine();
writer.append(cls + ".$$constructor$$($r);").softNewLine();
writer.append("if").ws().append("($rt_suspending())").ws().append("{").indent().softNewLine();
writer.append("return $rt_nativeThread().push($r);").softNewLine();
writer.outdent().append("}").softNewLine();
writer.append("return $r;").softNewLine();
writer.outdent().append("}").softNewLine();
writer.append("if").ws().append("(!").append(cls).append(".hasOwnProperty('$$constructor$$'))")
.ws().append("{").indent().softNewLine();
writer.append("return null;").softNewLine();
writer.outdent().append("}").softNewLine();
writer.append("var $r").ws().append('=').ws().append("new ").append(cls).append("();").softNewLine();
writer.append(cls).append(".$$constructor$$($r);").softNewLine();
writer.append("if").ws().append("($rt_suspending())").ws().append("{").indent().softNewLine();
writer.append("return $rt_nativeThread().push($r);").softNewLine();
writer.outdent().append("}").softNewLine();
writer.append("return $r;").softNewLine();
}
private void generateLookup(GeneratorContext context, SourceWriter writer) throws IOException {
String param = context.getParameterName(1);
writer.append("switch ($rt_ustr(" + param + ")) {").softNewLine().indent();
writer.append("switch").ws().append("(").appendFunction("$rt_ustr").append("(" + param + "))")
.ws().append("{").softNewLine().indent();
for (String name : context.getClassSource().getClassNames()) {
writer.append("case \"" + name + "\": ").appendClass(name).append(".$clinit(); ")
writer.append("case \"" + name + "\":").ws().appendClass(name).append(".$clinit();").ws()
.append("return ").appendClass(name).append(";").softNewLine();
}
writer.append("default: return null;").softNewLine();
writer.append("default:").ws().append("return null;").softNewLine();
writer.outdent().append("}").softNewLine();
}
private void generateClone(GeneratorContext context, SourceWriter writer) throws IOException {
String obj = context.getParameterName(1);
writer.append("var copy").ws().append("=").ws().append("new ").append(obj).append(".constructor();")
.softNewLine();
writer.append("for").ws().append("(var field in " + obj + ")").ws().append("{").softNewLine().indent();
writer.append("if").ws().append("(!" + obj + ".hasOwnProperty(field))").ws().append("{").softNewLine().indent();
writer.append("continue;").softNewLine().outdent().append("}").softNewLine();
writer.append("copy[field]").ws().append("=").ws().append(obj).append("[field];")
.softNewLine().outdent().append("}").softNewLine();
writer.append("return copy;").softNewLine();
}
private void generateSchedule(GeneratorContext context, SourceWriter writer, boolean timeout) throws IOException {
MethodReference launchRef = new MethodReference(Platform.class, "launchThread",
PlatformRunnable.class, void.class);
String runnable = context.getParameterName(1);
writer.append("return setTimeout(function()").ws().append("{").indent().softNewLine();
if (timeout) {
writer.appendMethodBody(launchRef);
} else {
writer.append("$rt_threadStarter(").appendMethodBody(launchRef).append(")");
}
writer.append("(").append(runnable).append(");").softNewLine();
writer.outdent().append("},").ws().append(timeout ? context.getParameterName(2) : "0")
.append(");").softNewLine();
}
private void generateEnumConstants(GeneratorContext context, SourceWriter writer) throws IOException {
writer.append("var c").ws().append("=").ws().append("'$$enumConstants$$';").softNewLine();
writer.append("let c").ws().append("=").ws().append("'$$enumConstants$$';").softNewLine();
for (String clsName : context.getClassSource().getClassNames()) {
ClassReader cls = context.getClassSource().get(clsName);
MethodReader method = cls.getMethod(new MethodDescriptor("values",
@ -214,8 +168,8 @@ public class PlatformGenerator implements Generator, Injector, DependencyPlugin
MethodReference selfRef = new MethodReference(Platform.class, "getEnumConstants",
PlatformClass.class, Enum[].class);
writer.appendMethodBody(selfRef).ws().append("=").ws().append("function(cls)").ws().append("{").softNewLine()
.indent();
writer.appendMethodBody(selfRef).ws().append("=").ws().append("cls").ws().append("=>").ws()
.append("{").softNewLine().indent();
writer.append("if").ws().append("(!cls.hasOwnProperty(c))").ws().append("{").indent().softNewLine();
writer.append("return null;").softNewLine();
writer.outdent().append("}").softNewLine();
@ -231,7 +185,7 @@ public class PlatformGenerator implements Generator, Injector, DependencyPlugin
}
private void generateAnnotations(GeneratorContext context, SourceWriter writer) throws IOException {
writer.append("var c").ws().append("=").ws().append("'$$annotations$$';").softNewLine();
writer.append("let c").ws().append("=").ws().append("'$$annotations$$';").softNewLine();
for (String clsName : context.getClassSource().getClassNames()) {
ClassReader annotCls = context.getClassSource().get(clsName + "$$__annotations__$$");
if (annotCls != null) {
@ -244,8 +198,8 @@ public class PlatformGenerator implements Generator, Injector, DependencyPlugin
MethodReference selfRef = new MethodReference(Platform.class, "getAnnotations", PlatformClass.class,
Annotation[].class);
writer.appendMethodBody(selfRef).ws().append("=").ws().append("function(cls)").ws().append("{").softNewLine()
.indent();
writer.appendMethodBody(selfRef).ws().append("=").ws().append("cls").ws().append("=>").ws()
.append("{").softNewLine().indent();
writer.append("if").ws().append("(!cls.hasOwnProperty(c))").ws().append("{").indent().softNewLine();
writer.append("return null;").softNewLine();
writer.outdent().append("}").softNewLine();

View File

@ -24,8 +24,9 @@ import org.teavm.model.MethodReference;
class ResourceAccessorGenerator implements Generator {
@Override
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException {
writer.append("var result = [];").softNewLine();
writer.append("for (var key in ").append(context.getParameterName(1)).append(") {").indent().softNewLine();
writer.append("let result").ws().append("=").ws().append("[];").softNewLine();
writer.append("for").ws().append("(let key in ").append(context.getParameterName(1)).append(")").ws()
.append("{").indent().softNewLine();
writer.append("result.push(key);").softNewLine();
writer.outdent().append("}").softNewLine();
writer.append("return result;").softNewLine();

View File

@ -95,7 +95,7 @@ class ResourceAccessorInjector implements Injector {
context.getWriter().append('(');
context.writeExpr(context.getArgument(0));
context.getWriter().ws().append("!==").ws().append("null").ws().append("?").ws();
context.getWriter().append("$rt_ustr(");
context.getWriter().appendFunction("$rt_ustr").append("(");
context.writeExpr(context.getArgument(0));
context.getWriter().append(")").ws().append(':').ws().append("null)");
break;
@ -114,7 +114,7 @@ class ResourceAccessorInjector implements Injector {
return;
}
}
context.getWriter().append("[$rt_ustr(");
context.getWriter().append("[").appendFunction("$rt_ustr").append("(");
context.writeExpr(property);
context.getWriter().append(")]");
}
@ -127,7 +127,7 @@ class ResourceAccessorInjector implements Injector {
context.getWriter().append('"');
return;
}
context.getWriter().append("$rt_ustr(");
context.getWriter().appendFunction("$rt_ustr").append("(");
context.writeExpr(expr);
context.getWriter().append(")");
}

View File

@ -0,0 +1,50 @@
/*
* Copyright 2023 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.
*/
function asyncMethod() {
let thread = $rt_nativeThread();
let javaThread = $rt_getThread();
if (thread.isResuming()) {
thread.status = 0;
let result = thread.attribute;
if (result instanceof teavm_globals.Error) {
throw result;
}
return result;
}
let callback = function() {};
callback[teavm_javaVirtualMethod("complete(Ljava/lang/Object;)V")] = val => {
thread.attribute = val;
$rt_setThread(javaThread);
thread.resume();
}
callback[teavm_javaVirtualMethod("error(Ljava/lang/Throwable;)V")] = e => {
thread.attribute = $rt_exception(e);
$rt_setThread(javaThread);
thread.resume();
}
callback = teavm_javaMethod("org.teavm.platform.plugin.AsyncCallbackWrapper",
"create(Lorg/teavm/interop/AsyncCallback;)Lorg/teavm/platform/plugin/AsyncCallbackWrapper;")(callback);
thread.suspend(() => {
try {
teavm_fragment("callMethod");
} catch ($e) {
callback[teavm_javaVirtualMethod("error(Ljava/lang/Throwable;)V")]($e);
}
});
return null;
}

View File

@ -0,0 +1,62 @@
/*
* Copyright 2023 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.
*/
function newInstanceImpl(cls) {
let thread = $rt_nativeThread();
if ($rt_resuming()) {
let r = thread.pop();
cls.$$constructor$$(r);
if ($rt_suspending()) {
return thread.push(r);
}
return r;
}
if (!cls.hasOwnProperty("$$constructor$$")) {
return null;
}
let r = new cls();
cls.$$constructor$$(r);
if ($rt_suspending()) {
thread.push(r);
}
return r;
}
function clone(obj) {
let copy = new obj.constructor();
for (let field in obj) {
if (obj.hasOwnProperty(field)) {
copy[field] = obj[field];
}
}
return copy;
}
function startThread(runnable) {
teavm_globals.setTimeout(() => {
$rt_threadStarter(teavm_javaMethod("org.teavm.platform.Platform",
"launchThread(Lorg/teavm/platform/PlatformRunnable;)V"))(runnable);
}, 0);
}
function schedule(runnable, timeout) {
teavm_globals.setTimeout(() => {
teavm_javaMethod("org.teavm.platform.Platform",
"launchThread(Lorg/teavm/platform/PlatformRunnable;)V")(runnable);
}, timeout);
}

View File

@ -65,8 +65,8 @@ class TestExceptionPlugin implements TeaVMPlugin {
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.append("return ").appendFunction("$rt_ustr").append("(this.")
.appendMethod("getMessage", String.class).append("());").softNewLine();
writer.outdent().append("};").newLine();
}
}