mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
Add support of virtual method invocation
This commit is contained in:
parent
45993091e4
commit
fe5aca5139
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* Copyright 2016 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.teavm.model.classes;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.teavm.model.ClassReader;
|
||||
import org.teavm.model.ClassReaderSource;
|
||||
import org.teavm.model.ElementModifier;
|
||||
import org.teavm.model.ListableClassReaderSource;
|
||||
|
||||
public class InterfaceToClassMapping {
|
||||
private Map<String, String> map = new HashMap<>();
|
||||
|
||||
public InterfaceToClassMapping(ListableClassReaderSource classSource) {
|
||||
for (String className : classSource.getClassNames()) {
|
||||
ClassReader cls = classSource.get(className);
|
||||
if (cls.hasModifier(ElementModifier.INTERFACE)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
map.put(className, className);
|
||||
for (String iface : getInterfaces(classSource, className)) {
|
||||
String existing = map.get(iface);
|
||||
if (existing == null) {
|
||||
map.put(iface, className);
|
||||
} else {
|
||||
map.put(iface, commonSuperClass(classSource, className, existing));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Set<String> getInterfaces(ClassReaderSource classSource, String className) {
|
||||
Set<String> interfaces = new HashSet<>();
|
||||
getInterfaces(classSource, className, interfaces);
|
||||
return interfaces;
|
||||
}
|
||||
|
||||
private static void getInterfaces(ClassReaderSource classSource, String className, Set<String> interfaces) {
|
||||
if (!interfaces.add(className)) {
|
||||
return;
|
||||
}
|
||||
ClassReader cls = classSource.get(className);
|
||||
if (cls == null) {
|
||||
return;
|
||||
}
|
||||
for (String iface : cls.getInterfaces()) {
|
||||
getInterfaces(classSource, iface, interfaces);
|
||||
}
|
||||
}
|
||||
|
||||
private static String commonSuperClass(ClassReaderSource classSource, String a, String b) {
|
||||
if (a.equals(b)) {
|
||||
return a;
|
||||
}
|
||||
|
||||
List<String> firstPath = pathToRoot(classSource, a);
|
||||
List<String> secondPath = pathToRoot(classSource, b);
|
||||
Collections.reverse(firstPath);
|
||||
Collections.reverse(secondPath);
|
||||
int min = Math.min(firstPath.size(), secondPath.size());
|
||||
for (int i = 1; i < min; ++i) {
|
||||
if (!firstPath.get(i).equals(secondPath.get(i))) {
|
||||
return firstPath.get(i - 1);
|
||||
}
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
private static List<String> pathToRoot(ClassReaderSource classSource, String className) {
|
||||
List<String> path = new ArrayList<>();
|
||||
while (true) {
|
||||
path.add(className);
|
||||
ClassReader cls = classSource.get(className);
|
||||
if (cls == null || cls.getParent() == null) {
|
||||
break;
|
||||
}
|
||||
className = cls.getParent();
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
public String mapClass(String className) {
|
||||
return map.get(className);
|
||||
}
|
||||
}
|
42
core/src/main/java/org/teavm/model/classes/VirtualTable.java
Normal file
42
core/src/main/java/org/teavm/model/classes/VirtualTable.java
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright 2016 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.teavm.model.classes;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import org.teavm.model.MethodDescriptor;
|
||||
|
||||
public class VirtualTable {
|
||||
private String className;
|
||||
Map<MethodDescriptor, VirtualTableEntry> entries = new LinkedHashMap<>();
|
||||
private Map<MethodDescriptor, VirtualTableEntry> readonlyEntries;
|
||||
|
||||
VirtualTable(String className) {
|
||||
this.className = className;
|
||||
}
|
||||
|
||||
public String getClassName() {
|
||||
return className;
|
||||
}
|
||||
|
||||
public Map<MethodDescriptor, VirtualTableEntry> getEntries() {
|
||||
if (readonlyEntries == null) {
|
||||
readonlyEntries = Collections.unmodifiableMap(entries);
|
||||
}
|
||||
return readonlyEntries;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright 2016 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.teavm.model.classes;
|
||||
|
||||
import org.teavm.model.MethodDescriptor;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
public class VirtualTableEntry {
|
||||
private VirtualTable virtualTable;
|
||||
private MethodDescriptor method;
|
||||
MethodReference implementor;
|
||||
private int index;
|
||||
|
||||
VirtualTableEntry(VirtualTable virtualTable, MethodDescriptor method, MethodReference implementor, int index) {
|
||||
this.virtualTable = virtualTable;
|
||||
this.method = method;
|
||||
this.implementor = implementor;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
public VirtualTable getVirtualTable() {
|
||||
return virtualTable;
|
||||
}
|
||||
|
||||
public MethodDescriptor getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
public MethodReference getImplementor() {
|
||||
return implementor;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Copyright 2016 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.teavm.model.classes;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.teavm.model.ClassReader;
|
||||
import org.teavm.model.ClassReaderSource;
|
||||
import org.teavm.model.ListableClassReaderSource;
|
||||
import org.teavm.model.MethodDescriptor;
|
||||
import org.teavm.model.MethodReader;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
public class VirtualTableProvider {
|
||||
private ClassReaderSource classSource;
|
||||
private Map<String, Set<MethodDescriptor>> virtualMethodMap = new HashMap<>();
|
||||
private Map<String, VirtualTable> virtualTables = new LinkedHashMap<>();
|
||||
private InterfaceToClassMapping interfaceMapping;
|
||||
|
||||
public VirtualTableProvider(ListableClassReaderSource classSource, Set<MethodReference> virtualMethods) {
|
||||
this.classSource = classSource;
|
||||
interfaceMapping = new InterfaceToClassMapping(classSource);
|
||||
|
||||
for (MethodReference virtualMethod : virtualMethods) {
|
||||
String cls = interfaceMapping.mapClass(virtualMethod.getClassName());
|
||||
virtualMethodMap.computeIfAbsent(cls, c -> new HashSet<>()).add(virtualMethod.getDescriptor());
|
||||
}
|
||||
|
||||
for (String className : classSource.getClassNames()) {
|
||||
fillClass(className);
|
||||
}
|
||||
}
|
||||
|
||||
private void fillClass(String className) {
|
||||
if (virtualTables.containsKey(className)) {
|
||||
return;
|
||||
}
|
||||
|
||||
VirtualTable table = new VirtualTable(className);
|
||||
virtualTables.put(className, table);
|
||||
ClassReader cls = classSource.get(className);
|
||||
if (cls.getParent() != null) {
|
||||
fillClass(cls.getParent());
|
||||
VirtualTable parentTable = virtualTables.get(cls.getParent());
|
||||
for (VirtualTableEntry parentEntry : parentTable.entries.values()) {
|
||||
VirtualTableEntry entry = new VirtualTableEntry(table, parentEntry.getMethod(),
|
||||
parentEntry.getImplementor(), parentEntry.getIndex());
|
||||
table.entries.put(entry.getMethod(), entry);
|
||||
}
|
||||
}
|
||||
|
||||
Set<MethodDescriptor> newDescriptors = virtualMethodMap.get(className);
|
||||
if (newDescriptors != null) {
|
||||
for (MethodDescriptor method : newDescriptors) {
|
||||
table.entries.put(method, new VirtualTableEntry(table, method, null, table.entries.size()));
|
||||
}
|
||||
}
|
||||
|
||||
for (MethodReader method : cls.getMethods()) {
|
||||
VirtualTableEntry entry = table.entries.get(method.getDescriptor());
|
||||
if (entry != null) {
|
||||
entry.implementor = method.getReference();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public VirtualTableEntry lookup(MethodReference method) {
|
||||
VirtualTable vtable = virtualTables.get(interfaceMapping.mapClass(method.getClassName()));
|
||||
if (vtable == null) {
|
||||
return null;
|
||||
}
|
||||
return vtable.getEntries().get(method.getDescriptor());
|
||||
}
|
||||
|
||||
public VirtualTable lookup(String className) {
|
||||
return virtualTables.get(interfaceMapping.mapClass(className));
|
||||
}
|
||||
}
|
|
@ -25,10 +25,6 @@ import org.teavm.model.*;
|
|||
import org.teavm.model.instructions.*;
|
||||
import org.teavm.model.util.ModelUtils;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public class ClassRefsRenamer implements InstructionVisitor {
|
||||
private Mapper<String, String> classNameMapper;
|
||||
|
||||
|
@ -49,6 +45,9 @@ public class ClassRefsRenamer implements InstructionVisitor {
|
|||
}
|
||||
}
|
||||
renamedCls.setParent(parent != null ? classNameMapper.map(parent) : null);
|
||||
if (renamedCls.getName().equals(renamedCls.getParent())) {
|
||||
renamedCls.setParent(null);
|
||||
}
|
||||
for (MethodHolder method : cls.getMethods()) {
|
||||
if (method.getAnnotations().get(Remove.class.getName()) != null) {
|
||||
continue;
|
||||
|
|
|
@ -28,7 +28,7 @@ public final class Allocator {
|
|||
Address result = address;
|
||||
address = result.add(tag.size);
|
||||
RuntimeObject object = result.toStructure();
|
||||
object.classInfo = tag;
|
||||
object.classReference = tag.toAddress().toInt() >> 3;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,5 +18,5 @@ package org.teavm.runtime;
|
|||
import org.teavm.interop.Structure;
|
||||
|
||||
public class RuntimeObject extends Structure {
|
||||
public RuntimeClass classInfo;
|
||||
public int classReference;
|
||||
}
|
||||
|
|
|
@ -29,6 +29,23 @@ public final class Example {
|
|||
WasmRuntime.print(a);
|
||||
}
|
||||
WasmRuntime.print(new A(2).getValue() + new A(3).getValue());
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
WasmRuntime.print(instance(i).foo());
|
||||
}
|
||||
}
|
||||
|
||||
private static Base instance(int index) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
return new Derived1();
|
||||
case 1:
|
||||
return new Derived2();
|
||||
case 2:
|
||||
return new Derived3();
|
||||
default:
|
||||
return new Derived4();
|
||||
}
|
||||
}
|
||||
|
||||
private static class A {
|
||||
|
@ -42,4 +59,32 @@ public final class Example {
|
|||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
interface Base {
|
||||
int foo();
|
||||
}
|
||||
|
||||
static class Derived1 implements Base {
|
||||
@Override
|
||||
public int foo() {
|
||||
return 234;
|
||||
}
|
||||
}
|
||||
|
||||
static class Derived2 implements Base {
|
||||
@Override
|
||||
public int foo() {
|
||||
return 345;
|
||||
}
|
||||
}
|
||||
|
||||
static class Derived3 extends Derived2 {
|
||||
}
|
||||
|
||||
static class Derived4 extends Derived1 {
|
||||
@Override
|
||||
public int foo() {
|
||||
return 123;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,22 +24,29 @@ import java.util.Arrays;
|
|||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.teavm.ast.decompilation.Decompiler;
|
||||
import org.teavm.dependency.DependencyChecker;
|
||||
import org.teavm.interop.Address;
|
||||
import org.teavm.interop.Import;
|
||||
import org.teavm.interop.StaticInit;
|
||||
import org.teavm.interop.Structure;
|
||||
import org.teavm.model.BasicBlock;
|
||||
import org.teavm.model.CallLocation;
|
||||
import org.teavm.model.ClassHolder;
|
||||
import org.teavm.model.ClassReader;
|
||||
import org.teavm.model.ElementModifier;
|
||||
import org.teavm.model.Instruction;
|
||||
import org.teavm.model.ListableClassHolderSource;
|
||||
import org.teavm.model.ListableClassReaderSource;
|
||||
import org.teavm.model.MethodDescriptor;
|
||||
import org.teavm.model.MethodHolder;
|
||||
import org.teavm.model.MethodReader;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.Program;
|
||||
import org.teavm.model.classes.VirtualTableProvider;
|
||||
import org.teavm.model.instructions.InvocationType;
|
||||
import org.teavm.model.instructions.InvokeInstruction;
|
||||
import org.teavm.runtime.Allocator;
|
||||
import org.teavm.runtime.RuntimeClass;
|
||||
import org.teavm.vm.BuildTarget;
|
||||
|
@ -109,7 +116,8 @@ public class WasmTarget implements TeaVMTarget {
|
|||
public void emit(ListableClassHolderSource classes, OutputStream output, BuildTarget buildTarget) {
|
||||
int address = 256;
|
||||
|
||||
WasmClassGenerator classGenerator = new WasmClassGenerator(classes, address);
|
||||
VirtualTableProvider vtableProvider = createVirtualTableProvider(classes);
|
||||
WasmClassGenerator classGenerator = new WasmClassGenerator(classes, vtableProvider, address);
|
||||
for (String className : classes.getClassNames()) {
|
||||
classGenerator.addClass(className);
|
||||
if (controller.wasCancelled()) {
|
||||
|
@ -120,7 +128,7 @@ public class WasmTarget implements TeaVMTarget {
|
|||
|
||||
Decompiler decompiler = new Decompiler(classes, controller.getClassLoader(), new HashSet<>(),
|
||||
new HashSet<>());
|
||||
WasmGenerationContext context = new WasmGenerationContext(classes);
|
||||
WasmGenerationContext context = new WasmGenerationContext(classes, vtableProvider);
|
||||
context.addIntrinsic(new WasmRuntimeIntrinsic());
|
||||
WasmGenerator generator = new WasmGenerator(decompiler, classes, context, classGenerator);
|
||||
|
||||
|
@ -168,7 +176,7 @@ public class WasmTarget implements TeaVMTarget {
|
|||
}
|
||||
|
||||
WasmFunction initFunction = new WasmFunction("__start__");
|
||||
classGenerator.contributeToInitializer(initFunction.getBody());
|
||||
classGenerator.contributeToInitializer(initFunction.getBody(), module);
|
||||
for (String className : classes.getClassNames()) {
|
||||
ClassReader cls = classes.get(className);
|
||||
if (cls.getAnnotations().get(StaticInit.class.getName()) == null) {
|
||||
|
@ -181,6 +189,7 @@ public class WasmTarget implements TeaVMTarget {
|
|||
initFunction.getBody().add(new WasmCall(WasmMangling.mangleMethod(clinit.getReference())));
|
||||
}
|
||||
module.add(initFunction);
|
||||
module.setStartFunction(initFunction);
|
||||
|
||||
for (TeaVMEntryPoint entryPoint : controller.getEntryPoints().values()) {
|
||||
String mangledName = WasmMangling.mangleMethod(entryPoint.getReference());
|
||||
|
@ -253,6 +262,33 @@ public class WasmTarget implements TeaVMTarget {
|
|||
module.add(function);
|
||||
}
|
||||
|
||||
private VirtualTableProvider createVirtualTableProvider(ListableClassHolderSource classes) {
|
||||
Set<MethodReference> virtualMethods = new HashSet<>();
|
||||
|
||||
for (String className : classes.getClassNames()) {
|
||||
ClassHolder cls = classes.get(className);
|
||||
for (MethodHolder method : cls.getMethods()) {
|
||||
Program program = method.getProgram();
|
||||
if (program == null) {
|
||||
continue;
|
||||
}
|
||||
for (int i = 0; i < program.basicBlockCount(); ++i) {
|
||||
BasicBlock block = program.basicBlockAt(i);
|
||||
for (Instruction insn : block.getInstructions()) {
|
||||
if (insn instanceof InvokeInstruction) {
|
||||
InvokeInstruction invoke = (InvokeInstruction) insn;
|
||||
if (invoke.getType() == InvocationType.VIRTUAL) {
|
||||
virtualMethods.add(invoke.getMethod());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new VirtualTableProvider(classes, virtualMethods);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
TeaVM vm = new TeaVMBuilder(new WasmTarget()).build();
|
||||
vm.installPlugins();
|
||||
|
|
|
@ -17,6 +17,7 @@ package org.teavm.wasm.generate;
|
|||
|
||||
import com.carrotsearch.hppc.ObjectIntMap;
|
||||
import com.carrotsearch.hppc.ObjectIntOpenHashMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -27,7 +28,12 @@ import org.teavm.model.ClassReaderSource;
|
|||
import org.teavm.model.ElementModifier;
|
||||
import org.teavm.model.FieldReader;
|
||||
import org.teavm.model.FieldReference;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.model.classes.VirtualTable;
|
||||
import org.teavm.model.classes.VirtualTableEntry;
|
||||
import org.teavm.model.classes.VirtualTableProvider;
|
||||
import org.teavm.wasm.model.WasmModule;
|
||||
import org.teavm.wasm.model.expression.WasmExpression;
|
||||
import org.teavm.wasm.model.expression.WasmInt32Constant;
|
||||
import org.teavm.wasm.model.expression.WasmInt32Subtype;
|
||||
|
@ -37,9 +43,11 @@ public class WasmClassGenerator {
|
|||
private ClassReaderSource classSource;
|
||||
private int address;
|
||||
private Map<String, ClassBinaryData> binaryDataMap = new LinkedHashMap<>();
|
||||
private VirtualTableProvider vtableProvider;
|
||||
|
||||
public WasmClassGenerator(ClassReaderSource classSource, int address) {
|
||||
public WasmClassGenerator(ClassReaderSource classSource, VirtualTableProvider vtableProvider, int address) {
|
||||
this.classSource = classSource;
|
||||
this.vtableProvider = vtableProvider;
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
|
@ -56,8 +64,11 @@ public class WasmClassGenerator {
|
|||
if (binaryData.start < 0) {
|
||||
return;
|
||||
}
|
||||
binaryData.start = align(address, 4);
|
||||
binaryData.end = binaryData.start + 8;
|
||||
|
||||
binaryData.start = align(address, 8);
|
||||
binaryData.vtable = vtableProvider.lookup(className);
|
||||
int vtableSize = binaryData.vtable != null ? binaryData.vtable.getEntries().size() : 0;
|
||||
binaryData.end = binaryData.start + 8 + vtableSize * 4;
|
||||
|
||||
address = binaryData.end;
|
||||
}
|
||||
|
@ -66,7 +77,9 @@ public class WasmClassGenerator {
|
|||
return address;
|
||||
}
|
||||
|
||||
public void contributeToInitializer(List<WasmExpression> initializer) {
|
||||
public void contributeToInitializer(List<WasmExpression> initializer, WasmModule module) {
|
||||
Map<MethodReference, Integer> functions = new HashMap<>();
|
||||
|
||||
for (ClassBinaryData binaryData : binaryDataMap.values()) {
|
||||
if (binaryData.start < 0) {
|
||||
continue;
|
||||
|
@ -74,6 +87,26 @@ public class WasmClassGenerator {
|
|||
WasmExpression index = new WasmInt32Constant(binaryData.start);
|
||||
WasmExpression size = new WasmInt32Constant(binaryData.size);
|
||||
initializer.add(new WasmStoreInt32(4, index, size, WasmInt32Subtype.INT32));
|
||||
|
||||
if (binaryData.vtable != null) {
|
||||
for (VirtualTableEntry vtableEntry : binaryData.vtable.getEntries().values()) {
|
||||
index = new WasmInt32Constant(binaryData.start + 8 + vtableEntry.getIndex() * 4);
|
||||
int methodIndex;
|
||||
if (vtableEntry.getImplementor() == null) {
|
||||
methodIndex = -1;
|
||||
} else {
|
||||
methodIndex = functions.computeIfAbsent(vtableEntry.getImplementor(), implementor -> {
|
||||
int result = module.getFunctionTable().size();
|
||||
String name = WasmMangling.mangleMethod(implementor);
|
||||
module.getFunctionTable().add(module.getFunctions().get(name));
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
WasmExpression methodIndexExpr = new WasmInt32Constant(methodIndex);
|
||||
initializer.add(new WasmStoreInt32(4, index, methodIndexExpr, WasmInt32Subtype.INT32));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -122,6 +155,9 @@ public class WasmClassGenerator {
|
|||
}
|
||||
|
||||
private static int align(int base, int alignment) {
|
||||
if (base == 0) {
|
||||
return 0;
|
||||
}
|
||||
return ((base - 1) / alignment + 1) * alignment;
|
||||
}
|
||||
|
||||
|
@ -149,6 +185,7 @@ public class WasmClassGenerator {
|
|||
int start;
|
||||
int end;
|
||||
|
||||
VirtualTable vtable;
|
||||
int size;
|
||||
ObjectIntMap<String> fieldLayout = new ObjectIntOpenHashMap<>();
|
||||
}
|
||||
|
|
|
@ -29,16 +29,19 @@ import org.teavm.model.FieldReference;
|
|||
import org.teavm.model.MethodReader;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.model.classes.VirtualTableProvider;
|
||||
import org.teavm.wasm.intrinsics.WasmIntrinsic;
|
||||
|
||||
public class WasmGenerationContext {
|
||||
private ClassReaderSource classSource;
|
||||
private VirtualTableProvider vtableProvider;
|
||||
private Map<MethodReference, ImportedMethod> importedMethods = new HashMap<>();
|
||||
private List<WasmIntrinsic> intrinsics = new ArrayList<>();
|
||||
private Map<MethodReference, WasmIntrinsic> intrinsicCache = new HashMap<>();
|
||||
|
||||
public WasmGenerationContext(ClassReaderSource classSource) {
|
||||
public WasmGenerationContext(ClassReaderSource classSource, VirtualTableProvider vtableProvider) {
|
||||
this.classSource = classSource;
|
||||
this.vtableProvider = vtableProvider;
|
||||
}
|
||||
|
||||
public void addIntrinsic(WasmIntrinsic intrinsic) {
|
||||
|
@ -86,6 +89,10 @@ public class WasmGenerationContext {
|
|||
return field.getType();
|
||||
}
|
||||
|
||||
public VirtualTableProvider getVirtualTableProvider() {
|
||||
return vtableProvider;
|
||||
}
|
||||
|
||||
public class ImportedMethod {
|
||||
public final String name;
|
||||
public final String module;
|
||||
|
|
|
@ -15,10 +15,8 @@
|
|||
*/
|
||||
package org.teavm.wasm.generate;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.teavm.ast.AssignmentStatement;
|
||||
|
@ -60,13 +58,16 @@ import org.teavm.ast.UnwrapArrayExpr;
|
|||
import org.teavm.ast.VariableExpr;
|
||||
import org.teavm.ast.WhileStatement;
|
||||
import org.teavm.interop.Address;
|
||||
import org.teavm.interop.Structure;
|
||||
import org.teavm.model.ClassReader;
|
||||
import org.teavm.model.FieldReference;
|
||||
import org.teavm.model.MethodDescriptor;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.model.classes.VirtualTableEntry;
|
||||
import org.teavm.runtime.Allocator;
|
||||
import org.teavm.runtime.RuntimeClass;
|
||||
import org.teavm.wasm.WasmRuntime;
|
||||
import org.teavm.wasm.intrinsics.WasmIntrinsic;
|
||||
import org.teavm.wasm.intrinsics.WasmIntrinsicManager;
|
||||
import org.teavm.wasm.model.WasmFunction;
|
||||
|
@ -86,6 +87,7 @@ import org.teavm.wasm.model.expression.WasmFloatBinary;
|
|||
import org.teavm.wasm.model.expression.WasmFloatBinaryOperation;
|
||||
import org.teavm.wasm.model.expression.WasmFloatType;
|
||||
import org.teavm.wasm.model.expression.WasmGetLocal;
|
||||
import org.teavm.wasm.model.expression.WasmIndirectCall;
|
||||
import org.teavm.wasm.model.expression.WasmInt32Constant;
|
||||
import org.teavm.wasm.model.expression.WasmInt32Subtype;
|
||||
import org.teavm.wasm.model.expression.WasmInt64Constant;
|
||||
|
@ -104,7 +106,6 @@ import org.teavm.wasm.model.expression.WasmStoreFloat64;
|
|||
import org.teavm.wasm.model.expression.WasmStoreInt32;
|
||||
import org.teavm.wasm.model.expression.WasmStoreInt64;
|
||||
import org.teavm.wasm.model.expression.WasmSwitch;
|
||||
import org.teavm.wasm.WasmRuntime;
|
||||
|
||||
class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||
private WasmGenerationContext context;
|
||||
|
@ -116,6 +117,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
private Map<IdentifiedStatement, WasmBlock> breakTargets = new HashMap<>();
|
||||
private Map<IdentifiedStatement, WasmBlock> continueTargets = new HashMap<>();
|
||||
private Set<WasmBlock> usedBlocks = new HashSet<>();
|
||||
private int temporaryInt32 = -1;
|
||||
WasmExpression result;
|
||||
|
||||
WasmGenerationVisitor(WasmGenerationContext context, WasmClassGenerator classGenerator,
|
||||
|
@ -486,36 +488,42 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
|
||||
@Override
|
||||
public void visit(SwitchStatement statement) {
|
||||
List<WasmBlock> wrappers = new ArrayList<>();
|
||||
WasmBlock defaultBlock = new WasmBlock(false);
|
||||
|
||||
breakTargets.put(statement, defaultBlock);
|
||||
IdentifiedStatement oldBreakTarget = currentBreakTarget;
|
||||
currentBreakTarget = statement;
|
||||
|
||||
WasmBlock wrapper = new WasmBlock(false);
|
||||
statement.getValue().acceptVisitor(this);
|
||||
WasmSwitch wasmSwitch = new WasmSwitch(result, wrapper);
|
||||
wrapper.getBody().add(wasmSwitch);
|
||||
|
||||
WasmBlock defaultBlock = new WasmBlock(false);
|
||||
defaultBlock.getBody().add(wrapper);
|
||||
for (Statement part : statement.getDefaultClause()) {
|
||||
part.acceptVisitor(this);
|
||||
defaultBlock.getBody().add(result);
|
||||
}
|
||||
wrapper = defaultBlock;
|
||||
|
||||
for (SwitchClause clause : statement.getClauses()) {
|
||||
WasmBlock caseBlock = new WasmBlock(false);
|
||||
caseBlock.getBody().add(wrapper);
|
||||
wasmSwitch.getTargets().add(wrapper);
|
||||
for (Statement part : clause.getBody()) {
|
||||
part.acceptVisitor(this);
|
||||
caseBlock.getBody().add(result);
|
||||
if (result != null) {
|
||||
caseBlock.getBody().add(result);
|
||||
}
|
||||
}
|
||||
wrappers.add(caseBlock);
|
||||
wrapper = caseBlock;
|
||||
}
|
||||
|
||||
for (WasmBlock nestedWrapper : wrappers) {
|
||||
nestedWrapper.getBody().add(new WasmBreak(wrapper));
|
||||
defaultBlock.getBody().add(wrapper);
|
||||
for (Statement part : statement.getDefaultClause()) {
|
||||
part.acceptVisitor(this);
|
||||
if (result != null) {
|
||||
defaultBlock.getBody().add(result);
|
||||
}
|
||||
}
|
||||
wasmSwitch.setDefaultTarget(wrapper);
|
||||
wrapper = defaultBlock;
|
||||
|
||||
breakTargets.remove(statement);
|
||||
currentBreakTarget = oldBreakTarget;
|
||||
|
||||
result = wrapper;
|
||||
}
|
||||
|
@ -570,6 +578,10 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
generateAddressInvocation(expr);
|
||||
return;
|
||||
}
|
||||
if (expr.getMethod().getClassName().equals(Structure.class.getName())) {
|
||||
generateStructureInvocation(expr);
|
||||
return;
|
||||
}
|
||||
|
||||
WasmIntrinsic intrinsic = context.getIntrinsic(expr.getMethod());
|
||||
if (intrinsic != null) {
|
||||
|
@ -589,6 +601,40 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
call.getArguments().add(result);
|
||||
}
|
||||
result = call;
|
||||
} else {
|
||||
expr.getArguments().get(0).acceptVisitor(this);
|
||||
WasmExpression instance = result;
|
||||
WasmBlock block = new WasmBlock(false);
|
||||
WasmLocal instanceVar = function.getLocalVariables().get(getTemporaryInt32());
|
||||
block.getBody().add(new WasmSetLocal(instanceVar, instance));
|
||||
instance = new WasmGetLocal(instanceVar);
|
||||
|
||||
WasmExpression classIndex = new WasmLoadInt32(4, instance, WasmInt32Subtype.INT32);
|
||||
classIndex = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.SHL, classIndex,
|
||||
new WasmInt32Constant(3));
|
||||
|
||||
VirtualTableEntry vtableEntry = context.getVirtualTableProvider().lookup(expr.getMethod());
|
||||
WasmExpression methodIndex = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD,
|
||||
classIndex, new WasmInt32Constant(vtableEntry.getIndex() * 4 + 8));
|
||||
methodIndex = new WasmLoadInt32(4, methodIndex, WasmInt32Subtype.INT32);
|
||||
|
||||
WasmIndirectCall call = new WasmIndirectCall(methodIndex);
|
||||
call.getParameterTypes().add(WasmType.INT32);
|
||||
for (int i = 0; i < expr.getMethod().parameterCount(); ++i) {
|
||||
call.getParameterTypes().add(WasmGeneratorUtil.mapType(expr.getMethod().parameterType(i)));
|
||||
}
|
||||
if (expr.getMethod().getReturnType() != ValueType.VOID) {
|
||||
call.setReturnType(WasmGeneratorUtil.mapType(expr.getMethod().getReturnType()));
|
||||
}
|
||||
|
||||
call.getArguments().add(instance);
|
||||
for (int i = 1; i < expr.getArguments().size(); ++i) {
|
||||
expr.getArguments().get(i).acceptVisitor(this);
|
||||
call.getArguments().add(result);
|
||||
}
|
||||
|
||||
block.getBody().add(call);
|
||||
result = block;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -700,6 +746,14 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
private void generateStructureInvocation(InvocationExpr expr) {
|
||||
switch (expr.getMethod().getName()) {
|
||||
case "toAddress":
|
||||
expr.getArguments().get(0).acceptVisitor(this);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(BlockStatement statement) {
|
||||
WasmBlock block = new WasmBlock(false);
|
||||
|
@ -990,4 +1044,12 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
private int getTemporaryInt32() {
|
||||
if (temporaryInt32 < 0) {
|
||||
temporaryInt32 = function.getLocalVariables().size();
|
||||
function.add(new WasmLocal(WasmType.INT32));
|
||||
}
|
||||
return temporaryInt32;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ package org.teavm.wasm.generate;
|
|||
|
||||
import java.util.Arrays;
|
||||
import java.util.stream.Collectors;
|
||||
import org.teavm.model.MethodDescriptor;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.ValueType;
|
||||
|
||||
|
|
|
@ -0,0 +1,183 @@
|
|||
/*
|
||||
* Copyright 2016 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.teavm.wasm.model.expression;
|
||||
|
||||
public class WasmDefaultExpressionVisitor implements WasmExpressionVisitor {
|
||||
@Override
|
||||
public void visit(WasmBlock expression) {
|
||||
for (WasmExpression part : expression.getBody()) {
|
||||
part.acceptVisitor(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmBranch expression) {
|
||||
expression.getCondition().acceptVisitor(this);
|
||||
if (expression.getResult() != null) {
|
||||
expression.getResult().acceptVisitor(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmBreak expression) {
|
||||
if (expression.getResult() != null) {
|
||||
expression.getResult().acceptVisitor(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmSwitch expression) {
|
||||
expression.getSelector().acceptVisitor(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmConditional expression) {
|
||||
expression.getCondition().acceptVisitor(this);
|
||||
for (WasmExpression part : expression.getThenBlock().getBody()) {
|
||||
part.acceptVisitor(this);
|
||||
}
|
||||
for (WasmExpression part : expression.getElseBlock().getBody()) {
|
||||
part.acceptVisitor(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmReturn expression) {
|
||||
if (expression.getValue() != null) {
|
||||
expression.getValue().acceptVisitor(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmUnreachable expression) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmInt32Constant expression) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmInt64Constant expression) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmFloat32Constant expression) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmFloat64Constant expression) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmGetLocal expression) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmSetLocal expression) {
|
||||
expression.getValue().acceptVisitor(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmIntBinary expression) {
|
||||
expression.getFirst().acceptVisitor(this);
|
||||
expression.getSecond().acceptVisitor(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmFloatBinary expression) {
|
||||
expression.getFirst().acceptVisitor(this);
|
||||
expression.getSecond().acceptVisitor(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmIntUnary expression) {
|
||||
expression.getOperand().acceptVisitor(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmFloatUnary expression) {
|
||||
expression.getOperand().acceptVisitor(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmConversion expression) {
|
||||
expression.getOperand().acceptVisitor(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmCall expression) {
|
||||
for (WasmExpression argument : expression.getArguments()) {
|
||||
argument.acceptVisitor(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmIndirectCall expression) {
|
||||
expression.getSelector().acceptVisitor(this);
|
||||
for (WasmExpression argument : expression.getArguments()) {
|
||||
argument.acceptVisitor(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmDrop expression) {
|
||||
expression.getOperand().acceptVisitor(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmLoadInt32 expression) {
|
||||
expression.getIndex().acceptVisitor(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmLoadInt64 expression) {
|
||||
expression.getIndex().acceptVisitor(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmLoadFloat32 expression) {
|
||||
expression.getIndex().acceptVisitor(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmLoadFloat64 expression) {
|
||||
expression.getIndex().acceptVisitor(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmStoreInt32 expression) {
|
||||
expression.getIndex().acceptVisitor(this);
|
||||
expression.getValue().acceptVisitor(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmStoreInt64 expression) {
|
||||
expression.getIndex().acceptVisitor(this);
|
||||
expression.getValue().acceptVisitor(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmStoreFloat32 expression) {
|
||||
expression.getIndex().acceptVisitor(this);
|
||||
expression.getValue().acceptVisitor(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmStoreFloat64 expression) {
|
||||
expression.getIndex().acceptVisitor(this);
|
||||
expression.getValue().acceptVisitor(this);
|
||||
}
|
||||
}
|
|
@ -18,16 +18,16 @@ package org.teavm.wasm.model.expression;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import org.teavm.wasm.model.WasmType;
|
||||
|
||||
public class WasmIndirectCall extends WasmExpression {
|
||||
private String typeName;
|
||||
private List<WasmType> parameterTypes = new ArrayList<>();
|
||||
private WasmType returnType;
|
||||
private WasmExpression selector;
|
||||
private List<WasmExpression> arguments = new ArrayList<>();
|
||||
|
||||
public WasmIndirectCall(String typeName, WasmExpression selector) {
|
||||
Objects.requireNonNull(typeName);
|
||||
public WasmIndirectCall(WasmExpression selector) {
|
||||
Objects.requireNonNull(selector);
|
||||
this.typeName = typeName;
|
||||
this.selector = selector;
|
||||
}
|
||||
|
||||
|
@ -40,13 +40,16 @@ public class WasmIndirectCall extends WasmExpression {
|
|||
this.selector = selector;
|
||||
}
|
||||
|
||||
public String getTypeName() {
|
||||
return typeName;
|
||||
public List<WasmType> getParameterTypes() {
|
||||
return parameterTypes;
|
||||
}
|
||||
|
||||
public void setTypeName(String typeName) {
|
||||
Objects.requireNonNull(typeName);
|
||||
this.typeName = typeName;
|
||||
public WasmType getReturnType() {
|
||||
return returnType;
|
||||
}
|
||||
|
||||
public void setReturnType(WasmType returnType) {
|
||||
this.returnType = returnType;
|
||||
}
|
||||
|
||||
public List<WasmExpression> getArguments() {
|
||||
|
|
|
@ -49,6 +49,8 @@ public class WasmRenderer {
|
|||
public void render(WasmModule module) {
|
||||
visitor.open().append("module");
|
||||
renderMemory(module);
|
||||
renderTypes(module);
|
||||
|
||||
for (WasmFunction function : module.getFunctions().values()) {
|
||||
if (function.getImportName() == null) {
|
||||
continue;
|
||||
|
@ -67,10 +69,15 @@ public class WasmRenderer {
|
|||
}
|
||||
lf().renderExport(function);
|
||||
}
|
||||
renderTable(module);
|
||||
if (module.getStartFunction() != null) {
|
||||
visitor.lf().open().append("start $" + module.getStartFunction().getName()).close().lf();
|
||||
}
|
||||
visitor.close().lf();
|
||||
}
|
||||
|
||||
public void renderMemory(WasmModule module) {
|
||||
visitor.lf();
|
||||
visitor.open().append("memory " + module.getMemorySize());
|
||||
for (WasmMemorySegment segment : module.getSegments()) {
|
||||
visitor.lf().open().append("segment " + segment.getLength());
|
||||
|
@ -136,16 +143,65 @@ public class WasmRenderer {
|
|||
}
|
||||
|
||||
private void renderSignature(WasmFunction function) {
|
||||
if (!function.getParameters().isEmpty()) {
|
||||
visitor.append(" ").open().append("param");
|
||||
for (WasmType type : function.getParameters()) {
|
||||
visitor.append(" ").append(type);
|
||||
WasmSignature signature = signatureFromFunction(function);
|
||||
visitor.append(" ").open().append("type $type" + visitor.getSignatureIndex(signature)).close();
|
||||
}
|
||||
|
||||
private WasmSignature signatureFromFunction(WasmFunction function) {
|
||||
WasmType[] types = new WasmType[function.getParameters().size() + 1];
|
||||
types[0] = function.getResult();
|
||||
for (int i = 0; i < function.getParameters().size(); ++i) {
|
||||
types[i + 1] = function.getParameters().get(i);
|
||||
}
|
||||
return new WasmSignature(types);
|
||||
}
|
||||
|
||||
private void renderTypes(WasmModule module) {
|
||||
WasmSignatureCollector signatureCollector = new WasmSignatureCollector(visitor);
|
||||
for (WasmFunction function : module.getFunctions().values()) {
|
||||
visitor.getSignatureIndex(signatureFromFunction(function));
|
||||
for (WasmExpression part : function.getBody()) {
|
||||
part.acceptVisitor(signatureCollector);
|
||||
}
|
||||
}
|
||||
|
||||
if (visitor.signatureList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
visitor.lf();
|
||||
int index = 0;
|
||||
for (WasmSignature signature : visitor.signatureList) {
|
||||
visitor.open().append("type $type" + index++ + " ");
|
||||
visitor.open().append("func");
|
||||
if (signature.types.length > 1) {
|
||||
visitor.append(" ").open().append("param");
|
||||
for (int i = 1; i < signature.types.length; ++i) {
|
||||
visitor.append(" ").append(signature.types[i]);
|
||||
}
|
||||
visitor.close();
|
||||
}
|
||||
if (signature.types[0] != null) {
|
||||
visitor.append(" ").open().append("result ");
|
||||
visitor.append(signature.types[0]);
|
||||
visitor.close();
|
||||
}
|
||||
visitor.close();
|
||||
visitor.close();
|
||||
visitor.lf();
|
||||
}
|
||||
if (function.getResult() != null) {
|
||||
visitor.append(" ").open().append("result ").append(function.getResult()).close();
|
||||
}
|
||||
|
||||
private void renderTable(WasmModule module) {
|
||||
if (module.getFunctionTable().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
visitor.lf().open().append("table");
|
||||
for (WasmFunction function : module.getFunctionTable()) {
|
||||
visitor.lf().append("$" + function.getName());
|
||||
}
|
||||
visitor.close().lf();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -15,8 +15,10 @@
|
|||
*/
|
||||
package org.teavm.wasm.render;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.teavm.wasm.model.WasmLocal;
|
||||
|
@ -65,6 +67,8 @@ class WasmRenderingVisitor implements WasmExpressionVisitor {
|
|||
private Map<WasmBlock, String> blockIdentifiers = new HashMap<>();
|
||||
private int indentLevel;
|
||||
private boolean lfDeferred;
|
||||
List<WasmSignature> signatureList = new ArrayList<>();
|
||||
Map<WasmSignature, Integer> signatureMap = new HashMap<>();
|
||||
|
||||
void clear() {
|
||||
blockIdentifiers.clear();
|
||||
|
@ -341,7 +345,13 @@ class WasmRenderingVisitor implements WasmExpressionVisitor {
|
|||
|
||||
@Override
|
||||
public void visit(WasmIndirectCall expression) {
|
||||
open().append("call_indirect").append(" " + expression.getTypeName());
|
||||
WasmType[] types = new WasmType[expression.getParameterTypes().size() + 1];
|
||||
types[0] = expression.getReturnType();
|
||||
for (int i = 0; i < expression.getParameterTypes().size(); ++i) {
|
||||
types[i + 1] = expression.getParameterTypes().get(i);
|
||||
}
|
||||
|
||||
open().append("call_indirect").append(" $type" + getSignatureIndex(new WasmSignature(types)));
|
||||
line(expression.getSelector());
|
||||
for (WasmExpression argument : expression.getArguments()) {
|
||||
line(argument);
|
||||
|
@ -349,6 +359,13 @@ class WasmRenderingVisitor implements WasmExpressionVisitor {
|
|||
close();
|
||||
}
|
||||
|
||||
int getSignatureIndex(WasmSignature signature) {
|
||||
return signatureMap.computeIfAbsent(signature, key -> {
|
||||
signatureList.add(key);
|
||||
return signatureMap.size();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmDrop expression) {
|
||||
append(expression.getOperand());
|
||||
|
|
44
core/src/main/java/org/teavm/wasm/render/WasmSignature.java
Normal file
44
core/src/main/java/org/teavm/wasm/render/WasmSignature.java
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright 2016 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.teavm.wasm.render;
|
||||
|
||||
import java.util.Arrays;
|
||||
import org.teavm.wasm.model.WasmType;
|
||||
|
||||
class WasmSignature {
|
||||
WasmType[] types;
|
||||
|
||||
public WasmSignature(WasmType[] types) {
|
||||
this.types = types;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
WasmSignature that = (WasmSignature) o;
|
||||
return Arrays.equals(types, that.types);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Arrays.hashCode(types);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright 2016 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.teavm.wasm.render;
|
||||
|
||||
import org.teavm.wasm.model.WasmType;
|
||||
import org.teavm.wasm.model.expression.WasmDefaultExpressionVisitor;
|
||||
import org.teavm.wasm.model.expression.WasmIndirectCall;
|
||||
|
||||
class WasmSignatureCollector extends WasmDefaultExpressionVisitor {
|
||||
WasmRenderingVisitor renderingVisitor;
|
||||
|
||||
public WasmSignatureCollector(WasmRenderingVisitor renderingVisitor) {
|
||||
this.renderingVisitor = renderingVisitor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmIndirectCall expression) {
|
||||
WasmType[] types = new WasmType[expression.getParameterTypes().size() + 1];
|
||||
types[0] = expression.getReturnType();
|
||||
for (int i = 0; i < expression.getParameterTypes().size(); ++i) {
|
||||
types[i + 1] = expression.getParameterTypes().get(i);
|
||||
}
|
||||
|
||||
renderingVisitor.getSignatureIndex(new WasmSignature(types));
|
||||
}
|
||||
}
|
|
@ -16,11 +16,11 @@
|
|||
package org.teavm.interop;
|
||||
|
||||
public class Structure {
|
||||
public native <T extends Structure> T cast();
|
||||
public final native <T extends Structure> T cast();
|
||||
|
||||
public native Address toAddress();
|
||||
public final native Address toAddress();
|
||||
|
||||
public native int sizeOf(Class<? extends Structure> type);
|
||||
public final native int sizeOf(Class<? extends Structure> type);
|
||||
|
||||
public native <T extends Structure> T add(T base, int offset);
|
||||
public final native <T extends Structure> T add(T base, int offset);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user