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.instructions.*;
|
||||||
import org.teavm.model.util.ModelUtils;
|
import org.teavm.model.util.ModelUtils;
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Alexey Andreev
|
|
||||||
*/
|
|
||||||
public class ClassRefsRenamer implements InstructionVisitor {
|
public class ClassRefsRenamer implements InstructionVisitor {
|
||||||
private Mapper<String, String> classNameMapper;
|
private Mapper<String, String> classNameMapper;
|
||||||
|
|
||||||
|
@ -49,6 +45,9 @@ public class ClassRefsRenamer implements InstructionVisitor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
renamedCls.setParent(parent != null ? classNameMapper.map(parent) : null);
|
renamedCls.setParent(parent != null ? classNameMapper.map(parent) : null);
|
||||||
|
if (renamedCls.getName().equals(renamedCls.getParent())) {
|
||||||
|
renamedCls.setParent(null);
|
||||||
|
}
|
||||||
for (MethodHolder method : cls.getMethods()) {
|
for (MethodHolder method : cls.getMethods()) {
|
||||||
if (method.getAnnotations().get(Remove.class.getName()) != null) {
|
if (method.getAnnotations().get(Remove.class.getName()) != null) {
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -28,7 +28,7 @@ public final class Allocator {
|
||||||
Address result = address;
|
Address result = address;
|
||||||
address = result.add(tag.size);
|
address = result.add(tag.size);
|
||||||
RuntimeObject object = result.toStructure();
|
RuntimeObject object = result.toStructure();
|
||||||
object.classInfo = tag;
|
object.classReference = tag.toAddress().toInt() >> 3;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,5 +18,5 @@ package org.teavm.runtime;
|
||||||
import org.teavm.interop.Structure;
|
import org.teavm.interop.Structure;
|
||||||
|
|
||||||
public class RuntimeObject extends 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(a);
|
||||||
}
|
}
|
||||||
WasmRuntime.print(new A(2).getValue() + new A(3).getValue());
|
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 {
|
private static class A {
|
||||||
|
@ -42,4 +59,32 @@ public final class Example {
|
||||||
return value;
|
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.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import org.teavm.ast.decompilation.Decompiler;
|
import org.teavm.ast.decompilation.Decompiler;
|
||||||
import org.teavm.dependency.DependencyChecker;
|
import org.teavm.dependency.DependencyChecker;
|
||||||
import org.teavm.interop.Address;
|
import org.teavm.interop.Address;
|
||||||
import org.teavm.interop.Import;
|
import org.teavm.interop.Import;
|
||||||
import org.teavm.interop.StaticInit;
|
import org.teavm.interop.StaticInit;
|
||||||
import org.teavm.interop.Structure;
|
import org.teavm.interop.Structure;
|
||||||
|
import org.teavm.model.BasicBlock;
|
||||||
import org.teavm.model.CallLocation;
|
import org.teavm.model.CallLocation;
|
||||||
import org.teavm.model.ClassHolder;
|
import org.teavm.model.ClassHolder;
|
||||||
import org.teavm.model.ClassReader;
|
import org.teavm.model.ClassReader;
|
||||||
import org.teavm.model.ElementModifier;
|
import org.teavm.model.ElementModifier;
|
||||||
|
import org.teavm.model.Instruction;
|
||||||
import org.teavm.model.ListableClassHolderSource;
|
import org.teavm.model.ListableClassHolderSource;
|
||||||
import org.teavm.model.ListableClassReaderSource;
|
import org.teavm.model.ListableClassReaderSource;
|
||||||
import org.teavm.model.MethodDescriptor;
|
import org.teavm.model.MethodDescriptor;
|
||||||
import org.teavm.model.MethodHolder;
|
import org.teavm.model.MethodHolder;
|
||||||
import org.teavm.model.MethodReader;
|
import org.teavm.model.MethodReader;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
|
import org.teavm.model.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.Allocator;
|
||||||
import org.teavm.runtime.RuntimeClass;
|
import org.teavm.runtime.RuntimeClass;
|
||||||
import org.teavm.vm.BuildTarget;
|
import org.teavm.vm.BuildTarget;
|
||||||
|
@ -109,7 +116,8 @@ public class WasmTarget implements TeaVMTarget {
|
||||||
public void emit(ListableClassHolderSource classes, OutputStream output, BuildTarget buildTarget) {
|
public void emit(ListableClassHolderSource classes, OutputStream output, BuildTarget buildTarget) {
|
||||||
int address = 256;
|
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()) {
|
for (String className : classes.getClassNames()) {
|
||||||
classGenerator.addClass(className);
|
classGenerator.addClass(className);
|
||||||
if (controller.wasCancelled()) {
|
if (controller.wasCancelled()) {
|
||||||
|
@ -120,7 +128,7 @@ public class WasmTarget implements TeaVMTarget {
|
||||||
|
|
||||||
Decompiler decompiler = new Decompiler(classes, controller.getClassLoader(), new HashSet<>(),
|
Decompiler decompiler = new Decompiler(classes, controller.getClassLoader(), new HashSet<>(),
|
||||||
new HashSet<>());
|
new HashSet<>());
|
||||||
WasmGenerationContext context = new WasmGenerationContext(classes);
|
WasmGenerationContext context = new WasmGenerationContext(classes, vtableProvider);
|
||||||
context.addIntrinsic(new WasmRuntimeIntrinsic());
|
context.addIntrinsic(new WasmRuntimeIntrinsic());
|
||||||
WasmGenerator generator = new WasmGenerator(decompiler, classes, context, classGenerator);
|
WasmGenerator generator = new WasmGenerator(decompiler, classes, context, classGenerator);
|
||||||
|
|
||||||
|
@ -168,7 +176,7 @@ public class WasmTarget implements TeaVMTarget {
|
||||||
}
|
}
|
||||||
|
|
||||||
WasmFunction initFunction = new WasmFunction("__start__");
|
WasmFunction initFunction = new WasmFunction("__start__");
|
||||||
classGenerator.contributeToInitializer(initFunction.getBody());
|
classGenerator.contributeToInitializer(initFunction.getBody(), module);
|
||||||
for (String className : classes.getClassNames()) {
|
for (String className : classes.getClassNames()) {
|
||||||
ClassReader cls = classes.get(className);
|
ClassReader cls = classes.get(className);
|
||||||
if (cls.getAnnotations().get(StaticInit.class.getName()) == null) {
|
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())));
|
initFunction.getBody().add(new WasmCall(WasmMangling.mangleMethod(clinit.getReference())));
|
||||||
}
|
}
|
||||||
module.add(initFunction);
|
module.add(initFunction);
|
||||||
|
module.setStartFunction(initFunction);
|
||||||
|
|
||||||
for (TeaVMEntryPoint entryPoint : controller.getEntryPoints().values()) {
|
for (TeaVMEntryPoint entryPoint : controller.getEntryPoints().values()) {
|
||||||
String mangledName = WasmMangling.mangleMethod(entryPoint.getReference());
|
String mangledName = WasmMangling.mangleMethod(entryPoint.getReference());
|
||||||
|
@ -253,6 +262,33 @@ public class WasmTarget implements TeaVMTarget {
|
||||||
module.add(function);
|
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 {
|
public static void main(String[] args) throws IOException {
|
||||||
TeaVM vm = new TeaVMBuilder(new WasmTarget()).build();
|
TeaVM vm = new TeaVMBuilder(new WasmTarget()).build();
|
||||||
vm.installPlugins();
|
vm.installPlugins();
|
||||||
|
|
|
@ -17,6 +17,7 @@ package org.teavm.wasm.generate;
|
||||||
|
|
||||||
import com.carrotsearch.hppc.ObjectIntMap;
|
import com.carrotsearch.hppc.ObjectIntMap;
|
||||||
import com.carrotsearch.hppc.ObjectIntOpenHashMap;
|
import com.carrotsearch.hppc.ObjectIntOpenHashMap;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -27,7 +28,12 @@ import org.teavm.model.ClassReaderSource;
|
||||||
import org.teavm.model.ElementModifier;
|
import org.teavm.model.ElementModifier;
|
||||||
import org.teavm.model.FieldReader;
|
import org.teavm.model.FieldReader;
|
||||||
import org.teavm.model.FieldReference;
|
import org.teavm.model.FieldReference;
|
||||||
|
import org.teavm.model.MethodReference;
|
||||||
import org.teavm.model.ValueType;
|
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.WasmExpression;
|
||||||
import org.teavm.wasm.model.expression.WasmInt32Constant;
|
import org.teavm.wasm.model.expression.WasmInt32Constant;
|
||||||
import org.teavm.wasm.model.expression.WasmInt32Subtype;
|
import org.teavm.wasm.model.expression.WasmInt32Subtype;
|
||||||
|
@ -37,9 +43,11 @@ public class WasmClassGenerator {
|
||||||
private ClassReaderSource classSource;
|
private ClassReaderSource classSource;
|
||||||
private int address;
|
private int address;
|
||||||
private Map<String, ClassBinaryData> binaryDataMap = new LinkedHashMap<>();
|
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.classSource = classSource;
|
||||||
|
this.vtableProvider = vtableProvider;
|
||||||
this.address = address;
|
this.address = address;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,8 +64,11 @@ public class WasmClassGenerator {
|
||||||
if (binaryData.start < 0) {
|
if (binaryData.start < 0) {
|
||||||
return;
|
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;
|
address = binaryData.end;
|
||||||
}
|
}
|
||||||
|
@ -66,7 +77,9 @@ public class WasmClassGenerator {
|
||||||
return address;
|
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()) {
|
for (ClassBinaryData binaryData : binaryDataMap.values()) {
|
||||||
if (binaryData.start < 0) {
|
if (binaryData.start < 0) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -74,6 +87,26 @@ public class WasmClassGenerator {
|
||||||
WasmExpression index = new WasmInt32Constant(binaryData.start);
|
WasmExpression index = new WasmInt32Constant(binaryData.start);
|
||||||
WasmExpression size = new WasmInt32Constant(binaryData.size);
|
WasmExpression size = new WasmInt32Constant(binaryData.size);
|
||||||
initializer.add(new WasmStoreInt32(4, index, size, WasmInt32Subtype.INT32));
|
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) {
|
private static int align(int base, int alignment) {
|
||||||
|
if (base == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
return ((base - 1) / alignment + 1) * alignment;
|
return ((base - 1) / alignment + 1) * alignment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,6 +185,7 @@ public class WasmClassGenerator {
|
||||||
int start;
|
int start;
|
||||||
int end;
|
int end;
|
||||||
|
|
||||||
|
VirtualTable vtable;
|
||||||
int size;
|
int size;
|
||||||
ObjectIntMap<String> fieldLayout = new ObjectIntOpenHashMap<>();
|
ObjectIntMap<String> fieldLayout = new ObjectIntOpenHashMap<>();
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,16 +29,19 @@ import org.teavm.model.FieldReference;
|
||||||
import org.teavm.model.MethodReader;
|
import org.teavm.model.MethodReader;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
import org.teavm.model.ValueType;
|
import org.teavm.model.ValueType;
|
||||||
|
import org.teavm.model.classes.VirtualTableProvider;
|
||||||
import org.teavm.wasm.intrinsics.WasmIntrinsic;
|
import org.teavm.wasm.intrinsics.WasmIntrinsic;
|
||||||
|
|
||||||
public class WasmGenerationContext {
|
public class WasmGenerationContext {
|
||||||
private ClassReaderSource classSource;
|
private ClassReaderSource classSource;
|
||||||
|
private VirtualTableProvider vtableProvider;
|
||||||
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, WasmIntrinsic> intrinsicCache = new HashMap<>();
|
private Map<MethodReference, WasmIntrinsic> intrinsicCache = new HashMap<>();
|
||||||
|
|
||||||
public WasmGenerationContext(ClassReaderSource classSource) {
|
public WasmGenerationContext(ClassReaderSource classSource, VirtualTableProvider vtableProvider) {
|
||||||
this.classSource = classSource;
|
this.classSource = classSource;
|
||||||
|
this.vtableProvider = vtableProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addIntrinsic(WasmIntrinsic intrinsic) {
|
public void addIntrinsic(WasmIntrinsic intrinsic) {
|
||||||
|
@ -86,6 +89,10 @@ public class WasmGenerationContext {
|
||||||
return field.getType();
|
return field.getType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public VirtualTableProvider getVirtualTableProvider() {
|
||||||
|
return vtableProvider;
|
||||||
|
}
|
||||||
|
|
||||||
public class ImportedMethod {
|
public class ImportedMethod {
|
||||||
public final String name;
|
public final String name;
|
||||||
public final String module;
|
public final String module;
|
||||||
|
|
|
@ -15,10 +15,8 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.wasm.generate;
|
package org.teavm.wasm.generate;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import org.teavm.ast.AssignmentStatement;
|
import org.teavm.ast.AssignmentStatement;
|
||||||
|
@ -60,13 +58,16 @@ import org.teavm.ast.UnwrapArrayExpr;
|
||||||
import org.teavm.ast.VariableExpr;
|
import org.teavm.ast.VariableExpr;
|
||||||
import org.teavm.ast.WhileStatement;
|
import org.teavm.ast.WhileStatement;
|
||||||
import org.teavm.interop.Address;
|
import org.teavm.interop.Address;
|
||||||
|
import org.teavm.interop.Structure;
|
||||||
import org.teavm.model.ClassReader;
|
import org.teavm.model.ClassReader;
|
||||||
import org.teavm.model.FieldReference;
|
import org.teavm.model.FieldReference;
|
||||||
import org.teavm.model.MethodDescriptor;
|
import org.teavm.model.MethodDescriptor;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
import org.teavm.model.ValueType;
|
import org.teavm.model.ValueType;
|
||||||
|
import org.teavm.model.classes.VirtualTableEntry;
|
||||||
import org.teavm.runtime.Allocator;
|
import org.teavm.runtime.Allocator;
|
||||||
import org.teavm.runtime.RuntimeClass;
|
import org.teavm.runtime.RuntimeClass;
|
||||||
|
import org.teavm.wasm.WasmRuntime;
|
||||||
import org.teavm.wasm.intrinsics.WasmIntrinsic;
|
import org.teavm.wasm.intrinsics.WasmIntrinsic;
|
||||||
import org.teavm.wasm.intrinsics.WasmIntrinsicManager;
|
import org.teavm.wasm.intrinsics.WasmIntrinsicManager;
|
||||||
import org.teavm.wasm.model.WasmFunction;
|
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.WasmFloatBinaryOperation;
|
||||||
import org.teavm.wasm.model.expression.WasmFloatType;
|
import org.teavm.wasm.model.expression.WasmFloatType;
|
||||||
import org.teavm.wasm.model.expression.WasmGetLocal;
|
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.WasmInt32Constant;
|
||||||
import org.teavm.wasm.model.expression.WasmInt32Subtype;
|
import org.teavm.wasm.model.expression.WasmInt32Subtype;
|
||||||
import org.teavm.wasm.model.expression.WasmInt64Constant;
|
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.WasmStoreInt32;
|
||||||
import org.teavm.wasm.model.expression.WasmStoreInt64;
|
import org.teavm.wasm.model.expression.WasmStoreInt64;
|
||||||
import org.teavm.wasm.model.expression.WasmSwitch;
|
import org.teavm.wasm.model.expression.WasmSwitch;
|
||||||
import org.teavm.wasm.WasmRuntime;
|
|
||||||
|
|
||||||
class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
private WasmGenerationContext context;
|
private WasmGenerationContext context;
|
||||||
|
@ -116,6 +117,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
private Map<IdentifiedStatement, WasmBlock> breakTargets = new HashMap<>();
|
private Map<IdentifiedStatement, WasmBlock> breakTargets = new HashMap<>();
|
||||||
private Map<IdentifiedStatement, WasmBlock> continueTargets = new HashMap<>();
|
private Map<IdentifiedStatement, WasmBlock> continueTargets = new HashMap<>();
|
||||||
private Set<WasmBlock> usedBlocks = new HashSet<>();
|
private Set<WasmBlock> usedBlocks = new HashSet<>();
|
||||||
|
private int temporaryInt32 = -1;
|
||||||
WasmExpression result;
|
WasmExpression result;
|
||||||
|
|
||||||
WasmGenerationVisitor(WasmGenerationContext context, WasmClassGenerator classGenerator,
|
WasmGenerationVisitor(WasmGenerationContext context, WasmClassGenerator classGenerator,
|
||||||
|
@ -486,36 +488,42 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(SwitchStatement statement) {
|
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);
|
WasmBlock wrapper = new WasmBlock(false);
|
||||||
statement.getValue().acceptVisitor(this);
|
statement.getValue().acceptVisitor(this);
|
||||||
WasmSwitch wasmSwitch = new WasmSwitch(result, wrapper);
|
WasmSwitch wasmSwitch = new WasmSwitch(result, wrapper);
|
||||||
wrapper.getBody().add(wasmSwitch);
|
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()) {
|
for (SwitchClause clause : statement.getClauses()) {
|
||||||
WasmBlock caseBlock = new WasmBlock(false);
|
WasmBlock caseBlock = new WasmBlock(false);
|
||||||
caseBlock.getBody().add(wrapper);
|
caseBlock.getBody().add(wrapper);
|
||||||
wasmSwitch.getTargets().add(wrapper);
|
wasmSwitch.getTargets().add(wrapper);
|
||||||
for (Statement part : clause.getBody()) {
|
for (Statement part : clause.getBody()) {
|
||||||
part.acceptVisitor(this);
|
part.acceptVisitor(this);
|
||||||
|
if (result != null) {
|
||||||
caseBlock.getBody().add(result);
|
caseBlock.getBody().add(result);
|
||||||
}
|
}
|
||||||
wrappers.add(caseBlock);
|
}
|
||||||
wrapper = caseBlock;
|
wrapper = caseBlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (WasmBlock nestedWrapper : wrappers) {
|
defaultBlock.getBody().add(wrapper);
|
||||||
nestedWrapper.getBody().add(new WasmBreak(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;
|
result = wrapper;
|
||||||
}
|
}
|
||||||
|
@ -570,6 +578,10 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
generateAddressInvocation(expr);
|
generateAddressInvocation(expr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (expr.getMethod().getClassName().equals(Structure.class.getName())) {
|
||||||
|
generateStructureInvocation(expr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
WasmIntrinsic intrinsic = context.getIntrinsic(expr.getMethod());
|
WasmIntrinsic intrinsic = context.getIntrinsic(expr.getMethod());
|
||||||
if (intrinsic != null) {
|
if (intrinsic != null) {
|
||||||
|
@ -589,6 +601,40 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
call.getArguments().add(result);
|
call.getArguments().add(result);
|
||||||
}
|
}
|
||||||
result = call;
|
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
|
@Override
|
||||||
public void visit(BlockStatement statement) {
|
public void visit(BlockStatement statement) {
|
||||||
WasmBlock block = new WasmBlock(false);
|
WasmBlock block = new WasmBlock(false);
|
||||||
|
@ -990,4 +1044,12 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
return result;
|
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.Arrays;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import org.teavm.model.MethodDescriptor;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
import org.teavm.model.ValueType;
|
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.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import org.teavm.wasm.model.WasmType;
|
||||||
|
|
||||||
public class WasmIndirectCall extends WasmExpression {
|
public class WasmIndirectCall extends WasmExpression {
|
||||||
private String typeName;
|
private List<WasmType> parameterTypes = new ArrayList<>();
|
||||||
|
private WasmType returnType;
|
||||||
private WasmExpression selector;
|
private WasmExpression selector;
|
||||||
private List<WasmExpression> arguments = new ArrayList<>();
|
private List<WasmExpression> arguments = new ArrayList<>();
|
||||||
|
|
||||||
public WasmIndirectCall(String typeName, WasmExpression selector) {
|
public WasmIndirectCall(WasmExpression selector) {
|
||||||
Objects.requireNonNull(typeName);
|
|
||||||
Objects.requireNonNull(selector);
|
Objects.requireNonNull(selector);
|
||||||
this.typeName = typeName;
|
|
||||||
this.selector = selector;
|
this.selector = selector;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,13 +40,16 @@ public class WasmIndirectCall extends WasmExpression {
|
||||||
this.selector = selector;
|
this.selector = selector;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getTypeName() {
|
public List<WasmType> getParameterTypes() {
|
||||||
return typeName;
|
return parameterTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTypeName(String typeName) {
|
public WasmType getReturnType() {
|
||||||
Objects.requireNonNull(typeName);
|
return returnType;
|
||||||
this.typeName = typeName;
|
}
|
||||||
|
|
||||||
|
public void setReturnType(WasmType returnType) {
|
||||||
|
this.returnType = returnType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<WasmExpression> getArguments() {
|
public List<WasmExpression> getArguments() {
|
||||||
|
|
|
@ -49,6 +49,8 @@ public class WasmRenderer {
|
||||||
public void render(WasmModule module) {
|
public void render(WasmModule module) {
|
||||||
visitor.open().append("module");
|
visitor.open().append("module");
|
||||||
renderMemory(module);
|
renderMemory(module);
|
||||||
|
renderTypes(module);
|
||||||
|
|
||||||
for (WasmFunction function : module.getFunctions().values()) {
|
for (WasmFunction function : module.getFunctions().values()) {
|
||||||
if (function.getImportName() == null) {
|
if (function.getImportName() == null) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -67,10 +69,15 @@ public class WasmRenderer {
|
||||||
}
|
}
|
||||||
lf().renderExport(function);
|
lf().renderExport(function);
|
||||||
}
|
}
|
||||||
|
renderTable(module);
|
||||||
|
if (module.getStartFunction() != null) {
|
||||||
|
visitor.lf().open().append("start $" + module.getStartFunction().getName()).close().lf();
|
||||||
|
}
|
||||||
visitor.close().lf();
|
visitor.close().lf();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void renderMemory(WasmModule module) {
|
public void renderMemory(WasmModule module) {
|
||||||
|
visitor.lf();
|
||||||
visitor.open().append("memory " + module.getMemorySize());
|
visitor.open().append("memory " + module.getMemorySize());
|
||||||
for (WasmMemorySegment segment : module.getSegments()) {
|
for (WasmMemorySegment segment : module.getSegments()) {
|
||||||
visitor.lf().open().append("segment " + segment.getLength());
|
visitor.lf().open().append("segment " + segment.getLength());
|
||||||
|
@ -136,16 +143,65 @@ public class WasmRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderSignature(WasmFunction function) {
|
private void renderSignature(WasmFunction function) {
|
||||||
if (!function.getParameters().isEmpty()) {
|
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");
|
visitor.append(" ").open().append("param");
|
||||||
for (WasmType type : function.getParameters()) {
|
for (int i = 1; i < signature.types.length; ++i) {
|
||||||
visitor.append(" ").append(type);
|
visitor.append(" ").append(signature.types[i]);
|
||||||
}
|
}
|
||||||
visitor.close();
|
visitor.close();
|
||||||
}
|
}
|
||||||
if (function.getResult() != null) {
|
if (signature.types[0] != null) {
|
||||||
visitor.append(" ").open().append("result ").append(function.getResult()).close();
|
visitor.append(" ").open().append("result ");
|
||||||
|
visitor.append(signature.types[0]);
|
||||||
|
visitor.close();
|
||||||
}
|
}
|
||||||
|
visitor.close();
|
||||||
|
visitor.close();
|
||||||
|
visitor.lf();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
@Override
|
||||||
|
|
|
@ -15,8 +15,10 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.wasm.render;
|
package org.teavm.wasm.render;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import org.teavm.wasm.model.WasmLocal;
|
import org.teavm.wasm.model.WasmLocal;
|
||||||
|
@ -65,6 +67,8 @@ class WasmRenderingVisitor implements WasmExpressionVisitor {
|
||||||
private Map<WasmBlock, String> blockIdentifiers = new HashMap<>();
|
private Map<WasmBlock, String> blockIdentifiers = new HashMap<>();
|
||||||
private int indentLevel;
|
private int indentLevel;
|
||||||
private boolean lfDeferred;
|
private boolean lfDeferred;
|
||||||
|
List<WasmSignature> signatureList = new ArrayList<>();
|
||||||
|
Map<WasmSignature, Integer> signatureMap = new HashMap<>();
|
||||||
|
|
||||||
void clear() {
|
void clear() {
|
||||||
blockIdentifiers.clear();
|
blockIdentifiers.clear();
|
||||||
|
@ -341,7 +345,13 @@ class WasmRenderingVisitor implements WasmExpressionVisitor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(WasmIndirectCall expression) {
|
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());
|
line(expression.getSelector());
|
||||||
for (WasmExpression argument : expression.getArguments()) {
|
for (WasmExpression argument : expression.getArguments()) {
|
||||||
line(argument);
|
line(argument);
|
||||||
|
@ -349,6 +359,13 @@ class WasmRenderingVisitor implements WasmExpressionVisitor {
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int getSignatureIndex(WasmSignature signature) {
|
||||||
|
return signatureMap.computeIfAbsent(signature, key -> {
|
||||||
|
signatureList.add(key);
|
||||||
|
return signatureMap.size();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(WasmDrop expression) {
|
public void visit(WasmDrop expression) {
|
||||||
append(expression.getOperand());
|
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;
|
package org.teavm.interop;
|
||||||
|
|
||||||
public class Structure {
|
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