mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 00:04:10 -08:00
Start supporting classes in WASM
This commit is contained in:
parent
081efd2d60
commit
675abe8740
34
core/src/main/java/org/teavm/runtime/Allocator.java
Normal file
34
core/src/main/java/org/teavm/runtime/Allocator.java
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* 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.runtime;
|
||||
|
||||
import org.teavm.interop.Address;
|
||||
import org.teavm.interop.StaticInit;
|
||||
|
||||
@StaticInit
|
||||
public final class Allocator {
|
||||
private static Address address = initialize();
|
||||
|
||||
private static native Address initialize();
|
||||
|
||||
public static Address allocate(RuntimeClass tag) {
|
||||
Address result = address;
|
||||
address = result.add(tag.size);
|
||||
RuntimeObject object = result.toStructure();
|
||||
object.classInfo = tag;
|
||||
return result;
|
||||
}
|
||||
}
|
24
core/src/main/java/org/teavm/runtime/RuntimeClass.java
Normal file
24
core/src/main/java/org/teavm/runtime/RuntimeClass.java
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* 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.runtime;
|
||||
|
||||
import org.teavm.interop.Structure;
|
||||
|
||||
public class RuntimeClass extends Structure {
|
||||
public static int INITIALIZED = 1;
|
||||
public int size;
|
||||
public int flags;
|
||||
}
|
22
core/src/main/java/org/teavm/runtime/RuntimeObject.java
Normal file
22
core/src/main/java/org/teavm/runtime/RuntimeObject.java
Normal file
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* 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.runtime;
|
||||
|
||||
import org.teavm.interop.Structure;
|
||||
|
||||
public class RuntimeObject extends Structure {
|
||||
public RuntimeClass classInfo;
|
||||
}
|
|
@ -30,5 +30,18 @@ public final class Example {
|
|||
b = c;
|
||||
WasmRuntime.print(a);
|
||||
}
|
||||
WasmRuntime.print(new A(2).getValue() + new A(3).getValue());
|
||||
}
|
||||
|
||||
private static class A {
|
||||
private int value;
|
||||
|
||||
public A(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,13 +26,22 @@ import java.util.HashSet;
|
|||
import java.util.List;
|
||||
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.CallLocation;
|
||||
import org.teavm.model.ClassHolder;
|
||||
import org.teavm.model.ClassReader;
|
||||
import org.teavm.model.ElementModifier;
|
||||
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.runtime.Allocator;
|
||||
import org.teavm.runtime.RuntimeClass;
|
||||
import org.teavm.vm.BuildTarget;
|
||||
import org.teavm.vm.TeaVM;
|
||||
import org.teavm.vm.TeaVMBuilder;
|
||||
|
@ -40,11 +49,25 @@ import org.teavm.vm.TeaVMEntryPoint;
|
|||
import org.teavm.vm.TeaVMTarget;
|
||||
import org.teavm.vm.TeaVMTargetController;
|
||||
import org.teavm.vm.spi.TeaVMHostExtension;
|
||||
import org.teavm.wasm.generate.WasmClassGenerator;
|
||||
import org.teavm.wasm.generate.WasmGenerationContext;
|
||||
import org.teavm.wasm.generate.WasmGenerator;
|
||||
import org.teavm.wasm.generate.WasmMangling;
|
||||
import org.teavm.wasm.model.WasmFunction;
|
||||
import org.teavm.wasm.model.WasmModule;
|
||||
import org.teavm.wasm.model.WasmType;
|
||||
import org.teavm.wasm.model.expression.WasmBlock;
|
||||
import org.teavm.wasm.model.expression.WasmBranch;
|
||||
import org.teavm.wasm.model.expression.WasmCall;
|
||||
import org.teavm.wasm.model.expression.WasmExpression;
|
||||
import org.teavm.wasm.model.expression.WasmInt32Constant;
|
||||
import org.teavm.wasm.model.expression.WasmInt32Subtype;
|
||||
import org.teavm.wasm.model.expression.WasmIntBinary;
|
||||
import org.teavm.wasm.model.expression.WasmIntBinaryOperation;
|
||||
import org.teavm.wasm.model.expression.WasmIntType;
|
||||
import org.teavm.wasm.model.expression.WasmLoadInt32;
|
||||
import org.teavm.wasm.model.expression.WasmReturn;
|
||||
import org.teavm.wasm.model.expression.WasmStoreInt32;
|
||||
import org.teavm.wasm.render.WasmRenderer;
|
||||
import org.teavm.wasm.runtime.WasmRuntime;
|
||||
|
||||
|
@ -76,19 +99,46 @@ public class WasmTarget implements TeaVMTarget {
|
|||
MethodReference method = new MethodReference(WasmRuntime.class, "remainder", type, type, type);
|
||||
dependencyChecker.linkMethod(method, null).use();
|
||||
}
|
||||
|
||||
dependencyChecker.linkMethod(new MethodReference(Allocator.class, "allocate",
|
||||
RuntimeClass.class, Address.class), null).use();
|
||||
dependencyChecker.linkMethod(new MethodReference(Allocator.class, "<clinit>", void.class), null).use();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void emit(ListableClassHolderSource classes, OutputStream output, BuildTarget buildTarget) {
|
||||
Decompiler decompiler = new Decompiler(classes, controller.getClassLoader(), new HashSet<>(), new HashSet<>());
|
||||
int address = 256;
|
||||
|
||||
WasmClassGenerator classGenerator = new WasmClassGenerator(classes, address);
|
||||
for (String className : classes.getClassNames()) {
|
||||
classGenerator.addClass(className);
|
||||
if (controller.wasCancelled()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
address = classGenerator.getAddress();
|
||||
|
||||
Decompiler decompiler = new Decompiler(classes, controller.getClassLoader(), new HashSet<>(),
|
||||
new HashSet<>());
|
||||
WasmGenerationContext context = new WasmGenerationContext(classes);
|
||||
WasmGenerator generator = new WasmGenerator(decompiler, classes, context);
|
||||
WasmGenerator generator = new WasmGenerator(decompiler, classes, context, classGenerator);
|
||||
|
||||
WasmModule module = new WasmModule();
|
||||
module.setMemorySize(64);
|
||||
|
||||
for (String className : classes.getClassNames()) {
|
||||
ClassHolder cls = classes.get(className);
|
||||
for (MethodHolder method : cls.getMethods()) {
|
||||
if (method.getOwnerName().equals(Allocator.class.getName())
|
||||
&& method.getName().equals("initialize")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (method.hasModifier(ElementModifier.NATIVE)) {
|
||||
if (method.getOwnerName().equals(Structure.class.getName())
|
||||
|| method.getOwnerName().equals(Address.class.getName())) {
|
||||
continue;
|
||||
}
|
||||
if (context.getImportedMethod(method.getReference()) == null) {
|
||||
CallLocation location = new CallLocation(method.getReference());
|
||||
controller.getDiagnostics().error(location, "Method {{m0}} is native but "
|
||||
|
@ -107,6 +157,27 @@ public class WasmTarget implements TeaVMTarget {
|
|||
}
|
||||
}
|
||||
|
||||
renderAllocatorInit(module, address);
|
||||
renderClinit(classes, classGenerator, module);
|
||||
if (controller.wasCancelled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
WasmFunction initFunction = new WasmFunction("__start__");
|
||||
classGenerator.contributeToInitializer(initFunction.getBody());
|
||||
for (String className : classes.getClassNames()) {
|
||||
ClassReader cls = classes.get(className);
|
||||
if (cls.getAnnotations().get(StaticInit.class.getName()) == null) {
|
||||
continue;
|
||||
}
|
||||
MethodReader clinit = cls.getMethod(new MethodDescriptor("<clinit>", void.class));
|
||||
if (clinit == null) {
|
||||
continue;
|
||||
}
|
||||
initFunction.getBody().add(new WasmCall(WasmMangling.mangleMethod(clinit.getReference())));
|
||||
}
|
||||
module.add(initFunction);
|
||||
|
||||
for (TeaVMEntryPoint entryPoint : controller.getEntryPoints().values()) {
|
||||
String mangledName = WasmMangling.mangleMethod(entryPoint.getReference());
|
||||
WasmFunction function = module.getFunctions().get(mangledName);
|
||||
|
@ -127,6 +198,57 @@ public class WasmTarget implements TeaVMTarget {
|
|||
}
|
||||
}
|
||||
|
||||
private void renderClinit(ListableClassReaderSource classes, WasmClassGenerator classGenerator,
|
||||
WasmModule module) {
|
||||
for (String className : classes.getClassNames()) {
|
||||
if (classGenerator.isStructure(className)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ClassReader cls = classes.get(className);
|
||||
MethodReader method = cls.getMethod(new MethodDescriptor("<clinit>", void.class));
|
||||
if (method == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
WasmFunction initFunction = new WasmFunction(WasmMangling.mangleInitializer(className));
|
||||
module.add(initFunction);
|
||||
|
||||
WasmBlock block = new WasmBlock(false);
|
||||
|
||||
int index = classGenerator.getClassPointer(className);
|
||||
WasmExpression initFlag = new WasmLoadInt32(4, new WasmInt32Constant(index), WasmInt32Subtype.INT32);
|
||||
initFlag = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.AND, initFlag,
|
||||
new WasmInt32Constant(RuntimeClass.INITIALIZED));
|
||||
block.getBody().add(new WasmBranch(initFlag, block));
|
||||
initFunction.getBody().add(block);
|
||||
|
||||
initFlag = new WasmLoadInt32(4, new WasmInt32Constant(index), WasmInt32Subtype.INT32);
|
||||
initFlag = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.OR, initFlag,
|
||||
new WasmInt32Constant(RuntimeClass.INITIALIZED));
|
||||
block.getBody().add(new WasmStoreInt32(4, new WasmInt32Constant(index), initFlag,
|
||||
WasmInt32Subtype.INT32));
|
||||
|
||||
if (method != null) {
|
||||
block.getBody().add(new WasmCall(WasmMangling.mangleMethod(method.getReference())));
|
||||
}
|
||||
|
||||
if (controller.wasCancelled()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void renderAllocatorInit(WasmModule module, int address) {
|
||||
address = (((address - 1) / 4096) + 1) * 4096;
|
||||
|
||||
WasmFunction function = new WasmFunction(WasmMangling.mangleMethod(new MethodReference(
|
||||
Allocator.class, "initialize", Address.class)));
|
||||
function.setResult(WasmType.INT32);
|
||||
function.getBody().add(new WasmReturn(new WasmInt32Constant(address)));
|
||||
module.add(function);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
TeaVM vm = new TeaVMBuilder(new WasmTarget()).build();
|
||||
vm.installPlugins();
|
||||
|
|
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
* 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.generate;
|
||||
|
||||
import com.carrotsearch.hppc.ObjectIntMap;
|
||||
import com.carrotsearch.hppc.ObjectIntOpenHashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.teavm.interop.Address;
|
||||
import org.teavm.interop.Structure;
|
||||
import org.teavm.model.ClassReader;
|
||||
import org.teavm.model.ClassReaderSource;
|
||||
import org.teavm.model.ElementModifier;
|
||||
import org.teavm.model.FieldReader;
|
||||
import org.teavm.model.FieldReference;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.wasm.model.expression.WasmExpression;
|
||||
import org.teavm.wasm.model.expression.WasmInt32Constant;
|
||||
import org.teavm.wasm.model.expression.WasmInt32Subtype;
|
||||
import org.teavm.wasm.model.expression.WasmStoreInt32;
|
||||
|
||||
public class WasmClassGenerator {
|
||||
private ClassReaderSource classSource;
|
||||
private int address;
|
||||
private Map<String, ClassBinaryData> binaryDataMap = new LinkedHashMap<>();
|
||||
|
||||
public WasmClassGenerator(ClassReaderSource classSource, int address) {
|
||||
this.classSource = classSource;
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public void addClass(String className) {
|
||||
if (binaryDataMap.containsKey(className)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ClassReader cls = classSource.get(className);
|
||||
ClassBinaryData binaryData = new ClassBinaryData();
|
||||
binaryDataMap.put(className, binaryData);
|
||||
|
||||
calculateLayout(cls, binaryData);
|
||||
if (binaryData.start < 0) {
|
||||
return;
|
||||
}
|
||||
binaryData.start = align(address, 4);
|
||||
binaryData.end = binaryData.start + 8;
|
||||
|
||||
address = binaryData.end;
|
||||
}
|
||||
|
||||
public int getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void contributeToInitializer(List<WasmExpression> initializer) {
|
||||
for (ClassBinaryData binaryData : binaryDataMap.values()) {
|
||||
if (binaryData.start < 0) {
|
||||
continue;
|
||||
}
|
||||
WasmExpression index = new WasmInt32Constant(binaryData.start);
|
||||
WasmExpression size = new WasmInt32Constant(binaryData.size);
|
||||
initializer.add(new WasmStoreInt32(4, index, size, WasmInt32Subtype.INT32));
|
||||
}
|
||||
}
|
||||
|
||||
public int getClassPointer(String className) {
|
||||
ClassBinaryData data = binaryDataMap.get(className);
|
||||
return data.start;
|
||||
}
|
||||
|
||||
public int getFieldOffset(FieldReference field) {
|
||||
ClassBinaryData data = binaryDataMap.get(field.getClassName());
|
||||
return data.fieldLayout.get(field.getFieldName());
|
||||
}
|
||||
|
||||
public boolean isStructure(String className) {
|
||||
ClassBinaryData data = binaryDataMap.get(className);
|
||||
return data.start < 0;
|
||||
}
|
||||
|
||||
private void calculateLayout(ClassReader cls, ClassBinaryData data) {
|
||||
if (cls.getName().equals(Structure.class.getName()) || cls.getName().equals(Address.class.getName())) {
|
||||
data.size = 0;
|
||||
data.start = -1;
|
||||
} else if (cls.getParent() != null && !cls.getParent().equals(cls.getName())) {
|
||||
addClass(cls.getParent());
|
||||
ClassBinaryData parentData = binaryDataMap.get(cls.getParent());
|
||||
data.size = parentData.size;
|
||||
if (parentData.start == -1) {
|
||||
data.start = -1;
|
||||
}
|
||||
} else {
|
||||
data.size = 4;
|
||||
}
|
||||
|
||||
for (FieldReader field : cls.getFields()) {
|
||||
int desiredAlignment = getDesiredAlignment(field.getType());
|
||||
if (field.hasModifier(ElementModifier.STATIC)) {
|
||||
int offset = align(address, desiredAlignment);
|
||||
data.fieldLayout.put(field.getName(), offset);
|
||||
address = offset + desiredAlignment;
|
||||
} else {
|
||||
int offset = align(data.size, desiredAlignment);
|
||||
data.fieldLayout.put(field.getName(), offset);
|
||||
data.size = offset + desiredAlignment;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int align(int base, int alignment) {
|
||||
return ((base - 1) / alignment + 1) * alignment;
|
||||
}
|
||||
|
||||
private int getDesiredAlignment(ValueType type) {
|
||||
if (type instanceof ValueType.Primitive) {
|
||||
switch (((ValueType.Primitive) type).getKind()) {
|
||||
case BOOLEAN:
|
||||
case BYTE:
|
||||
return 1;
|
||||
case SHORT:
|
||||
case CHARACTER:
|
||||
return 2;
|
||||
case INTEGER:
|
||||
case FLOAT:
|
||||
return 4;
|
||||
case LONG:
|
||||
case DOUBLE:
|
||||
return 8;
|
||||
}
|
||||
}
|
||||
return 4;
|
||||
}
|
||||
|
||||
private class ClassBinaryData {
|
||||
int start;
|
||||
int end;
|
||||
|
||||
int size;
|
||||
ObjectIntMap<String> fieldLayout = new ObjectIntOpenHashMap<>();
|
||||
}
|
||||
}
|
|
@ -22,8 +22,11 @@ import org.teavm.model.AnnotationReader;
|
|||
import org.teavm.model.AnnotationValue;
|
||||
import org.teavm.model.ClassReader;
|
||||
import org.teavm.model.ClassReaderSource;
|
||||
import org.teavm.model.FieldReader;
|
||||
import org.teavm.model.FieldReference;
|
||||
import org.teavm.model.MethodReader;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.ValueType;
|
||||
|
||||
public class WasmGenerationContext {
|
||||
private ClassReaderSource classSource;
|
||||
|
@ -58,6 +61,16 @@ public class WasmGenerationContext {
|
|||
});
|
||||
}
|
||||
|
||||
public ClassReaderSource getClassSource() {
|
||||
return classSource;
|
||||
}
|
||||
|
||||
public ValueType getFieldType(FieldReference fieldReference) {
|
||||
ClassReader cls = classSource.get(fieldReference.getClassName());
|
||||
FieldReader field = cls.getField(fieldReference.getFieldName());
|
||||
return field.getType();
|
||||
}
|
||||
|
||||
public class ImportedMethod {
|
||||
public final String name;
|
||||
public final String module;
|
||||
|
|
|
@ -59,9 +59,17 @@ import org.teavm.ast.UnaryExpr;
|
|||
import org.teavm.ast.UnwrapArrayExpr;
|
||||
import org.teavm.ast.VariableExpr;
|
||||
import org.teavm.ast.WhileStatement;
|
||||
import org.teavm.interop.Address;
|
||||
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.runtime.Allocator;
|
||||
import org.teavm.runtime.RuntimeClass;
|
||||
import org.teavm.wasm.model.WasmFunction;
|
||||
import org.teavm.wasm.model.WasmLocal;
|
||||
import org.teavm.wasm.model.WasmType;
|
||||
import org.teavm.wasm.model.expression.WasmBlock;
|
||||
import org.teavm.wasm.model.expression.WasmBranch;
|
||||
import org.teavm.wasm.model.expression.WasmBreak;
|
||||
|
@ -77,17 +85,28 @@ 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.WasmInt32Constant;
|
||||
import org.teavm.wasm.model.expression.WasmInt32Subtype;
|
||||
import org.teavm.wasm.model.expression.WasmInt64Constant;
|
||||
import org.teavm.wasm.model.expression.WasmInt64Subtype;
|
||||
import org.teavm.wasm.model.expression.WasmIntBinary;
|
||||
import org.teavm.wasm.model.expression.WasmIntBinaryOperation;
|
||||
import org.teavm.wasm.model.expression.WasmIntType;
|
||||
import org.teavm.wasm.model.expression.WasmLoadFloat32;
|
||||
import org.teavm.wasm.model.expression.WasmLoadFloat64;
|
||||
import org.teavm.wasm.model.expression.WasmLoadInt32;
|
||||
import org.teavm.wasm.model.expression.WasmLoadInt64;
|
||||
import org.teavm.wasm.model.expression.WasmReturn;
|
||||
import org.teavm.wasm.model.expression.WasmSetLocal;
|
||||
import org.teavm.wasm.model.expression.WasmStoreFloat32;
|
||||
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.runtime.WasmRuntime;
|
||||
|
||||
class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||
private WasmGenerationContext context;
|
||||
private WasmClassGenerator classGenerator;
|
||||
private WasmFunction function;
|
||||
private int firstVariable;
|
||||
private IdentifiedStatement currentContinueTarget;
|
||||
|
@ -97,8 +116,10 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
private Set<WasmBlock> usedBlocks = new HashSet<>();
|
||||
WasmExpression result;
|
||||
|
||||
WasmGenerationVisitor(WasmGenerationContext context, WasmFunction function, int firstVariable) {
|
||||
WasmGenerationVisitor(WasmGenerationContext context, WasmClassGenerator classGenerator,
|
||||
WasmFunction function, int firstVariable) {
|
||||
this.context = context;
|
||||
this.classGenerator = classGenerator;
|
||||
this.function = function;
|
||||
this.firstVariable = firstVariable;
|
||||
}
|
||||
|
@ -350,11 +371,48 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
WasmLocal local = function.getLocalVariables().get(varExpr.getIndex() - firstVariable);
|
||||
statement.getRightValue().acceptVisitor(this);
|
||||
result = new WasmSetLocal(local, result);
|
||||
} else if (left instanceof QualificationExpr) {
|
||||
QualificationExpr lhs = (QualificationExpr) left;
|
||||
storeField(lhs.getQualified(), lhs.getField(), statement.getRightValue());
|
||||
} else {
|
||||
throw new UnsupportedOperationException("This expression is not supported yet");
|
||||
}
|
||||
}
|
||||
|
||||
private void storeField(Expr qualified, FieldReference field, Expr value) {
|
||||
WasmExpression address = getAddress(qualified, field);
|
||||
ValueType type = context.getFieldType(field);
|
||||
value.acceptVisitor(this);
|
||||
if (type instanceof ValueType.Primitive) {
|
||||
switch (((ValueType.Primitive) type).getKind()) {
|
||||
case BOOLEAN:
|
||||
case BYTE:
|
||||
result = new WasmStoreInt32(1, address, result, WasmInt32Subtype.INT8);
|
||||
break;
|
||||
case SHORT:
|
||||
result = new WasmStoreInt32(2, address, result, WasmInt32Subtype.INT16);
|
||||
break;
|
||||
case CHARACTER:
|
||||
result = new WasmStoreInt32(2, address, result, WasmInt32Subtype.UINT16);
|
||||
break;
|
||||
case INTEGER:
|
||||
result = new WasmStoreInt32(4, address, result, WasmInt32Subtype.INT32);
|
||||
break;
|
||||
case LONG:
|
||||
result = new WasmStoreInt64(8, address, result, WasmInt64Subtype.INT64);
|
||||
break;
|
||||
case FLOAT:
|
||||
result = new WasmStoreFloat32(4, address, result);
|
||||
break;
|
||||
case DOUBLE:
|
||||
result = new WasmStoreFloat64(8, address, result);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
result = new WasmStoreInt32(4, address, result, WasmInt32Subtype.INT32);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ConditionalExpr expr) {
|
||||
expr.getCondition().acceptVisitor(this);
|
||||
|
@ -371,7 +429,9 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
WasmBlock block = new WasmBlock(false);
|
||||
for (Statement part : statement.getSequence()) {
|
||||
part.acceptVisitor(this);
|
||||
block.getBody().add(result);
|
||||
if (result != null) {
|
||||
block.getBody().add(result);
|
||||
}
|
||||
}
|
||||
result = block;
|
||||
}
|
||||
|
@ -399,11 +459,15 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
WasmConditional conditional = new WasmConditional(result);
|
||||
for (Statement part : statement.getConsequent()) {
|
||||
part.acceptVisitor(this);
|
||||
conditional.getThenBlock().getBody().add(result);
|
||||
if (result != null) {
|
||||
conditional.getThenBlock().getBody().add(result);
|
||||
}
|
||||
}
|
||||
for (Statement part : statement.getAlternative()) {
|
||||
part.acceptVisitor(this);
|
||||
conditional.getElseBlock().getBody().add(result);
|
||||
if (result != null) {
|
||||
conditional.getElseBlock().getBody().add(result);
|
||||
}
|
||||
}
|
||||
result = conditional;
|
||||
}
|
||||
|
@ -479,7 +543,9 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
|
||||
for (Statement part : statement.getBody()) {
|
||||
part.acceptVisitor(this);
|
||||
loop.getBody().add(result);
|
||||
if (result != null) {
|
||||
loop.getBody().add(result);
|
||||
}
|
||||
}
|
||||
loop.getBody().add(new WasmBreak(loop));
|
||||
|
||||
|
@ -498,6 +564,11 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
|
||||
@Override
|
||||
public void visit(InvocationExpr expr) {
|
||||
if (expr.getMethod().getClassName().equals(Address.class.getName())) {
|
||||
generateAddressInvocation(expr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (expr.getType() == InvocationType.STATIC || expr.getType() == InvocationType.SPECIAL) {
|
||||
String methodName = WasmMangling.mangleMethod(expr.getMethod());
|
||||
|
||||
|
@ -513,6 +584,114 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
private void generateAddressInvocation(InvocationExpr expr) {
|
||||
switch (expr.getMethod().getName()) {
|
||||
case "toInt":
|
||||
case "toStructure":
|
||||
expr.getArguments().get(0).acceptVisitor(this);
|
||||
break;
|
||||
case "toLong":
|
||||
expr.getArguments().get(0).acceptVisitor(this);
|
||||
result = new WasmConversion(WasmType.INT32, WasmType.INT64, false, result);
|
||||
break;
|
||||
case "fromInt":
|
||||
expr.getArguments().get(0).acceptVisitor(this);
|
||||
break;
|
||||
case "fromLong":
|
||||
expr.getArguments().get(0).acceptVisitor(this);
|
||||
result = new WasmConversion(WasmType.INT64, WasmType.INT32, false, result);
|
||||
break;
|
||||
case "add": {
|
||||
expr.getArguments().get(0).acceptVisitor(this);
|
||||
WasmExpression base = result;
|
||||
expr.getArguments().get(1).acceptVisitor(this);
|
||||
WasmExpression offset = result;
|
||||
if (expr.getMethod().parameterType(0) == ValueType.LONG) {
|
||||
offset = new WasmConversion(WasmType.INT64, WasmType.INT32, false, offset);
|
||||
}
|
||||
result = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD, base, offset);
|
||||
break;
|
||||
}
|
||||
case "getByte":
|
||||
expr.getArguments().get(0).acceptVisitor(this);
|
||||
result = new WasmLoadInt32(1, result, WasmInt32Subtype.INT8);
|
||||
break;
|
||||
case "getShort":
|
||||
expr.getArguments().get(0).acceptVisitor(this);
|
||||
result = new WasmLoadInt32(2, result, WasmInt32Subtype.INT16);
|
||||
break;
|
||||
case "getChar":
|
||||
expr.getArguments().get(0).acceptVisitor(this);
|
||||
result = new WasmLoadInt32(2, result, WasmInt32Subtype.UINT16);
|
||||
break;
|
||||
case "getInt":
|
||||
expr.getArguments().get(0).acceptVisitor(this);
|
||||
result = new WasmLoadInt32(4, result, WasmInt32Subtype.INT32);
|
||||
break;
|
||||
case "getLong":
|
||||
expr.getArguments().get(0).acceptVisitor(this);
|
||||
result = new WasmLoadInt64(8, result, WasmInt64Subtype.INT64);
|
||||
break;
|
||||
case "getFloat":
|
||||
expr.getArguments().get(0).acceptVisitor(this);
|
||||
result = new WasmLoadFloat32(4, result);
|
||||
break;
|
||||
case "getDouble":
|
||||
expr.getArguments().get(0).acceptVisitor(this);
|
||||
result = new WasmLoadFloat64(8, result);
|
||||
break;
|
||||
case "putByte": {
|
||||
expr.getArguments().get(0).acceptVisitor(this);
|
||||
WasmExpression address = result;
|
||||
expr.getArguments().get(1).acceptVisitor(this);
|
||||
result = new WasmStoreInt32(1, address, result, WasmInt32Subtype.INT8);
|
||||
break;
|
||||
}
|
||||
case "putShort": {
|
||||
expr.getArguments().get(0).acceptVisitor(this);
|
||||
WasmExpression address = result;
|
||||
expr.getArguments().get(1).acceptVisitor(this);
|
||||
result = new WasmStoreInt32(2, address, result, WasmInt32Subtype.INT16);
|
||||
break;
|
||||
}
|
||||
case "putChar": {
|
||||
expr.getArguments().get(0).acceptVisitor(this);
|
||||
WasmExpression address = result;
|
||||
expr.getArguments().get(1).acceptVisitor(this);
|
||||
result = new WasmStoreInt32(2, address, result, WasmInt32Subtype.UINT16);
|
||||
break;
|
||||
}
|
||||
case "putInt": {
|
||||
expr.getArguments().get(0).acceptVisitor(this);
|
||||
WasmExpression address = result;
|
||||
expr.getArguments().get(1).acceptVisitor(this);
|
||||
result = new WasmStoreInt32(4, address, result, WasmInt32Subtype.INT32);
|
||||
break;
|
||||
}
|
||||
case "putLong": {
|
||||
expr.getArguments().get(0).acceptVisitor(this);
|
||||
WasmExpression address = result;
|
||||
expr.getArguments().get(1).acceptVisitor(this);
|
||||
result = new WasmStoreInt64(8, address, result, WasmInt64Subtype.INT64);
|
||||
break;
|
||||
}
|
||||
case "putFloat": {
|
||||
expr.getArguments().get(0).acceptVisitor(this);
|
||||
WasmExpression address = result;
|
||||
expr.getArguments().get(1).acceptVisitor(this);
|
||||
result = new WasmStoreFloat32(4, address, result);
|
||||
break;
|
||||
}
|
||||
case "putDouble": {
|
||||
expr.getArguments().get(0).acceptVisitor(this);
|
||||
WasmExpression address = result;
|
||||
expr.getArguments().get(1).acceptVisitor(this);
|
||||
result = new WasmStoreFloat64(8, address, result);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(BlockStatement statement) {
|
||||
WasmBlock block = new WasmBlock(false);
|
||||
|
@ -523,7 +702,9 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
|
||||
for (Statement part : statement.getBody()) {
|
||||
part.acceptVisitor(this);
|
||||
block.getBody().add(result);
|
||||
if (result != null) {
|
||||
block.getBody().add(result);
|
||||
}
|
||||
}
|
||||
|
||||
if (statement.getId() != null) {
|
||||
|
@ -535,6 +716,48 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
|
||||
@Override
|
||||
public void visit(QualificationExpr expr) {
|
||||
WasmExpression address = getAddress(expr.getQualified(), expr.getField());
|
||||
|
||||
ValueType type = context.getFieldType(expr.getField());
|
||||
if (type instanceof ValueType.Primitive) {
|
||||
switch (((ValueType.Primitive) type).getKind()) {
|
||||
case BOOLEAN:
|
||||
case BYTE:
|
||||
result = new WasmLoadInt32(1, address, WasmInt32Subtype.INT8);
|
||||
break;
|
||||
case SHORT:
|
||||
result = new WasmLoadInt32(2, address, WasmInt32Subtype.INT16);
|
||||
break;
|
||||
case CHARACTER:
|
||||
result = new WasmLoadInt32(2, address, WasmInt32Subtype.UINT16);
|
||||
break;
|
||||
case INTEGER:
|
||||
result = new WasmLoadInt32(4, address, WasmInt32Subtype.INT32);
|
||||
break;
|
||||
case LONG:
|
||||
result = new WasmLoadInt64(8, address, WasmInt64Subtype.INT64);
|
||||
break;
|
||||
case FLOAT:
|
||||
result = new WasmLoadFloat32(4, address);
|
||||
break;
|
||||
case DOUBLE:
|
||||
result = new WasmLoadFloat64(8, address);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
result = new WasmLoadInt32(4, address, WasmInt32Subtype.INT32);
|
||||
}
|
||||
}
|
||||
|
||||
private WasmExpression getAddress(Expr qualified, FieldReference field) {
|
||||
int offset = classGenerator.getFieldOffset(field);
|
||||
if (qualified == null) {
|
||||
return new WasmInt32Constant(offset);
|
||||
} else {
|
||||
qualified.acceptVisitor(this);
|
||||
return new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD, result,
|
||||
new WasmInt32Constant(offset));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -550,6 +773,12 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
|
||||
@Override
|
||||
public void visit(NewExpr expr) {
|
||||
int tag = classGenerator.getClassPointer(expr.getConstructedClass());
|
||||
String allocName = WasmMangling.mangleMethod(new MethodReference(Allocator.class, "allocate",
|
||||
RuntimeClass.class, Address.class));
|
||||
WasmCall call = new WasmCall(allocName);
|
||||
call.getArguments().add(new WasmInt32Constant(tag));
|
||||
result = call;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -598,6 +827,22 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
|
||||
@Override
|
||||
public void visit(InitClassStatement statement) {
|
||||
if (hasClinit(statement.getClassName())) {
|
||||
result = new WasmCall(WasmMangling.mangleInitializer(statement.getClassName()));
|
||||
} else {
|
||||
result = null;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasClinit(String className) {
|
||||
if (classGenerator.isStructure(className)) {
|
||||
return false;
|
||||
}
|
||||
ClassReader cls = context.getClassSource().get(className);
|
||||
if (cls == null) {
|
||||
return false;
|
||||
}
|
||||
return cls.getMethod(new MethodDescriptor("<clinit>", ValueType.VOID)) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -35,11 +35,14 @@ public class WasmGenerator {
|
|||
private Decompiler decompiler;
|
||||
private ClassHolderSource classSource;
|
||||
private WasmGenerationContext context;
|
||||
private WasmClassGenerator classGenerator;
|
||||
|
||||
public WasmGenerator(Decompiler decompiler, ClassHolderSource classSource, WasmGenerationContext context) {
|
||||
public WasmGenerator(Decompiler decompiler, ClassHolderSource classSource, WasmGenerationContext context,
|
||||
WasmClassGenerator classGenerator) {
|
||||
this.decompiler = decompiler;
|
||||
this.classSource = classSource;
|
||||
this.context = context;
|
||||
this.classGenerator = classGenerator;
|
||||
}
|
||||
|
||||
public WasmFunction generate(MethodReference methodReference) {
|
||||
|
@ -79,7 +82,7 @@ public class WasmGenerator {
|
|||
function.setResult(WasmGeneratorUtil.mapType(methodReference.getReturnType()));
|
||||
}
|
||||
|
||||
WasmGenerationVisitor visitor = new WasmGenerationVisitor(context, function, firstVariable);
|
||||
WasmGenerationVisitor visitor = new WasmGenerationVisitor(context, classGenerator, function, firstVariable);
|
||||
methodAst.getBody().acceptVisitor(visitor);
|
||||
function.getBody().add(visitor.result);
|
||||
|
||||
|
|
|
@ -36,6 +36,10 @@ public final class WasmMangling {
|
|||
return sb.toString();
|
||||
}
|
||||
|
||||
public static String mangleInitializer(String className) {
|
||||
return "clinit$" + mangleString(className);
|
||||
}
|
||||
|
||||
private static String mangleString(String string) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < string.length(); ++i) {
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class WasmMemorySegment {
|
||||
private int offset;
|
||||
private byte[] data = new byte[0];
|
||||
|
||||
public int getOffset() {
|
||||
return offset;
|
||||
}
|
||||
|
||||
public void setOffset(int offset) {
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
public byte[] getData() {
|
||||
return data.clone();
|
||||
}
|
||||
|
||||
public void setData(byte[] data) {
|
||||
this.data = data.clone();
|
||||
}
|
||||
|
||||
public int getLength() {
|
||||
return data.length;
|
||||
}
|
||||
|
||||
public void setLength(int value) {
|
||||
data = Arrays.copyOf(data, value);
|
||||
}
|
||||
|
||||
public byte[] getData(int offset, int size) {
|
||||
return Arrays.copyOfRange(data, offset, size);
|
||||
}
|
||||
}
|
|
@ -22,9 +22,12 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
|
||||
public class WasmModule {
|
||||
private int memorySize;
|
||||
private List<WasmMemorySegment> segments = new ArrayList<>();
|
||||
private Map<String, WasmFunction> functions = new LinkedHashMap<>();
|
||||
private Map<String, WasmFunction> readonlyFunctions = Collections.unmodifiableMap(functions);
|
||||
private List<WasmFunction> functionTable = new ArrayList<>();
|
||||
private WasmFunction startFunction;
|
||||
|
||||
public void add(WasmFunction function) {
|
||||
if (functions.containsKey(function.getName())) {
|
||||
|
@ -44,4 +47,24 @@ public class WasmModule {
|
|||
public List<WasmFunction> getFunctionTable() {
|
||||
return functionTable;
|
||||
}
|
||||
|
||||
public List<WasmMemorySegment> getSegments() {
|
||||
return segments;
|
||||
}
|
||||
|
||||
public int getMemorySize() {
|
||||
return memorySize;
|
||||
}
|
||||
|
||||
public void setMemorySize(int memorySize) {
|
||||
this.memorySize = memorySize;
|
||||
}
|
||||
|
||||
public WasmFunction getStartFunction() {
|
||||
return startFunction;
|
||||
}
|
||||
|
||||
public void setStartFunction(WasmFunction startFunction) {
|
||||
this.startFunction = startFunction;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ package org.teavm.wasm.render;
|
|||
import java.util.List;
|
||||
import org.teavm.wasm.model.WasmFunction;
|
||||
import org.teavm.wasm.model.WasmLocal;
|
||||
import org.teavm.wasm.model.WasmMemorySegment;
|
||||
import org.teavm.wasm.model.WasmModule;
|
||||
import org.teavm.wasm.model.WasmType;
|
||||
import org.teavm.wasm.model.expression.WasmExpression;
|
||||
|
@ -47,6 +48,7 @@ public class WasmRenderer {
|
|||
|
||||
public void render(WasmModule module) {
|
||||
visitor.open().append("module");
|
||||
renderMemory(module);
|
||||
for (WasmFunction function : module.getFunctions().values()) {
|
||||
if (function.getImportName() == null) {
|
||||
continue;
|
||||
|
@ -68,6 +70,35 @@ public class WasmRenderer {
|
|||
visitor.close().lf();
|
||||
}
|
||||
|
||||
public void renderMemory(WasmModule module) {
|
||||
visitor.open().append("memory " + module.getMemorySize());
|
||||
for (WasmMemorySegment segment : module.getSegments()) {
|
||||
visitor.lf().open().append("segment " + segment.getLength());
|
||||
visitor.indent();
|
||||
for (int i = 0; i < segment.getLength(); i += 256) {
|
||||
visitor.lf().append("\"");
|
||||
byte[] part = segment.getData(i, Math.max(segment.getLength(), i + 256) - i);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int j = 0; j < part.length; ++j) {
|
||||
int b = part[j] << 24 >>> 24;
|
||||
if (b < ' ' || b > 126) {
|
||||
sb.append("\\0x" + Character.forDigit(b >> 4, 16) + Character.forDigit(b & 0xF, 16));
|
||||
} else if (b == '\\') {
|
||||
sb.append("\\\\");
|
||||
} else if (b == '"') {
|
||||
sb.append("\\\"");
|
||||
} else {
|
||||
sb.append((char) b);
|
||||
}
|
||||
}
|
||||
visitor.append(sb.toString()).append("\"");
|
||||
}
|
||||
visitor.outdent();
|
||||
visitor.close();
|
||||
}
|
||||
visitor.close().lf();
|
||||
}
|
||||
|
||||
public void renderImport(WasmFunction function) {
|
||||
String importModule = function.getImportModule();
|
||||
if (importModule == null) {
|
||||
|
|
|
@ -356,42 +356,134 @@ class WasmRenderingVisitor implements WasmExpressionVisitor {
|
|||
|
||||
@Override
|
||||
public void visit(WasmLoadInt32 expression) {
|
||||
|
||||
open();
|
||||
switch (expression.getConvertFrom()) {
|
||||
case INT8:
|
||||
append("i32.load8_s");
|
||||
break;
|
||||
case UINT8:
|
||||
append("i32.load8_u");
|
||||
break;
|
||||
case INT16:
|
||||
append("i32.load16_s");
|
||||
break;
|
||||
case UINT16:
|
||||
append("i32.load16_u");
|
||||
break;
|
||||
case INT32:
|
||||
append("i32.load");
|
||||
break;
|
||||
}
|
||||
append(" align=" + expression.getAlignment());
|
||||
line(expression.getIndex());
|
||||
close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmLoadInt64 expression) {
|
||||
|
||||
open();
|
||||
switch (expression.getConvertFrom()) {
|
||||
case INT8:
|
||||
append("i64.load8_s");
|
||||
break;
|
||||
case UINT8:
|
||||
append("i64.load8_u");
|
||||
break;
|
||||
case INT16:
|
||||
append("i64.load16_s");
|
||||
break;
|
||||
case UINT16:
|
||||
append("i64.load16_u");
|
||||
break;
|
||||
case INT32:
|
||||
append("i64.load32_s");
|
||||
break;
|
||||
case UINT32:
|
||||
append("i64.load32_u");
|
||||
break;
|
||||
case INT64:
|
||||
append("i64.load");
|
||||
break;
|
||||
}
|
||||
append(" align=" + expression.getAlignment());
|
||||
line(expression.getIndex());
|
||||
close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmLoadFloat32 expression) {
|
||||
|
||||
open().append("f32.load align=" + expression.getAlignment());
|
||||
line(expression.getIndex());
|
||||
close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmLoadFloat64 expression) {
|
||||
|
||||
open().append("f64.load align=" + expression.getAlignment());
|
||||
line(expression.getIndex());
|
||||
close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmStoreInt32 expression) {
|
||||
|
||||
open();
|
||||
switch (expression.getConvertTo()) {
|
||||
case INT8:
|
||||
case UINT8:
|
||||
append("i32.store8");
|
||||
case INT16:
|
||||
case UINT16:
|
||||
append("i32.store16");
|
||||
break;
|
||||
case INT32:
|
||||
append("i32.store");
|
||||
break;
|
||||
}
|
||||
append(" align=" + expression.getAlignment());
|
||||
line(expression.getIndex());
|
||||
line(expression.getValue());
|
||||
close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmStoreInt64 expression) {
|
||||
|
||||
open();
|
||||
switch (expression.getConvertTo()) {
|
||||
case INT8:
|
||||
case UINT8:
|
||||
append("i64.store8");
|
||||
case INT16:
|
||||
case UINT16:
|
||||
append("i64.store16");
|
||||
break;
|
||||
case INT32:
|
||||
case UINT32:
|
||||
append("i64.store32");
|
||||
break;
|
||||
case INT64:
|
||||
append("i64.store");
|
||||
break;
|
||||
}
|
||||
append(" align=" + expression.getAlignment());
|
||||
line(expression.getIndex());
|
||||
line(expression.getValue());
|
||||
close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmStoreFloat32 expression) {
|
||||
|
||||
open().append("f32.store align=" + expression.getAlignment());
|
||||
line(expression.getIndex());
|
||||
line(expression.getValue());
|
||||
close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmStoreFloat64 expression) {
|
||||
|
||||
open().append("f64.store align=" + expression.getAlignment());
|
||||
line(expression.getIndex());
|
||||
line(expression.getValue());
|
||||
close();
|
||||
}
|
||||
|
||||
private String getIdentifier(String suggested) {
|
||||
|
|
60
interop/core/src/main/java/org/teavm/interop/Address.java
Normal file
60
interop/core/src/main/java/org/teavm/interop/Address.java
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* 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.interop;
|
||||
|
||||
public final class Address {
|
||||
public final native Address add(int offset);
|
||||
|
||||
public final native Address add(long offset);
|
||||
|
||||
public final native int toInt();
|
||||
|
||||
public final native long toLong();
|
||||
|
||||
public final native <T extends Structure> T toStructure();
|
||||
|
||||
public final native byte getByte();
|
||||
|
||||
public final native void putByte(byte value);
|
||||
|
||||
public final native char getChar();
|
||||
|
||||
public final native void putChar(char value);
|
||||
|
||||
public final native short getShort();
|
||||
|
||||
public final native void putShort(short value);
|
||||
|
||||
public final native int getInt();
|
||||
|
||||
public final native void putInt(int value);
|
||||
|
||||
public final native long getLong();
|
||||
|
||||
public final native void putLong(long value);
|
||||
|
||||
public final native float getFloat();
|
||||
|
||||
public final native void putFloat(float value);
|
||||
|
||||
public final native double getDouble();
|
||||
|
||||
public final native void putDouble(double value);
|
||||
|
||||
public static native Address fromInt(int value);
|
||||
|
||||
public static native Address fromLong(long value);
|
||||
}
|
26
interop/core/src/main/java/org/teavm/interop/StaticInit.java
Normal file
26
interop/core/src/main/java/org/teavm/interop/StaticInit.java
Normal file
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* 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.interop;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface StaticInit {
|
||||
}
|
26
interop/core/src/main/java/org/teavm/interop/Structure.java
Normal file
26
interop/core/src/main/java/org/teavm/interop/Structure.java
Normal file
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* 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.interop;
|
||||
|
||||
public class Structure {
|
||||
public native <T extends Structure> T cast();
|
||||
|
||||
public native Address toAddress();
|
||||
|
||||
public native int sizeOf(Class<? extends Structure> type);
|
||||
|
||||
public native <T extends Structure> T add(T base, int offset);
|
||||
}
|
Loading…
Reference in New Issue
Block a user