mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
Wasm backend: fix hanging tests, make more tests pass, change name generation scheme
This commit is contained in:
parent
b087610c2c
commit
a81eeeee03
|
@ -1,149 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2018 Alexey Andreev.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.teavm.ast;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import org.teavm.model.FieldReference;
|
|
||||||
import org.teavm.model.MethodDescriptor;
|
|
||||||
import org.teavm.model.MethodReference;
|
|
||||||
import org.teavm.model.ValueType;
|
|
||||||
|
|
||||||
public final class Mangling {
|
|
||||||
private Mangling() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String mangleIsSupertype(ValueType type) {
|
|
||||||
return "isSupertype$" + mangleType(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String mangleMethod(MethodReference method) {
|
|
||||||
String className = mangleClassBase(method.getClassName());
|
|
||||||
StringBuilder sb = new StringBuilder("method$" + className + "_");
|
|
||||||
mangleSignature(method.getDescriptor(), sb);
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String mangleVTableEntry(MethodDescriptor method) {
|
|
||||||
StringBuilder sb = new StringBuilder("m_");
|
|
||||||
mangleSignature(method, sb);
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void mangleSignature(MethodDescriptor method, StringBuilder sb) {
|
|
||||||
sb.append(mangleType(method.getResultType()));
|
|
||||||
sb.append(mangleString(method.getName()));
|
|
||||||
sb.append(Arrays.stream(method.getParameterTypes())
|
|
||||||
.map(Mangling::mangleType)
|
|
||||||
.collect(Collectors.joining()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String mangleField(FieldReference field) {
|
|
||||||
String className = mangleClassBase(field.getClassName());
|
|
||||||
return "field$" + className + "_" + field.getFieldName().length() + mangleString(field.getFieldName());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String mangleClass(String className) {
|
|
||||||
return "class$" + mangleClassBase(className);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String mangleClassObject(ValueType type) {
|
|
||||||
return "tobject$" + mangleType(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String mangleVtable(String className) {
|
|
||||||
return "vt$" + mangleClassBase(className);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String mangleClassBase(String className) {
|
|
||||||
return className.length() + mangleString(className);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String mangleInitializer(String className) {
|
|
||||||
return "clinit$" + mangleString(className);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String mangleInstanceOf(ValueType type) {
|
|
||||||
return "instanceof$" + mangleType(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String mangleString(String string) {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
for (int i = 0; i < string.length(); ++i) {
|
|
||||||
char c = string.charAt(i);
|
|
||||||
switch (c) {
|
|
||||||
case '$':
|
|
||||||
sb.append(c);
|
|
||||||
break;
|
|
||||||
case '.':
|
|
||||||
sb.append("_g");
|
|
||||||
break;
|
|
||||||
case '<':
|
|
||||||
sb.append("_h");
|
|
||||||
break;
|
|
||||||
case '>':
|
|
||||||
sb.append("_i");
|
|
||||||
break;
|
|
||||||
case '_':
|
|
||||||
sb.append("__");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z' || c >= '0' && c <= '9') {
|
|
||||||
sb.append(c);
|
|
||||||
} else {
|
|
||||||
sb.append('_')
|
|
||||||
.append(Character.forDigit(c >>> 12, 16))
|
|
||||||
.append(Character.forDigit((c >>> 8) & 0xF, 16))
|
|
||||||
.append(Character.forDigit((c >>> 4) & 0xF, 16))
|
|
||||||
.append(Character.forDigit(c & 0xF, 16));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String mangleType(ValueType type) {
|
|
||||||
if (type instanceof ValueType.Primitive) {
|
|
||||||
switch (((ValueType.Primitive) type).getKind()) {
|
|
||||||
case BOOLEAN:
|
|
||||||
return "Z";
|
|
||||||
case BYTE:
|
|
||||||
return "B";
|
|
||||||
case SHORT:
|
|
||||||
return "S";
|
|
||||||
case CHARACTER:
|
|
||||||
return "C";
|
|
||||||
case INTEGER:
|
|
||||||
return "I";
|
|
||||||
case LONG:
|
|
||||||
return "L";
|
|
||||||
case FLOAT:
|
|
||||||
return "F";
|
|
||||||
case DOUBLE:
|
|
||||||
return "D";
|
|
||||||
}
|
|
||||||
} else if (type instanceof ValueType.Void) {
|
|
||||||
return "V";
|
|
||||||
} else if (type instanceof ValueType.Array) {
|
|
||||||
return "A" + mangleType(((ValueType.Array) type).getItemType());
|
|
||||||
} else if (type instanceof ValueType.Object) {
|
|
||||||
String className = ((ValueType.Object) type).getClassName();
|
|
||||||
return className.length() + "_" + mangleString(className);
|
|
||||||
}
|
|
||||||
throw new IllegalArgumentException("Don't know how to mangle " + type);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -16,46 +16,17 @@
|
||||||
package org.teavm.backend.c.generate;
|
package org.teavm.backend.c.generate;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedHashSet;
|
import org.teavm.backend.lowlevel.generate.LowLevelNameProvider;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import org.teavm.interop.Export;
|
|
||||||
import org.teavm.interop.Import;
|
|
||||||
import org.teavm.model.AnnotationReader;
|
|
||||||
import org.teavm.model.ClassReaderSource;
|
import org.teavm.model.ClassReaderSource;
|
||||||
import org.teavm.model.FieldReference;
|
import org.teavm.model.FieldReference;
|
||||||
import org.teavm.model.MethodReader;
|
|
||||||
import org.teavm.model.MethodReference;
|
|
||||||
import org.teavm.model.ValueType;
|
|
||||||
import org.teavm.runtime.RuntimeArray;
|
import org.teavm.runtime.RuntimeArray;
|
||||||
import org.teavm.runtime.RuntimeClass;
|
import org.teavm.runtime.RuntimeClass;
|
||||||
import org.teavm.runtime.RuntimeObject;
|
import org.teavm.runtime.RuntimeObject;
|
||||||
|
|
||||||
public class NameProvider {
|
public class NameProvider extends LowLevelNameProvider {
|
||||||
private ClassReaderSource classSource;
|
|
||||||
|
|
||||||
private Set<String> occupiedTopLevelNames = new HashSet<>();
|
|
||||||
private Map<String, Set<String>> occupiedVtableNames = new HashMap<>();
|
|
||||||
private Map<String, Set<String>> occupiedClassNames = new HashMap<>();
|
|
||||||
|
|
||||||
private Map<MethodReference, String> methodNames = new HashMap<>();
|
|
||||||
private Map<MethodReference, String> virtualMethodNames = new HashMap<>();
|
|
||||||
|
|
||||||
private Map<FieldReference, String> staticFieldNames = new HashMap<>();
|
|
||||||
private Map<FieldReference, String> memberFieldNames = new HashMap<>();
|
|
||||||
|
|
||||||
private Map<String, String> classNames = new HashMap<>();
|
|
||||||
private Map<String, String> classInitializerNames = new HashMap<>();
|
|
||||||
private Map<String, String> classClassNames = new HashMap<>();
|
|
||||||
private Map<ValueType, String> classInstanceNames = new HashMap<>();
|
|
||||||
private Map<ValueType, String> supertypeNames = new HashMap<>();
|
|
||||||
|
|
||||||
private Set<ValueType> types = new LinkedHashSet<>();
|
|
||||||
|
|
||||||
public NameProvider(ClassReaderSource classSource) {
|
public NameProvider(ClassReaderSource classSource) {
|
||||||
this.classSource = classSource;
|
super(classSource);
|
||||||
|
|
||||||
occupiedTopLevelNames.add("JavaObject");
|
occupiedTopLevelNames.add("JavaObject");
|
||||||
occupiedTopLevelNames.add("JavaArray");
|
occupiedTopLevelNames.add("JavaArray");
|
||||||
|
@ -75,166 +46,4 @@ public class NameProvider {
|
||||||
occupiedClassNames.put(RuntimeObject.class.getName(), new HashSet<>(Arrays.asList("header")));
|
occupiedClassNames.put(RuntimeObject.class.getName(), new HashSet<>(Arrays.asList("header")));
|
||||||
occupiedClassNames.put(RuntimeArray.class.getName(), new HashSet<>(Arrays.asList("length")));
|
occupiedClassNames.put(RuntimeArray.class.getName(), new HashSet<>(Arrays.asList("length")));
|
||||||
}
|
}
|
||||||
|
|
||||||
public String forMethod(MethodReference method) {
|
|
||||||
return methodNames.computeIfAbsent(method, k -> {
|
|
||||||
String specialName = getSpecialName(k);
|
|
||||||
return specialName == null ? pickUnoccupied(suggestForMethod(k)) : specialName;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public String forVirtualMethod(MethodReference method) {
|
|
||||||
return virtualMethodNames.computeIfAbsent(method, k -> {
|
|
||||||
Set<String> occupied = occupiedVtableNames.computeIfAbsent(k.getClassName(),
|
|
||||||
c -> new HashSet<>(Arrays.asList("parent")));
|
|
||||||
return pickUnoccupied(k.getName(), occupied);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getSpecialName(MethodReference methodReference) {
|
|
||||||
MethodReader method = classSource.resolve(methodReference);
|
|
||||||
if (method == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
AnnotationReader exportAnnot = method.getAnnotations().get(Export.class.getName());
|
|
||||||
if (exportAnnot != null) {
|
|
||||||
return exportAnnot.getValue("name").getString();
|
|
||||||
}
|
|
||||||
|
|
||||||
AnnotationReader importAnnot = method.getAnnotations().get(Import.class.getName());
|
|
||||||
if (importAnnot != null) {
|
|
||||||
return importAnnot.getValue("name").getString();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String forStaticField(FieldReference field) {
|
|
||||||
return staticFieldNames.computeIfAbsent(field, k -> pickUnoccupied(suggestForStaticField(k)));
|
|
||||||
}
|
|
||||||
|
|
||||||
public String forMemberField(FieldReference field) {
|
|
||||||
return memberFieldNames.computeIfAbsent(field, k -> {
|
|
||||||
Set<String> occupied = occupiedClassNames.computeIfAbsent(k.getClassName(),
|
|
||||||
c -> new HashSet<>(Arrays.asList("parent")));
|
|
||||||
return pickUnoccupied(sanitize(field.getFieldName()), occupied);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public String forClass(String className) {
|
|
||||||
return classNames.computeIfAbsent(className, k -> pickUnoccupied(suggestForClass(k)));
|
|
||||||
}
|
|
||||||
|
|
||||||
public String forClassInitializer(String className) {
|
|
||||||
return classInitializerNames.computeIfAbsent(className, k -> pickUnoccupied("initclass_" + suggestForClass(k)));
|
|
||||||
}
|
|
||||||
|
|
||||||
public String forClassClass(String className) {
|
|
||||||
types.add(ValueType.object(className));
|
|
||||||
return classClassNames.computeIfAbsent(className, k -> pickUnoccupied(suggestForClass(k) + "_VT"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public String forClassInstance(ValueType type) {
|
|
||||||
types.add(type);
|
|
||||||
return classInstanceNames.computeIfAbsent(type, k -> pickUnoccupied(suggestForType(k) + "_Cls"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public String forSupertypeFunction(ValueType type) {
|
|
||||||
return supertypeNames.computeIfAbsent(type, k -> pickUnoccupied("supertypeof_" + suggestForType(k)));
|
|
||||||
}
|
|
||||||
|
|
||||||
private String suggestForMethod(MethodReference method) {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
suggestForClass(method.getClassName(), sb);
|
|
||||||
sb.append('_');
|
|
||||||
sb.append(sanitize(method.getName()));
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String suggestForStaticField(FieldReference field) {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
suggestForClass(field.getClassName(), sb);
|
|
||||||
sb.append('_');
|
|
||||||
sb.append(sanitize(field.getFieldName()));
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String suggestForClass(String className) {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
suggestForClass(className, sb);
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void suggestForClass(String className, StringBuilder sb) {
|
|
||||||
int index = 0;
|
|
||||||
while (true) {
|
|
||||||
int next = className.indexOf('.', index);
|
|
||||||
if (next < 0) {
|
|
||||||
if (index > 0) {
|
|
||||||
sb.append('_');
|
|
||||||
sb.append(sanitize(className.substring(index)));
|
|
||||||
} else {
|
|
||||||
sb.append(sanitize(className));
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
sb.append(sanitize(String.valueOf(className.charAt(index))));
|
|
||||||
index = next + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String suggestForType(ValueType type) {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
suggestForType(type, sb);
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void suggestForType(ValueType type, StringBuilder sb) {
|
|
||||||
if (type instanceof ValueType.Object) {
|
|
||||||
suggestForClass(((ValueType.Object) type).getClassName(), sb);
|
|
||||||
} else if (type instanceof ValueType.Array) {
|
|
||||||
sb.append("Arr_");
|
|
||||||
suggestForType(((ValueType.Array) type).getItemType(), sb);
|
|
||||||
} else {
|
|
||||||
sb.append(type.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String sanitize(String name) {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
for (int i = 0; i < name.length(); ++i) {
|
|
||||||
char c = name.charAt(i);
|
|
||||||
switch (c) {
|
|
||||||
case '>':
|
|
||||||
case '<':
|
|
||||||
case '$':
|
|
||||||
sb.append('_');
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
sb.append(c);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String pickUnoccupied(String name) {
|
|
||||||
return pickUnoccupied(name, occupiedTopLevelNames);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String pickUnoccupied(String name, Set<String> occupied) {
|
|
||||||
String result = name;
|
|
||||||
int index = 0;
|
|
||||||
while (!occupied.add(result)) {
|
|
||||||
result = name + "_" + index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<? extends ValueType> getTypes() {
|
|
||||||
return types;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,219 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Alexey Andreev.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.teavm.backend.lowlevel.generate;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import org.teavm.interop.Export;
|
||||||
|
import org.teavm.interop.Import;
|
||||||
|
import org.teavm.model.AnnotationReader;
|
||||||
|
import org.teavm.model.ClassReaderSource;
|
||||||
|
import org.teavm.model.FieldReference;
|
||||||
|
import org.teavm.model.MethodReader;
|
||||||
|
import org.teavm.model.MethodReference;
|
||||||
|
import org.teavm.model.ValueType;
|
||||||
|
|
||||||
|
public abstract class LowLevelNameProvider {
|
||||||
|
private ClassReaderSource classSource;
|
||||||
|
|
||||||
|
protected Set<String> occupiedTopLevelNames = new HashSet<>();
|
||||||
|
protected Map<String, Set<String>> occupiedVtableNames = new HashMap<>();
|
||||||
|
protected Map<String, Set<String>> occupiedClassNames = new HashMap<>();
|
||||||
|
|
||||||
|
protected Map<MethodReference, String> methodNames = new HashMap<>();
|
||||||
|
protected Map<MethodReference, String> virtualMethodNames = new HashMap<>();
|
||||||
|
|
||||||
|
protected Map<FieldReference, String> staticFieldNames = new HashMap<>();
|
||||||
|
protected Map<FieldReference, String> memberFieldNames = new HashMap<>();
|
||||||
|
|
||||||
|
protected Map<String, String> classNames = new HashMap<>();
|
||||||
|
protected Map<String, String> classInitializerNames = new HashMap<>();
|
||||||
|
protected Map<String, String> classClassNames = new HashMap<>();
|
||||||
|
protected Map<ValueType, String> classInstanceNames = new HashMap<>();
|
||||||
|
protected Map<ValueType, String> supertypeNames = new HashMap<>();
|
||||||
|
|
||||||
|
private Set<ValueType> types = new LinkedHashSet<>();
|
||||||
|
|
||||||
|
public LowLevelNameProvider(ClassReaderSource classSource) {
|
||||||
|
this.classSource = classSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String forMethod(MethodReference method) {
|
||||||
|
return methodNames.computeIfAbsent(method, k -> {
|
||||||
|
String specialName = getSpecialName(k);
|
||||||
|
return specialName == null ? pickUnoccupied(suggestForMethod(k)) : specialName;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public String forVirtualMethod(MethodReference method) {
|
||||||
|
return virtualMethodNames.computeIfAbsent(method, k -> {
|
||||||
|
Set<String> occupied = occupiedVtableNames.computeIfAbsent(k.getClassName(),
|
||||||
|
c -> new HashSet<>(Arrays.asList("parent")));
|
||||||
|
return pickUnoccupied(k.getName(), occupied);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getSpecialName(MethodReference methodReference) {
|
||||||
|
MethodReader method = classSource.resolve(methodReference);
|
||||||
|
if (method == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
AnnotationReader exportAnnot = method.getAnnotations().get(Export.class.getName());
|
||||||
|
if (exportAnnot != null) {
|
||||||
|
return exportAnnot.getValue("name").getString();
|
||||||
|
}
|
||||||
|
|
||||||
|
AnnotationReader importAnnot = method.getAnnotations().get(Import.class.getName());
|
||||||
|
if (importAnnot != null) {
|
||||||
|
return importAnnot.getValue("name").getString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String forStaticField(FieldReference field) {
|
||||||
|
return staticFieldNames.computeIfAbsent(field, k -> pickUnoccupied(suggestForStaticField(k)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String forMemberField(FieldReference field) {
|
||||||
|
return memberFieldNames.computeIfAbsent(field, k -> {
|
||||||
|
Set<String> occupied = occupiedClassNames.computeIfAbsent(k.getClassName(),
|
||||||
|
c -> new HashSet<>(Arrays.asList("parent")));
|
||||||
|
return pickUnoccupied(sanitize(field.getFieldName()), occupied);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public String forClass(String className) {
|
||||||
|
return classNames.computeIfAbsent(className, k -> pickUnoccupied(suggestForClass(k)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String forClassInitializer(String className) {
|
||||||
|
return classInitializerNames.computeIfAbsent(className, k -> pickUnoccupied("initclass_" + suggestForClass(k)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String forClassClass(String className) {
|
||||||
|
types.add(ValueType.object(className));
|
||||||
|
return classClassNames.computeIfAbsent(className, k -> pickUnoccupied(suggestForClass(k) + "_VT"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String forClassInstance(ValueType type) {
|
||||||
|
types.add(type);
|
||||||
|
return classInstanceNames.computeIfAbsent(type, k -> pickUnoccupied(suggestForType(k) + "_Cls"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String forSupertypeFunction(ValueType type) {
|
||||||
|
return supertypeNames.computeIfAbsent(type, k -> pickUnoccupied("supertypeof_" + suggestForType(k)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String suggestForMethod(MethodReference method) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
suggestForClass(method.getClassName(), sb);
|
||||||
|
sb.append('_');
|
||||||
|
sb.append(sanitize(method.getName()));
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String suggestForStaticField(FieldReference field) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
suggestForClass(field.getClassName(), sb);
|
||||||
|
sb.append('_');
|
||||||
|
sb.append(sanitize(field.getFieldName()));
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String suggestForClass(String className) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
suggestForClass(className, sb);
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void suggestForClass(String className, StringBuilder sb) {
|
||||||
|
int index = 0;
|
||||||
|
while (true) {
|
||||||
|
int next = className.indexOf('.', index);
|
||||||
|
if (next < 0) {
|
||||||
|
if (index > 0) {
|
||||||
|
sb.append('_');
|
||||||
|
sb.append(sanitize(className.substring(index)));
|
||||||
|
} else {
|
||||||
|
sb.append(sanitize(className));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.append(sanitize(String.valueOf(className.charAt(index))));
|
||||||
|
index = next + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String suggestForType(ValueType type) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
suggestForType(type, sb);
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void suggestForType(ValueType type, StringBuilder sb) {
|
||||||
|
if (type instanceof ValueType.Object) {
|
||||||
|
suggestForClass(((ValueType.Object) type).getClassName(), sb);
|
||||||
|
} else if (type instanceof ValueType.Array) {
|
||||||
|
sb.append("Arr_");
|
||||||
|
suggestForType(((ValueType.Array) type).getItemType(), sb);
|
||||||
|
} else {
|
||||||
|
sb.append(type.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String sanitize(String name) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (int i = 0; i < name.length(); ++i) {
|
||||||
|
char c = name.charAt(i);
|
||||||
|
switch (c) {
|
||||||
|
case '>':
|
||||||
|
case '<':
|
||||||
|
case '$':
|
||||||
|
sb.append('_');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sb.append(c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String pickUnoccupied(String name) {
|
||||||
|
return pickUnoccupied(name, occupiedTopLevelNames);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String pickUnoccupied(String name, Set<String> occupied) {
|
||||||
|
String result = name;
|
||||||
|
int index = 0;
|
||||||
|
while (!occupied.add(result)) {
|
||||||
|
result = name + "_" + index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<? extends ValueType> getTypes() {
|
||||||
|
return types;
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,9 +27,9 @@ import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import org.teavm.ast.Mangling;
|
|
||||||
import org.teavm.ast.decompilation.Decompiler;
|
import org.teavm.ast.decompilation.Decompiler;
|
||||||
import org.teavm.backend.wasm.binary.BinaryWriter;
|
import org.teavm.backend.wasm.binary.BinaryWriter;
|
||||||
|
import org.teavm.backend.wasm.generate.NameProvider;
|
||||||
import org.teavm.backend.wasm.generate.WasmClassGenerator;
|
import org.teavm.backend.wasm.generate.WasmClassGenerator;
|
||||||
import org.teavm.backend.wasm.generate.WasmDependencyListener;
|
import org.teavm.backend.wasm.generate.WasmDependencyListener;
|
||||||
import org.teavm.backend.wasm.generate.WasmGenerationContext;
|
import org.teavm.backend.wasm.generate.WasmGenerationContext;
|
||||||
|
@ -43,6 +43,7 @@ import org.teavm.backend.wasm.intrinsics.FunctionIntrinsic;
|
||||||
import org.teavm.backend.wasm.intrinsics.GCIntrinsic;
|
import org.teavm.backend.wasm.intrinsics.GCIntrinsic;
|
||||||
import org.teavm.backend.wasm.intrinsics.MutatorIntrinsic;
|
import org.teavm.backend.wasm.intrinsics.MutatorIntrinsic;
|
||||||
import org.teavm.backend.wasm.intrinsics.PlatformClassIntrinsic;
|
import org.teavm.backend.wasm.intrinsics.PlatformClassIntrinsic;
|
||||||
|
import org.teavm.backend.wasm.intrinsics.PlatformClassMetadataIntrinsic;
|
||||||
import org.teavm.backend.wasm.intrinsics.PlatformIntrinsic;
|
import org.teavm.backend.wasm.intrinsics.PlatformIntrinsic;
|
||||||
import org.teavm.backend.wasm.intrinsics.PlatformObjectIntrinsic;
|
import org.teavm.backend.wasm.intrinsics.PlatformObjectIntrinsic;
|
||||||
import org.teavm.backend.wasm.intrinsics.ShadowStackIntrinsic;
|
import org.teavm.backend.wasm.intrinsics.ShadowStackIntrinsic;
|
||||||
|
@ -132,6 +133,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
||||||
private boolean debugging;
|
private boolean debugging;
|
||||||
private boolean wastEmitted;
|
private boolean wastEmitted;
|
||||||
private boolean cEmitted;
|
private boolean cEmitted;
|
||||||
|
private boolean cLineNumbersEmitted = Boolean.parseBoolean(System.getProperty("wasm.c.lineNumbers", "false"));
|
||||||
private ClassInitializerInsertionTransformer clinitInsertionTransformer;
|
private ClassInitializerInsertionTransformer clinitInsertionTransformer;
|
||||||
private ClassInitializerEliminator classInitializerEliminator;
|
private ClassInitializerEliminator classInitializerEliminator;
|
||||||
private ClassInitializerTransformer classInitializerTransformer;
|
private ClassInitializerTransformer classInitializerTransformer;
|
||||||
|
@ -205,6 +207,10 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
||||||
this.cEmitted = cEmitted;
|
this.cEmitted = cEmitted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setCLineNumbersEmitted(boolean cLineNumbersEmitted) {
|
||||||
|
this.cLineNumbersEmitted = cLineNumbersEmitted;
|
||||||
|
}
|
||||||
|
|
||||||
public WasmBinaryVersion getVersion() {
|
public WasmBinaryVersion getVersion() {
|
||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
@ -297,14 +303,15 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
||||||
VirtualTableProvider vtableProvider = createVirtualTableProvider(classes);
|
VirtualTableProvider vtableProvider = createVirtualTableProvider(classes);
|
||||||
TagRegistry tagRegistry = new TagRegistry(classes);
|
TagRegistry tagRegistry = new TagRegistry(classes);
|
||||||
BinaryWriter binaryWriter = new BinaryWriter(256);
|
BinaryWriter binaryWriter = new BinaryWriter(256);
|
||||||
|
NameProvider names = new NameProvider(controller.getUnprocessedClassSource());
|
||||||
WasmClassGenerator classGenerator = new WasmClassGenerator(
|
WasmClassGenerator classGenerator = new WasmClassGenerator(
|
||||||
controller.getUnprocessedClassSource(), vtableProvider, tagRegistry, binaryWriter);
|
controller.getUnprocessedClassSource(), vtableProvider, tagRegistry, binaryWriter, names);
|
||||||
|
|
||||||
Decompiler decompiler = new Decompiler(classes, controller.getClassLoader(), new HashSet<>(),
|
Decompiler decompiler = new Decompiler(classes, controller.getClassLoader(), new HashSet<>(),
|
||||||
new HashSet<>(), false, true);
|
new HashSet<>(), false, true);
|
||||||
WasmStringPool stringPool = classGenerator.getStringPool();
|
WasmStringPool stringPool = classGenerator.getStringPool();
|
||||||
WasmGenerationContext context = new WasmGenerationContext(classes, module, controller.getDiagnostics(),
|
WasmGenerationContext context = new WasmGenerationContext(classes, module, controller.getDiagnostics(),
|
||||||
vtableProvider, tagRegistry, stringPool);
|
vtableProvider, tagRegistry, stringPool, names);
|
||||||
|
|
||||||
context.addIntrinsic(new AddressIntrinsic(classGenerator));
|
context.addIntrinsic(new AddressIntrinsic(classGenerator));
|
||||||
context.addIntrinsic(new StructureIntrinsic(classes, classGenerator));
|
context.addIntrinsic(new StructureIntrinsic(classes, classGenerator));
|
||||||
|
@ -315,6 +322,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
||||||
context.addIntrinsic(new PlatformIntrinsic());
|
context.addIntrinsic(new PlatformIntrinsic());
|
||||||
context.addIntrinsic(new PlatformClassIntrinsic());
|
context.addIntrinsic(new PlatformClassIntrinsic());
|
||||||
context.addIntrinsic(new PlatformObjectIntrinsic(classGenerator));
|
context.addIntrinsic(new PlatformObjectIntrinsic(classGenerator));
|
||||||
|
context.addIntrinsic(new PlatformClassMetadataIntrinsic());
|
||||||
context.addIntrinsic(new ClassIntrinsic());
|
context.addIntrinsic(new ClassIntrinsic());
|
||||||
|
|
||||||
IntrinsicFactoryContext intrinsicFactoryContext = new IntrinsicFactoryContext(classes);
|
IntrinsicFactoryContext intrinsicFactoryContext = new IntrinsicFactoryContext(classes);
|
||||||
|
@ -362,13 +370,13 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
||||||
if (clinit == null) {
|
if (clinit == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
initFunction.getBody().add(new WasmCall(Mangling.mangleInitializer(className)));
|
initFunction.getBody().add(new WasmCall(names.forClassInitializer(className)));
|
||||||
}
|
}
|
||||||
module.add(initFunction);
|
module.add(initFunction);
|
||||||
module.setStartFunction(initFunction);
|
module.setStartFunction(initFunction);
|
||||||
|
|
||||||
for (TeaVMEntryPoint entryPoint : controller.getEntryPoints().values()) {
|
for (TeaVMEntryPoint entryPoint : controller.getEntryPoints().values()) {
|
||||||
String mangledName = Mangling.mangleMethod(entryPoint.getReference());
|
String mangledName = names.forMethod(entryPoint.getReference());
|
||||||
WasmFunction function = module.getFunctions().get(mangledName);
|
WasmFunction function = module.getFunctions().get(mangledName);
|
||||||
if (function != null) {
|
if (function != null) {
|
||||||
function.setExportName(entryPoint.getPublicName());
|
function.setExportName(entryPoint.getPublicName());
|
||||||
|
@ -403,7 +411,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
||||||
emitWast(module, buildTarget, getBaseName(outputName) + ".wast");
|
emitWast(module, buildTarget, getBaseName(outputName) + ".wast");
|
||||||
}
|
}
|
||||||
if (cEmitted) {
|
if (cEmitted) {
|
||||||
emitC(module, buildTarget, getBaseName(outputName) + ".c");
|
emitC(module, buildTarget, getBaseName(outputName) + ".wasm.c");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -452,7 +460,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
||||||
|
|
||||||
private void emitC(WasmModule module, BuildTarget buildTarget, String outputName) throws IOException {
|
private void emitC(WasmModule module, BuildTarget buildTarget, String outputName) throws IOException {
|
||||||
WasmCRenderer renderer = new WasmCRenderer();
|
WasmCRenderer renderer = new WasmCRenderer();
|
||||||
renderer.setLineNumbersEmitted(Boolean.parseBoolean(System.getProperty("wasm.c.lineNumbers", "false")));
|
renderer.setLineNumbersEmitted(cLineNumbersEmitted);
|
||||||
renderer.setMemoryAccessChecked(Boolean.parseBoolean(System.getProperty("wasm.c.assertMemory", "false")));
|
renderer.setMemoryAccessChecked(Boolean.parseBoolean(System.getProperty("wasm.c.assertMemory", "false")));
|
||||||
renderer.render(module);
|
renderer.render(module);
|
||||||
try (OutputStream output = buildTarget.createResource(outputName);
|
try (OutputStream output = buildTarget.createResource(outputName);
|
||||||
|
@ -512,7 +520,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
||||||
if (method == implementor) {
|
if (method == implementor) {
|
||||||
generator.generate(method.getReference(), implementor);
|
generator.generate(method.getReference(), implementor);
|
||||||
} else {
|
} else {
|
||||||
generateStub(module, method, implementor);
|
generateStub(context.names, module, method, implementor);
|
||||||
}
|
}
|
||||||
if (controller.wasCancelled()) {
|
if (controller.wasCancelled()) {
|
||||||
return;
|
return;
|
||||||
|
@ -523,7 +531,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
||||||
private void generateIsSupertypeFunctions(TagRegistry tagRegistry, WasmModule module,
|
private void generateIsSupertypeFunctions(TagRegistry tagRegistry, WasmModule module,
|
||||||
WasmClassGenerator classGenerator) {
|
WasmClassGenerator classGenerator) {
|
||||||
for (ValueType type : classGenerator.getRegisteredClasses()) {
|
for (ValueType type : classGenerator.getRegisteredClasses()) {
|
||||||
WasmFunction function = new WasmFunction(Mangling.mangleIsSupertype(type));
|
WasmFunction function = new WasmFunction(classGenerator.names.forSupertypeFunction(type));
|
||||||
function.getParameters().add(WasmType.INT32);
|
function.getParameters().add(WasmType.INT32);
|
||||||
function.setResult(WasmType.INT32);
|
function.setResult(WasmType.INT32);
|
||||||
module.add(function);
|
module.add(function);
|
||||||
|
@ -573,7 +581,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
||||||
testLower.getThenBlock().getBody().add(new WasmReturn(new WasmInt32Constant(0)));
|
testLower.getThenBlock().getBody().add(new WasmReturn(new WasmInt32Constant(0)));
|
||||||
body.add(testLower);
|
body.add(testLower);
|
||||||
|
|
||||||
WasmExpression upperCondition = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.GT_SIGNED,
|
WasmExpression upperCondition = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.GE_SIGNED,
|
||||||
new WasmGetLocal(subtypeVar), new WasmInt32Constant(upper));
|
new WasmGetLocal(subtypeVar), new WasmInt32Constant(upper));
|
||||||
WasmConditional testUpper = new WasmConditional(upperCondition);
|
WasmConditional testUpper = new WasmConditional(upperCondition);
|
||||||
testUpper.getThenBlock().getBody().add(new WasmReturn(new WasmInt32Constant(0)));
|
testUpper.getThenBlock().getBody().add(new WasmReturn(new WasmInt32Constant(0)));
|
||||||
|
@ -615,17 +623,17 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
||||||
itemTest.setType(WasmType.INT32);
|
itemTest.setType(WasmType.INT32);
|
||||||
itemTest.getThenBlock().getBody().add(new WasmInt32Constant(0));
|
itemTest.getThenBlock().getBody().add(new WasmInt32Constant(0));
|
||||||
|
|
||||||
WasmCall delegateToItem = new WasmCall(Mangling.mangleIsSupertype(itemType));
|
WasmCall delegateToItem = new WasmCall(classGenerator.names.forSupertypeFunction(itemType));
|
||||||
delegateToItem.getArguments().add(new WasmGetLocal(subtypeVar));
|
delegateToItem.getArguments().add(new WasmGetLocal(subtypeVar));
|
||||||
itemTest.getElseBlock().getBody().add(delegateToItem);
|
itemTest.getElseBlock().getBody().add(delegateToItem);
|
||||||
|
|
||||||
body.add(new WasmReturn(itemTest));
|
body.add(new WasmReturn(itemTest));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void generateStub(WasmModule module, MethodHolder method, MethodHolder implementor) {
|
private void generateStub(NameProvider names, WasmModule module, MethodHolder method, MethodHolder implementor) {
|
||||||
WasmFunction function = module.getFunctions().get(Mangling.mangleMethod(method.getReference()));
|
WasmFunction function = module.getFunctions().get(names.forMethod(method.getReference()));
|
||||||
|
|
||||||
WasmCall call = new WasmCall(Mangling.mangleMethod(implementor.getReference()));
|
WasmCall call = new WasmCall(names.forMethod(implementor.getReference()));
|
||||||
for (WasmType param : function.getParameters()) {
|
for (WasmType param : function.getParameters()) {
|
||||||
WasmLocal local = new WasmLocal(param);
|
WasmLocal local = new WasmLocal(param);
|
||||||
function.add(local);
|
function.add(local);
|
||||||
|
@ -659,7 +667,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
WasmFunction initFunction = new WasmFunction(Mangling.mangleInitializer(className));
|
WasmFunction initFunction = new WasmFunction(classGenerator.names.forClassInitializer(className));
|
||||||
module.add(initFunction);
|
module.add(initFunction);
|
||||||
|
|
||||||
WasmBlock block = new WasmBlock(false);
|
WasmBlock block = new WasmBlock(false);
|
||||||
|
@ -679,7 +687,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
||||||
WasmInt32Subtype.INT32));
|
WasmInt32Subtype.INT32));
|
||||||
|
|
||||||
if (method != null) {
|
if (method != null) {
|
||||||
block.getBody().add(new WasmCall(Mangling.mangleMethod(method.getReference())));
|
block.getBody().add(new WasmCall(classGenerator.names.forMethod(method.getReference())));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (controller.wasCancelled()) {
|
if (controller.wasCancelled()) {
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Alexey Andreev.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.teavm.backend.wasm.generate;
|
||||||
|
|
||||||
|
import org.teavm.backend.lowlevel.generate.LowLevelNameProvider;
|
||||||
|
import org.teavm.model.ClassReaderSource;
|
||||||
|
|
||||||
|
public class NameProvider extends LowLevelNameProvider {
|
||||||
|
public NameProvider(ClassReaderSource classSource) {
|
||||||
|
super(classSource);
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,7 +24,6 @@ import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import org.teavm.ast.Mangling;
|
|
||||||
import org.teavm.backend.wasm.binary.BinaryWriter;
|
import org.teavm.backend.wasm.binary.BinaryWriter;
|
||||||
import org.teavm.backend.wasm.binary.DataArray;
|
import org.teavm.backend.wasm.binary.DataArray;
|
||||||
import org.teavm.backend.wasm.binary.DataPrimitives;
|
import org.teavm.backend.wasm.binary.DataPrimitives;
|
||||||
|
@ -52,6 +51,7 @@ import org.teavm.runtime.RuntimeObject;
|
||||||
|
|
||||||
public class WasmClassGenerator {
|
public class WasmClassGenerator {
|
||||||
private ClassReaderSource classSource;
|
private ClassReaderSource classSource;
|
||||||
|
public final NameProvider names;
|
||||||
private Map<ValueType, ClassBinaryData> binaryDataMap = new LinkedHashMap<>();
|
private Map<ValueType, ClassBinaryData> binaryDataMap = new LinkedHashMap<>();
|
||||||
private BinaryWriter binaryWriter;
|
private BinaryWriter binaryWriter;
|
||||||
private Map<MethodReference, Integer> functions = new HashMap<>();
|
private Map<MethodReference, Integer> functions = new HashMap<>();
|
||||||
|
@ -96,12 +96,13 @@ public class WasmClassGenerator {
|
||||||
private static final int CLASS_SIMPLE_NAME = 13;
|
private static final int CLASS_SIMPLE_NAME = 13;
|
||||||
|
|
||||||
public WasmClassGenerator(ClassReaderSource classSource, VirtualTableProvider vtableProvider,
|
public WasmClassGenerator(ClassReaderSource classSource, VirtualTableProvider vtableProvider,
|
||||||
TagRegistry tagRegistry, BinaryWriter binaryWriter) {
|
TagRegistry tagRegistry, BinaryWriter binaryWriter, NameProvider names) {
|
||||||
this.classSource = classSource;
|
this.classSource = classSource;
|
||||||
this.vtableProvider = vtableProvider;
|
this.vtableProvider = vtableProvider;
|
||||||
this.tagRegistry = tagRegistry;
|
this.tagRegistry = tagRegistry;
|
||||||
this.binaryWriter = binaryWriter;
|
this.binaryWriter = binaryWriter;
|
||||||
this.stringPool = new WasmStringPool(this, binaryWriter);
|
this.stringPool = new WasmStringPool(this, binaryWriter);
|
||||||
|
this.names = names;
|
||||||
}
|
}
|
||||||
|
|
||||||
public WasmStringPool getStringPool() {
|
public WasmStringPool getStringPool() {
|
||||||
|
@ -173,7 +174,7 @@ public class WasmClassGenerator {
|
||||||
binaryData.data.setAddress(CLASS_ITEM_TYPE, itemBinaryData.start);
|
binaryData.data.setAddress(CLASS_ITEM_TYPE, itemBinaryData.start);
|
||||||
binaryData.data.setInt(CLASS_IS_INSTANCE, functionTable.size());
|
binaryData.data.setInt(CLASS_IS_INSTANCE, functionTable.size());
|
||||||
binaryData.data.setInt(CLASS_CANARY, RuntimeClass.computeCanary(4, 0));
|
binaryData.data.setInt(CLASS_CANARY, RuntimeClass.computeCanary(4, 0));
|
||||||
functionTable.add(Mangling.mangleIsSupertype(type));
|
functionTable.add(names.forSupertypeFunction(type));
|
||||||
binaryData.data.setAddress(CLASS_SIMPLE_NAME, 0);
|
binaryData.data.setAddress(CLASS_SIMPLE_NAME, 0);
|
||||||
binaryData.data.setInt(CLASS_INIT, -1);
|
binaryData.data.setInt(CLASS_INIT, -1);
|
||||||
binaryData.start = binaryWriter.append(vtableSize > 0 ? wrapper : binaryData.data);
|
binaryData.start = binaryWriter.append(vtableSize > 0 ? wrapper : binaryData.data);
|
||||||
|
@ -189,7 +190,7 @@ public class WasmClassGenerator {
|
||||||
value.setInt(CLASS_IS_INSTANCE, functionTable.size());
|
value.setInt(CLASS_IS_INSTANCE, functionTable.size());
|
||||||
value.setAddress(CLASS_SIMPLE_NAME, 0);
|
value.setAddress(CLASS_SIMPLE_NAME, 0);
|
||||||
value.setInt(CLASS_INIT, -1);
|
value.setInt(CLASS_INIT, -1);
|
||||||
functionTable.add(Mangling.mangleIsSupertype(type));
|
functionTable.add(names.forSupertypeFunction(type));
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,7 +227,7 @@ public class WasmClassGenerator {
|
||||||
header.setInt(CLASS_CANARY, RuntimeClass.computeCanary(occupiedSize, tag));
|
header.setInt(CLASS_CANARY, RuntimeClass.computeCanary(occupiedSize, tag));
|
||||||
header.setAddress(CLASS_NAME, stringPool.getStringPointer(name));
|
header.setAddress(CLASS_NAME, stringPool.getStringPointer(name));
|
||||||
header.setInt(CLASS_IS_INSTANCE, functionTable.size());
|
header.setInt(CLASS_IS_INSTANCE, functionTable.size());
|
||||||
functionTable.add(Mangling.mangleIsSupertype(ValueType.object(name)));
|
functionTable.add(names.forSupertypeFunction(ValueType.object(name)));
|
||||||
header.setAddress(CLASS_PARENT, parentPtr);
|
header.setAddress(CLASS_PARENT, parentPtr);
|
||||||
|
|
||||||
if (vtable != null) {
|
if (vtable != null) {
|
||||||
|
@ -259,7 +260,7 @@ public class WasmClassGenerator {
|
||||||
if (cls != null && binaryData.start >= 0
|
if (cls != null && binaryData.start >= 0
|
||||||
&& cls.getMethod(new MethodDescriptor("<clinit>", ValueType.VOID)) != null) {
|
&& cls.getMethod(new MethodDescriptor("<clinit>", ValueType.VOID)) != null) {
|
||||||
header.setInt(CLASS_INIT, functionTable.size());
|
header.setInt(CLASS_INIT, functionTable.size());
|
||||||
functionTable.add(Mangling.mangleInitializer(name));
|
functionTable.add(names.forClassInitializer(name));
|
||||||
} else {
|
} else {
|
||||||
header.setInt(CLASS_INIT, -1);
|
header.setInt(CLASS_INIT, -1);
|
||||||
}
|
}
|
||||||
|
@ -340,7 +341,7 @@ public class WasmClassGenerator {
|
||||||
} else {
|
} else {
|
||||||
methodIndex = functions.computeIfAbsent(vtableEntry.getImplementor(), implementor -> {
|
methodIndex = functions.computeIfAbsent(vtableEntry.getImplementor(), implementor -> {
|
||||||
int result = functionTable.size();
|
int result = functionTable.size();
|
||||||
functionTable.add(Mangling.mangleMethod(implementor));
|
functionTable.add(names.forMethod(implementor));
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,18 +43,21 @@ public class WasmGenerationContext {
|
||||||
private VirtualTableProvider vtableProvider;
|
private VirtualTableProvider vtableProvider;
|
||||||
private TagRegistry tagRegistry;
|
private TagRegistry tagRegistry;
|
||||||
private WasmStringPool stringPool;
|
private WasmStringPool stringPool;
|
||||||
|
public final NameProvider names;
|
||||||
private Map<MethodReference, ImportedMethod> importedMethods = new HashMap<>();
|
private Map<MethodReference, ImportedMethod> importedMethods = new HashMap<>();
|
||||||
private List<WasmIntrinsic> intrinsics = new ArrayList<>();
|
private List<WasmIntrinsic> intrinsics = new ArrayList<>();
|
||||||
private Map<MethodReference, WasmIntrinsicHolder> intrinsicCache = new HashMap<>();
|
private Map<MethodReference, WasmIntrinsicHolder> intrinsicCache = new HashMap<>();
|
||||||
|
|
||||||
public WasmGenerationContext(ClassReaderSource classSource, WasmModule module, Diagnostics diagnostics,
|
public WasmGenerationContext(ClassReaderSource classSource, WasmModule module, Diagnostics diagnostics,
|
||||||
VirtualTableProvider vtableProvider, TagRegistry tagRegistry, WasmStringPool stringPool) {
|
VirtualTableProvider vtableProvider, TagRegistry tagRegistry, WasmStringPool stringPool,
|
||||||
|
NameProvider names) {
|
||||||
this.classSource = classSource;
|
this.classSource = classSource;
|
||||||
this.module = module;
|
this.module = module;
|
||||||
this.diagnostics = diagnostics;
|
this.diagnostics = diagnostics;
|
||||||
this.vtableProvider = vtableProvider;
|
this.vtableProvider = vtableProvider;
|
||||||
this.tagRegistry = tagRegistry;
|
this.tagRegistry = tagRegistry;
|
||||||
this.stringPool = stringPool;
|
this.stringPool = stringPool;
|
||||||
|
this.names = names;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addIntrinsic(WasmIntrinsic intrinsic) {
|
public void addIntrinsic(WasmIntrinsic intrinsic) {
|
||||||
|
|
|
@ -42,7 +42,6 @@ import org.teavm.ast.InitClassStatement;
|
||||||
import org.teavm.ast.InstanceOfExpr;
|
import org.teavm.ast.InstanceOfExpr;
|
||||||
import org.teavm.ast.InvocationExpr;
|
import org.teavm.ast.InvocationExpr;
|
||||||
import org.teavm.ast.InvocationType;
|
import org.teavm.ast.InvocationType;
|
||||||
import org.teavm.ast.Mangling;
|
|
||||||
import org.teavm.ast.MonitorEnterStatement;
|
import org.teavm.ast.MonitorEnterStatement;
|
||||||
import org.teavm.ast.MonitorExitStatement;
|
import org.teavm.ast.MonitorExitStatement;
|
||||||
import org.teavm.ast.NewArrayExpr;
|
import org.teavm.ast.NewArrayExpr;
|
||||||
|
@ -185,7 +184,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
default:
|
default:
|
||||||
Class<?> type = convertType(expr.getType());
|
Class<?> type = convertType(expr.getType());
|
||||||
MethodReference method = new MethodReference(WasmRuntime.class, "remainder", type, type, type);
|
MethodReference method = new MethodReference(WasmRuntime.class, "remainder", type, type, type);
|
||||||
WasmCall call = new WasmCall(Mangling.mangleMethod(method), false);
|
WasmCall call = new WasmCall(context.names.forMethod(method), false);
|
||||||
|
|
||||||
accept(expr.getFirstOperand());
|
accept(expr.getFirstOperand());
|
||||||
call.getArguments().add(result);
|
call.getArguments().add(result);
|
||||||
|
@ -239,7 +238,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
case COMPARE: {
|
case COMPARE: {
|
||||||
Class<?> type = convertType(expr.getType());
|
Class<?> type = convertType(expr.getType());
|
||||||
MethodReference method = new MethodReference(WasmRuntime.class, "compare", type, type, int.class);
|
MethodReference method = new MethodReference(WasmRuntime.class, "compare", type, type, int.class);
|
||||||
WasmCall call = new WasmCall(Mangling.mangleMethod(method), false);
|
WasmCall call = new WasmCall(context.names.forMethod(method), false);
|
||||||
|
|
||||||
accept(expr.getFirstOperand());
|
accept(expr.getFirstOperand());
|
||||||
call.getArguments().add(result);
|
call.getArguments().add(result);
|
||||||
|
@ -912,7 +911,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (expr.getType() == InvocationType.STATIC || expr.getType() == InvocationType.SPECIAL) {
|
if (expr.getType() == InvocationType.STATIC || expr.getType() == InvocationType.SPECIAL) {
|
||||||
String methodName = Mangling.mangleMethod(expr.getMethod());
|
String methodName = context.names.forMethod(expr.getMethod());
|
||||||
|
|
||||||
WasmCall call = new WasmCall(methodName);
|
WasmCall call = new WasmCall(methodName);
|
||||||
if (context.getImportedMethod(expr.getMethod()) != null) {
|
if (context.getImportedMethod(expr.getMethod()) != null) {
|
||||||
|
@ -931,7 +930,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
block.getBody().add(new WasmSetLocal(tmp, allocateObject(expr.getMethod().getClassName(),
|
block.getBody().add(new WasmSetLocal(tmp, allocateObject(expr.getMethod().getClassName(),
|
||||||
expr.getLocation())));
|
expr.getLocation())));
|
||||||
|
|
||||||
String methodName = Mangling.mangleMethod(expr.getMethod());
|
String methodName = context.names.forMethod(expr.getMethod());
|
||||||
WasmCall call = new WasmCall(methodName);
|
WasmCall call = new WasmCall(methodName);
|
||||||
call.getArguments().add(new WasmGetLocal(tmp));
|
call.getArguments().add(new WasmGetLocal(tmp));
|
||||||
for (Expr argument : expr.getArguments()) {
|
for (Expr argument : expr.getArguments()) {
|
||||||
|
@ -1201,7 +1200,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
|
|
||||||
private WasmExpression allocateObject(String className, TextLocation location) {
|
private WasmExpression allocateObject(String className, TextLocation location) {
|
||||||
int tag = classGenerator.getClassPointer(ValueType.object(className));
|
int tag = classGenerator.getClassPointer(ValueType.object(className));
|
||||||
String allocName = Mangling.mangleMethod(new MethodReference(Allocator.class, "allocate",
|
String allocName = context.names.forMethod(new MethodReference(Allocator.class, "allocate",
|
||||||
RuntimeClass.class, Address.class));
|
RuntimeClass.class, Address.class));
|
||||||
WasmCall call = new WasmCall(allocName);
|
WasmCall call = new WasmCall(allocName);
|
||||||
call.getArguments().add(new WasmInt32Constant(tag));
|
call.getArguments().add(new WasmInt32Constant(tag));
|
||||||
|
@ -1214,7 +1213,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
ValueType type = expr.getType();
|
ValueType type = expr.getType();
|
||||||
|
|
||||||
int classPointer = classGenerator.getClassPointer(ValueType.arrayOf(type));
|
int classPointer = classGenerator.getClassPointer(ValueType.arrayOf(type));
|
||||||
String allocName = Mangling.mangleMethod(new MethodReference(Allocator.class, "allocateArray",
|
String allocName = context.names.forMethod(new MethodReference(Allocator.class, "allocateArray",
|
||||||
RuntimeClass.class, int.class, Address.class));
|
RuntimeClass.class, int.class, Address.class));
|
||||||
WasmCall call = new WasmCall(allocName);
|
WasmCall call = new WasmCall(allocName);
|
||||||
call.getArguments().add(new WasmInt32Constant(classPointer));
|
call.getArguments().add(new WasmInt32Constant(classPointer));
|
||||||
|
@ -1244,7 +1243,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
int classPointer = classGenerator.getClassPointer(ValueType.arrayOf(type));
|
int classPointer = classGenerator.getClassPointer(ValueType.arrayOf(type));
|
||||||
String allocName = Mangling.mangleMethod(new MethodReference(Allocator.class, "allocateMultiArray",
|
String allocName = context.names.forMethod(new MethodReference(Allocator.class, "allocateMultiArray",
|
||||||
RuntimeClass.class, Address.class, int.class, RuntimeArray.class));
|
RuntimeClass.class, Address.class, int.class, RuntimeArray.class));
|
||||||
WasmCall call = new WasmCall(allocName);
|
WasmCall call = new WasmCall(allocName);
|
||||||
call.getArguments().add(new WasmInt32Constant(classPointer));
|
call.getArguments().add(new WasmInt32Constant(classPointer));
|
||||||
|
@ -1345,7 +1344,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
@Override
|
@Override
|
||||||
public void visit(InitClassStatement statement) {
|
public void visit(InitClassStatement statement) {
|
||||||
if (classGenerator.hasClinit(statement.getClassName())) {
|
if (classGenerator.hasClinit(statement.getClassName())) {
|
||||||
result = new WasmCall(Mangling.mangleInitializer(statement.getClassName()));
|
result = new WasmCall(context.names.forClassInitializer(statement.getClassName()));
|
||||||
result.setLocation(statement.getLocation());
|
result.setLocation(statement.getLocation());
|
||||||
} else {
|
} else {
|
||||||
result = null;
|
result = null;
|
||||||
|
@ -1378,10 +1377,12 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(MonitorEnterStatement statement) {
|
public void visit(MonitorEnterStatement statement) {
|
||||||
|
result = emptyStatement(statement.getLocation());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(MonitorExitStatement statement) {
|
public void visit(MonitorExitStatement statement) {
|
||||||
|
result = emptyStatement(statement.getLocation());
|
||||||
}
|
}
|
||||||
|
|
||||||
private WasmExpression negate(WasmExpression expr) {
|
private WasmExpression negate(WasmExpression expr) {
|
||||||
|
@ -1546,6 +1547,11 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
public Diagnostics getDiagnostics() {
|
public Diagnostics getDiagnostics() {
|
||||||
return context.getDiagnostics();
|
return context.getDiagnostics();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NameProvider getNames() {
|
||||||
|
return context.names;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private WasmLocal getTemporary(WasmType type) {
|
private WasmLocal getTemporary(WasmType type) {
|
||||||
|
@ -1568,4 +1574,10 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
return new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.SHL, classIndex,
|
return new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.SHL, classIndex,
|
||||||
new WasmInt32Constant(3));
|
new WasmInt32Constant(3));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private WasmExpression emptyStatement(TextLocation location) {
|
||||||
|
WasmDrop drop = new WasmDrop(new WasmInt32Constant(0));
|
||||||
|
drop.setLocation(location);
|
||||||
|
return drop;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.backend.wasm.generate;
|
package org.teavm.backend.wasm.generate;
|
||||||
|
|
||||||
import org.teavm.ast.Mangling;
|
|
||||||
import org.teavm.ast.RegularMethodNode;
|
import org.teavm.ast.RegularMethodNode;
|
||||||
import org.teavm.ast.VariableNode;
|
import org.teavm.ast.VariableNode;
|
||||||
import org.teavm.ast.decompilation.Decompiler;
|
import org.teavm.ast.decompilation.Decompiler;
|
||||||
|
@ -39,6 +38,7 @@ public class WasmGenerator {
|
||||||
private WasmGenerationContext context;
|
private WasmGenerationContext context;
|
||||||
private WasmClassGenerator classGenerator;
|
private WasmClassGenerator classGenerator;
|
||||||
private BinaryWriter binaryWriter;
|
private BinaryWriter binaryWriter;
|
||||||
|
private NameProvider names;
|
||||||
|
|
||||||
public WasmGenerator(Decompiler decompiler, ClassHolderSource classSource,
|
public WasmGenerator(Decompiler decompiler, ClassHolderSource classSource,
|
||||||
WasmGenerationContext context, WasmClassGenerator classGenerator, BinaryWriter binaryWriter) {
|
WasmGenerationContext context, WasmClassGenerator classGenerator, BinaryWriter binaryWriter) {
|
||||||
|
@ -47,12 +47,13 @@ public class WasmGenerator {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.classGenerator = classGenerator;
|
this.classGenerator = classGenerator;
|
||||||
this.binaryWriter = binaryWriter;
|
this.binaryWriter = binaryWriter;
|
||||||
|
names = classGenerator.names;
|
||||||
}
|
}
|
||||||
|
|
||||||
public WasmFunction generateDefinition(MethodReference methodReference) {
|
public WasmFunction generateDefinition(MethodReference methodReference) {
|
||||||
ClassHolder cls = classSource.get(methodReference.getClassName());
|
ClassHolder cls = classSource.get(methodReference.getClassName());
|
||||||
MethodHolder method = cls.getMethod(methodReference.getDescriptor());
|
MethodHolder method = cls.getMethod(methodReference.getDescriptor());
|
||||||
WasmFunction function = new WasmFunction(Mangling.mangleMethod(method.getReference()));
|
WasmFunction function = new WasmFunction(names.forMethod(method.getReference()));
|
||||||
|
|
||||||
if (!method.hasModifier(ElementModifier.STATIC)) {
|
if (!method.hasModifier(ElementModifier.STATIC)) {
|
||||||
function.getParameters().add(WasmType.INT32);
|
function.getParameters().add(WasmType.INT32);
|
||||||
|
@ -72,7 +73,7 @@ public class WasmGenerator {
|
||||||
MethodHolder method = cls.getMethod(methodReference.getDescriptor());
|
MethodHolder method = cls.getMethod(methodReference.getDescriptor());
|
||||||
|
|
||||||
RegularMethodNode methodAst = decompiler.decompileRegular(bodyMethod);
|
RegularMethodNode methodAst = decompiler.decompileRegular(bodyMethod);
|
||||||
WasmFunction function = context.getFunction(Mangling.mangleMethod(methodReference));
|
WasmFunction function = context.getFunction(names.forMethod(methodReference));
|
||||||
int firstVariable = method.hasModifier(ElementModifier.STATIC) ? 1 : 0;
|
int firstVariable = method.hasModifier(ElementModifier.STATIC) ? 1 : 0;
|
||||||
for (int i = firstVariable; i < methodAst.getVariables().size(); ++i) {
|
for (int i = firstVariable; i < methodAst.getVariables().size(); ++i) {
|
||||||
VariableNode variable = methodAst.getVariables().get(i);
|
VariableNode variable = methodAst.getVariables().get(i);
|
||||||
|
@ -99,7 +100,7 @@ public class WasmGenerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
public WasmFunction generateNative(MethodReference methodReference) {
|
public WasmFunction generateNative(MethodReference methodReference) {
|
||||||
WasmFunction function = context.getFunction(Mangling.mangleMethod(methodReference));
|
WasmFunction function = context.getFunction(names.forMethod(methodReference));
|
||||||
|
|
||||||
WasmGenerationContext.ImportedMethod importedMethod = context.getImportedMethod(methodReference);
|
WasmGenerationContext.ImportedMethod importedMethod = context.getImportedMethod(methodReference);
|
||||||
if (importedMethod != null) {
|
if (importedMethod != null) {
|
||||||
|
|
|
@ -18,7 +18,6 @@ package org.teavm.backend.wasm.intrinsics;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import org.teavm.ast.ConstantExpr;
|
import org.teavm.ast.ConstantExpr;
|
||||||
import org.teavm.ast.InvocationExpr;
|
import org.teavm.ast.InvocationExpr;
|
||||||
import org.teavm.ast.Mangling;
|
|
||||||
import org.teavm.backend.wasm.WasmRuntime;
|
import org.teavm.backend.wasm.WasmRuntime;
|
||||||
import org.teavm.backend.wasm.generate.WasmClassGenerator;
|
import org.teavm.backend.wasm.generate.WasmClassGenerator;
|
||||||
import org.teavm.backend.wasm.model.WasmType;
|
import org.teavm.backend.wasm.model.WasmType;
|
||||||
|
@ -154,7 +153,7 @@ public class AddressIntrinsic implements WasmIntrinsic {
|
||||||
case "align": {
|
case "align": {
|
||||||
MethodReference delegate = new MethodReference(WasmRuntime.class.getName(),
|
MethodReference delegate = new MethodReference(WasmRuntime.class.getName(),
|
||||||
invocation.getMethod().getDescriptor());
|
invocation.getMethod().getDescriptor());
|
||||||
WasmCall call = new WasmCall(Mangling.mangleMethod(delegate));
|
WasmCall call = new WasmCall(manager.getNames().forMethod(delegate));
|
||||||
call.getArguments().addAll(invocation.getArguments().stream()
|
call.getArguments().addAll(invocation.getArguments().stream()
|
||||||
.map(arg -> manager.generate(arg))
|
.map(arg -> manager.generate(arg))
|
||||||
.collect(Collectors.toList()));
|
.collect(Collectors.toList()));
|
||||||
|
|
|
@ -17,7 +17,6 @@ package org.teavm.backend.wasm.intrinsics;
|
||||||
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import org.teavm.ast.InvocationExpr;
|
import org.teavm.ast.InvocationExpr;
|
||||||
import org.teavm.ast.Mangling;
|
|
||||||
import org.teavm.backend.wasm.WasmRuntime;
|
import org.teavm.backend.wasm.WasmRuntime;
|
||||||
import org.teavm.backend.wasm.generate.WasmClassGenerator;
|
import org.teavm.backend.wasm.generate.WasmClassGenerator;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmCall;
|
import org.teavm.backend.wasm.model.expression.WasmCall;
|
||||||
|
@ -63,7 +62,7 @@ public class AllocatorIntrinsic implements WasmIntrinsic {
|
||||||
case "moveMemoryBlock": {
|
case "moveMemoryBlock": {
|
||||||
MethodReference delegateMethod = new MethodReference(WasmRuntime.class.getName(),
|
MethodReference delegateMethod = new MethodReference(WasmRuntime.class.getName(),
|
||||||
invocation.getMethod().getDescriptor());
|
invocation.getMethod().getDescriptor());
|
||||||
WasmCall call = new WasmCall(Mangling.mangleMethod(delegateMethod));
|
WasmCall call = new WasmCall(manager.getNames().forMethod(delegateMethod));
|
||||||
call.getArguments().addAll(invocation.getArguments().stream()
|
call.getArguments().addAll(invocation.getArguments().stream()
|
||||||
.map(manager::generate)
|
.map(manager::generate)
|
||||||
.collect(Collectors.toList()));
|
.collect(Collectors.toList()));
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Alexey Andreev.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.teavm.backend.wasm.intrinsics;
|
||||||
|
|
||||||
|
import org.teavm.ast.InvocationExpr;
|
||||||
|
import org.teavm.ast.QualificationExpr;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmUnreachable;
|
||||||
|
import org.teavm.model.FieldReference;
|
||||||
|
import org.teavm.model.MethodReference;
|
||||||
|
import org.teavm.runtime.RuntimeClass;
|
||||||
|
|
||||||
|
public class PlatformClassMetadataIntrinsic implements WasmIntrinsic {
|
||||||
|
private static final String PLATFORM_CLASS_METADATA = "org.teavm.platform.PlatformClassMetadata";
|
||||||
|
private static final FieldReference ITEM_TYPE_FIELD = new FieldReference(
|
||||||
|
RuntimeClass.class.getName(), "itemType");
|
||||||
|
private static final FieldReference SUPERCLASS_FIELD = new FieldReference(
|
||||||
|
RuntimeClass.class.getName(), "parent");
|
||||||
|
private static final FieldReference NAME_FIELD = new FieldReference(
|
||||||
|
RuntimeClass.class.getName(), "name");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isApplicable(MethodReference methodReference) {
|
||||||
|
if (!methodReference.getClassName().equals(PLATFORM_CLASS_METADATA)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
switch (methodReference.getName()) {
|
||||||
|
case "getArrayItem":
|
||||||
|
case "getSuperclass":
|
||||||
|
case "getName":
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WasmExpression apply(InvocationExpr invocation, WasmIntrinsicManager manager) {
|
||||||
|
switch (invocation.getMethod().getName()) {
|
||||||
|
case "getArrayItem":
|
||||||
|
return fieldAccess(manager, invocation, ITEM_TYPE_FIELD);
|
||||||
|
case "getSuperclass":
|
||||||
|
return fieldAccess(manager, invocation, SUPERCLASS_FIELD);
|
||||||
|
case "getName":
|
||||||
|
return fieldAccess(manager, invocation, NAME_FIELD);
|
||||||
|
default:
|
||||||
|
return new WasmUnreachable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private WasmExpression fieldAccess(WasmIntrinsicManager manager, InvocationExpr expr, FieldReference field) {
|
||||||
|
QualificationExpr qualification = new QualificationExpr();
|
||||||
|
qualification.setField(field);
|
||||||
|
qualification.setQualified(expr.getArguments().get(0));
|
||||||
|
qualification.setLocation(expr.getLocation());
|
||||||
|
return manager.generate(qualification);
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,6 +17,7 @@ package org.teavm.backend.wasm.intrinsics;
|
||||||
|
|
||||||
import org.teavm.ast.Expr;
|
import org.teavm.ast.Expr;
|
||||||
import org.teavm.backend.wasm.binary.BinaryWriter;
|
import org.teavm.backend.wasm.binary.BinaryWriter;
|
||||||
|
import org.teavm.backend.wasm.generate.NameProvider;
|
||||||
import org.teavm.backend.wasm.generate.WasmStringPool;
|
import org.teavm.backend.wasm.generate.WasmStringPool;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||||
import org.teavm.diagnostics.Diagnostics;
|
import org.teavm.diagnostics.Diagnostics;
|
||||||
|
@ -29,4 +30,6 @@ public interface WasmIntrinsicManager {
|
||||||
WasmStringPool getStringPool();
|
WasmStringPool getStringPool();
|
||||||
|
|
||||||
Diagnostics getDiagnostics();
|
Diagnostics getDiagnostics();
|
||||||
|
|
||||||
|
NameProvider getNames();
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,9 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.backend.wasm.render;
|
package org.teavm.backend.wasm.render;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.teavm.backend.wasm.model.WasmFunction;
|
import org.teavm.backend.wasm.model.WasmFunction;
|
||||||
|
@ -65,10 +68,7 @@ public class WasmCRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void render(WasmModule module) {
|
public void render(WasmModule module) {
|
||||||
line("#include <inttypes.h>");
|
renderPrologue();
|
||||||
line("#include <string.h>");
|
|
||||||
line("#include <stdlib.h>");
|
|
||||||
line("#include <assert.h>");
|
|
||||||
line("");
|
line("");
|
||||||
|
|
||||||
renderFunctionDeclarations(module);
|
renderFunctionDeclarations(module);
|
||||||
|
@ -100,6 +100,22 @@ public class WasmCRenderer {
|
||||||
line("}");
|
line("}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void renderPrologue() {
|
||||||
|
ClassLoader classLoader = WasmCRenderer.class.getClassLoader();
|
||||||
|
try (BufferedReader reader = new BufferedReader(new InputStreamReader(
|
||||||
|
classLoader.getResourceAsStream("org/teavm/backend/wasm/wasm-runtime.c")))) {
|
||||||
|
while (true) {
|
||||||
|
String line = reader.readLine();
|
||||||
|
if (line == null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
line(line);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void renderHeap(WasmModule module) {
|
private void renderHeap(WasmModule module) {
|
||||||
line("wasm_heap_size = " + 65536 * module.getMemorySize() + ";");
|
line("wasm_heap_size = " + 65536 * module.getMemorySize() + ";");
|
||||||
line("wasm_heap = malloc(" + 65536 * module.getMemorySize() + ");");
|
line("wasm_heap = malloc(" + 65536 * module.getMemorySize() + ");");
|
||||||
|
@ -143,7 +159,9 @@ public class WasmCRenderer {
|
||||||
|
|
||||||
private void renderFunctionDeclarations(WasmModule module) {
|
private void renderFunctionDeclarations(WasmModule module) {
|
||||||
for (WasmFunction function : module.getFunctions().values()) {
|
for (WasmFunction function : module.getFunctions().values()) {
|
||||||
line(functionDeclaration(function) + ";");
|
if (function.getImportName() == null) {
|
||||||
|
line(functionDeclaration(function) + ";");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
#include <wctype.h>
|
||||||
|
|
||||||
|
static inline float TeaVM_getNaN() {
|
||||||
|
return NAN;
|
||||||
|
}
|
|
@ -104,14 +104,14 @@ function launchWasmTest(path, callback) {
|
||||||
case "SUCCESS":
|
case "SUCCESS":
|
||||||
callback({status: "OK"});
|
callback({status: "OK"});
|
||||||
break;
|
break;
|
||||||
case "FAILED":
|
case "FAILURE":
|
||||||
callback({
|
callback({
|
||||||
status: "failed",
|
status: "failed",
|
||||||
errorMessage: output.join("\n")
|
errorMessage: output.join("\n")
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
output.push(TeaVM_outputBuffer);
|
output.push(outputBuffer);
|
||||||
outputBuffer = "";
|
outputBuffer = "";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -95,6 +95,8 @@ interface TeaVMTestConfiguration<T extends TeaVMTarget> {
|
||||||
public void apply(WasmTarget target) {
|
public void apply(WasmTarget target) {
|
||||||
target.setMinHeapSize(32 * 1024 * 1024);
|
target.setMinHeapSize(32 * 1024 * 1024);
|
||||||
target.setWastEmitted(true);
|
target.setWastEmitted(true);
|
||||||
|
target.setCEmitted(true);
|
||||||
|
target.setDebugging(true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user