mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14:10 -08:00
WASM: implementing intrinsics to access resources
This commit is contained in:
parent
05d4652c86
commit
9e6061c3f1
|
@ -26,6 +26,7 @@ public final class Example {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
System.out.println(Integer.parseInt("123"));
|
||||||
testFibonacci();
|
testFibonacci();
|
||||||
testClasses();
|
testClasses();
|
||||||
testVirtualCall();
|
testVirtualCall();
|
||||||
|
@ -38,7 +39,7 @@ public final class Example {
|
||||||
testArrayIsObject();
|
testArrayIsObject();
|
||||||
testIsAssignableFrom();
|
testIsAssignableFrom();
|
||||||
testExceptions();
|
testExceptions();
|
||||||
testBigInteger();
|
//testBigInteger();
|
||||||
testGC();
|
testGC();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,9 +23,14 @@ public class WasmLoadFloat32 extends WasmExpression implements WasmMemoryAccess
|
||||||
private int offset;
|
private int offset;
|
||||||
|
|
||||||
public WasmLoadFloat32(int alignment, WasmExpression index) {
|
public WasmLoadFloat32(int alignment, WasmExpression index) {
|
||||||
|
this(alignment, index, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public WasmLoadFloat32(int alignment, WasmExpression index, int offset) {
|
||||||
Objects.requireNonNull(index);
|
Objects.requireNonNull(index);
|
||||||
this.alignment = alignment;
|
this.alignment = alignment;
|
||||||
this.index = index;
|
this.index = index;
|
||||||
|
this.offset = offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getAlignment() {
|
public int getAlignment() {
|
||||||
|
|
|
@ -23,9 +23,14 @@ public class WasmLoadFloat64 extends WasmExpression implements WasmMemoryAccess
|
||||||
private int offset;
|
private int offset;
|
||||||
|
|
||||||
public WasmLoadFloat64(int alignment, WasmExpression index) {
|
public WasmLoadFloat64(int alignment, WasmExpression index) {
|
||||||
|
this(alignment, index, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public WasmLoadFloat64(int alignment, WasmExpression index, int offset) {
|
||||||
Objects.requireNonNull(index);
|
Objects.requireNonNull(index);
|
||||||
this.alignment = alignment;
|
this.alignment = alignment;
|
||||||
this.index = index;
|
this.index = index;
|
||||||
|
this.offset = offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getAlignment() {
|
public int getAlignment() {
|
||||||
|
|
|
@ -24,11 +24,16 @@ public class WasmLoadInt32 extends WasmExpression implements WasmMemoryAccess {
|
||||||
private int offset;
|
private int offset;
|
||||||
|
|
||||||
public WasmLoadInt32(int alignment, WasmExpression index, WasmInt32Subtype convertFrom) {
|
public WasmLoadInt32(int alignment, WasmExpression index, WasmInt32Subtype convertFrom) {
|
||||||
|
this(alignment, index, convertFrom, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public WasmLoadInt32(int alignment, WasmExpression index, WasmInt32Subtype convertFrom, int offset) {
|
||||||
Objects.requireNonNull(index);
|
Objects.requireNonNull(index);
|
||||||
Objects.requireNonNull(convertFrom);
|
Objects.requireNonNull(convertFrom);
|
||||||
this.alignment = alignment;
|
this.alignment = alignment;
|
||||||
this.index = index;
|
this.index = index;
|
||||||
this.convertFrom = convertFrom;
|
this.convertFrom = convertFrom;
|
||||||
|
this.offset = offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getAlignment() {
|
public int getAlignment() {
|
||||||
|
|
|
@ -24,11 +24,16 @@ public class WasmLoadInt64 extends WasmExpression implements WasmMemoryAccess {
|
||||||
private int offset;
|
private int offset;
|
||||||
|
|
||||||
public WasmLoadInt64(int alignment, WasmExpression index, WasmInt64Subtype convertFrom) {
|
public WasmLoadInt64(int alignment, WasmExpression index, WasmInt64Subtype convertFrom) {
|
||||||
|
this(alignment, index, convertFrom, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public WasmLoadInt64(int alignment, WasmExpression index, WasmInt64Subtype convertFrom, int offset) {
|
||||||
Objects.requireNonNull(index);
|
Objects.requireNonNull(index);
|
||||||
Objects.requireNonNull(convertFrom);
|
Objects.requireNonNull(convertFrom);
|
||||||
this.alignment = alignment;
|
this.alignment = alignment;
|
||||||
this.index = index;
|
this.index = index;
|
||||||
this.convertFrom = convertFrom;
|
this.convertFrom = convertFrom;
|
||||||
|
this.offset = offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getAlignment() {
|
public int getAlignment() {
|
||||||
|
|
|
@ -18,7 +18,9 @@ package org.teavm.model;
|
||||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||||
import com.fasterxml.jackson.annotation.JsonValue;
|
import com.fasterxml.jackson.annotation.JsonValue;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Specifies a fully qualified name of a method, including its name, class name, parameter types
|
* <p>Specifies a fully qualified name of a method, including its name, class name, parameter types
|
||||||
|
@ -162,6 +164,12 @@ public class MethodReference implements Serializable {
|
||||||
return desc != null ? new MethodReference(className, desc) : null;
|
return desc != null ? new MethodReference(className, desc) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static MethodReference parse(Method method) {
|
||||||
|
ValueType[] signature = Stream.concat(Arrays.stream(method.getParameterTypes()).map(ValueType::parse),
|
||||||
|
Stream.of(ValueType.parse(method.getReturnType()))).toArray(ValueType[]::new);
|
||||||
|
return new MethodReference(method.getDeclaringClass().getName(), method.getName(), signature);
|
||||||
|
}
|
||||||
|
|
||||||
public String signatureToString() {
|
public String signatureToString() {
|
||||||
return getDescriptor().signatureToString();
|
return getDescriptor().signatureToString();
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,7 +112,7 @@ public class MetadataIntrinsic implements WasmIntrinsic {
|
||||||
private void writeValueTo(BinaryWriter writer, WasmStringPool stringPool, Class<?> type, DataValue target,
|
private void writeValueTo(BinaryWriter writer, WasmStringPool stringPool, Class<?> type, DataValue target,
|
||||||
int index, Object value) {
|
int index, Object value) {
|
||||||
if (type == String.class) {
|
if (type == String.class) {
|
||||||
target.setAddress(index, stringPool.getStringPointer((String) value));
|
target.setAddress(index, value != null ? stringPool.getStringPointer((String) value) : 0);
|
||||||
} else if (type == boolean.class) {
|
} else if (type == boolean.class) {
|
||||||
target.setByte(index, (boolean) value ? (byte) 1 : 0);
|
target.setByte(index, (boolean) value ? (byte) 1 : 0);
|
||||||
} else if (type == byte.class) {
|
} else if (type == byte.class) {
|
||||||
|
@ -132,6 +132,8 @@ public class MetadataIntrinsic implements WasmIntrinsic {
|
||||||
} else if (value instanceof ResourceTypeDescriptorProvider && value instanceof Resource) {
|
} else if (value instanceof ResourceTypeDescriptorProvider && value instanceof Resource) {
|
||||||
int address = writeResource(writer, stringPool, (ResourceTypeDescriptorProvider) value);
|
int address = writeResource(writer, stringPool, (ResourceTypeDescriptorProvider) value);
|
||||||
target.setAddress(index, address);
|
target.setAddress(index, address);
|
||||||
|
} else if (value == null) {
|
||||||
|
target.setAddress(index, 0);
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException("Don't know how to write resource: " + value);
|
throw new IllegalArgumentException("Don't know how to write resource: " + value);
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ public class PlatformPlugin implements TeaVMPlugin {
|
||||||
if (wasmHost != null) {
|
if (wasmHost != null) {
|
||||||
wasmHost.add(ctx -> new MetadataIntrinsic(ctx.getClassSource(), ctx.getClassLoader(), ctx.getServices(),
|
wasmHost.add(ctx -> new MetadataIntrinsic(ctx.getClassSource(), ctx.getClassLoader(), ctx.getServices(),
|
||||||
ctx.getProperties()));
|
ctx.getProperties()));
|
||||||
wasmHost.add(ctx -> new ResourceReadIntrinsic(ctx.getClassSource()));
|
wasmHost.add(ctx -> new ResourceReadIntrinsic(ctx.getClassSource(), ctx.getClassLoader()));
|
||||||
}
|
}
|
||||||
|
|
||||||
host.add(new AsyncMethodProcessor());
|
host.add(new AsyncMethodProcessor());
|
||||||
|
|
|
@ -15,19 +15,34 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.platform.plugin;
|
package org.teavm.platform.plugin;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import org.teavm.ast.InvocationExpr;
|
import org.teavm.ast.InvocationExpr;
|
||||||
import org.teavm.backend.wasm.intrinsics.WasmIntrinsic;
|
import org.teavm.backend.wasm.intrinsics.WasmIntrinsic;
|
||||||
import org.teavm.backend.wasm.intrinsics.WasmIntrinsicManager;
|
import org.teavm.backend.wasm.intrinsics.WasmIntrinsicManager;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmInt32Subtype;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmInt64Subtype;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmLoadFloat32;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmLoadFloat64;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmLoadInt32;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmLoadInt64;
|
||||||
import org.teavm.model.ClassReaderSource;
|
import org.teavm.model.ClassReaderSource;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
|
import org.teavm.model.ValueType;
|
||||||
import org.teavm.platform.metadata.Resource;
|
import org.teavm.platform.metadata.Resource;
|
||||||
|
|
||||||
public class ResourceReadIntrinsic implements WasmIntrinsic {
|
public class ResourceReadIntrinsic implements WasmIntrinsic {
|
||||||
private ClassReaderSource classSource;
|
private ClassReaderSource classSource;
|
||||||
|
private ClassLoader classLoader;
|
||||||
|
private Map<String, StructureDescriptor> typeDescriptorCache = new HashMap<>();
|
||||||
|
|
||||||
public ResourceReadIntrinsic(ClassReaderSource classSource) {
|
public ResourceReadIntrinsic(ClassReaderSource classSource, ClassLoader classLoader) {
|
||||||
this.classSource = classSource;
|
this.classSource = classSource;
|
||||||
|
this.classLoader = classLoader;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -37,6 +52,112 @@ public class ResourceReadIntrinsic implements WasmIntrinsic {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WasmExpression apply(InvocationExpr invocation, WasmIntrinsicManager manager) {
|
public WasmExpression apply(InvocationExpr invocation, WasmIntrinsicManager manager) {
|
||||||
return null;
|
StructureDescriptor typeDescriptor = getTypeDescriptor(invocation.getMethod().getClassName());
|
||||||
|
PropertyDescriptor property = typeDescriptor.layout.get(invocation.getMethod());
|
||||||
|
|
||||||
|
WasmExpression base = manager.generate(invocation.getArguments().get(0));
|
||||||
|
|
||||||
|
if (property.type instanceof ValueType.Primitive) {
|
||||||
|
switch (((ValueType.Primitive) property.type).getKind()) {
|
||||||
|
case BOOLEAN:
|
||||||
|
case BYTE:
|
||||||
|
return new WasmLoadInt32(1, base, WasmInt32Subtype.INT8, property.offset);
|
||||||
|
case SHORT:
|
||||||
|
return new WasmLoadInt32(2, base, WasmInt32Subtype.INT16, property.offset);
|
||||||
|
case CHARACTER:
|
||||||
|
return new WasmLoadInt32(2, base, WasmInt32Subtype.UINT16, property.offset);
|
||||||
|
case INTEGER:
|
||||||
|
return new WasmLoadInt32(4, base, WasmInt32Subtype.INT32, property.offset);
|
||||||
|
case LONG:
|
||||||
|
return new WasmLoadInt64(8, base, WasmInt64Subtype.INT64, property.offset);
|
||||||
|
case FLOAT:
|
||||||
|
return new WasmLoadFloat32(4, base, property.offset);
|
||||||
|
case DOUBLE:
|
||||||
|
return new WasmLoadFloat64(8, base, property.offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new WasmLoadInt32(4, base, WasmInt32Subtype.INT32, property.offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
private StructureDescriptor getTypeDescriptor(String className) {
|
||||||
|
return typeDescriptorCache.computeIfAbsent(className, n -> {
|
||||||
|
Class<?> cls;
|
||||||
|
try {
|
||||||
|
cls = Class.forName(className, false, classLoader);
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
throw new AssertionError("Class " + className + " should exist", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
StructureDescriptor structureDescriptor = new StructureDescriptor();
|
||||||
|
structureDescriptor.typeDescriptor = new ResourceTypeDescriptor(cls);
|
||||||
|
calculateLayout(structureDescriptor.typeDescriptor, structureDescriptor.layout);
|
||||||
|
return structureDescriptor;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void calculateLayout(ResourceTypeDescriptor typeDescriptor,
|
||||||
|
Map<MethodReference, PropertyDescriptor> layout) {
|
||||||
|
Map<String, Integer> propertyIndexes = new HashMap<>();
|
||||||
|
List<String> propertyNames = new ArrayList<>(typeDescriptor.getPropertyTypes().keySet());
|
||||||
|
for (int i = 0; i < propertyNames.size(); ++i) {
|
||||||
|
propertyIndexes.put(propertyNames.get(i), i);
|
||||||
|
}
|
||||||
|
|
||||||
|
Method[] methods = new Method[typeDescriptor.getPropertyTypes().size()];
|
||||||
|
for (Method method : typeDescriptor.getMethods().keySet()) {
|
||||||
|
ResourceMethodDescriptor methodDescriptor = typeDescriptor.getMethods().get(method);
|
||||||
|
if (methodDescriptor.getType() == ResourceAccessorType.SETTER) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String propertyName = methodDescriptor.getPropertyName();
|
||||||
|
int index = propertyIndexes.get(propertyName);
|
||||||
|
methods[index] = method;
|
||||||
|
}
|
||||||
|
|
||||||
|
int currentOffset = 0;
|
||||||
|
for (Method method : methods) {
|
||||||
|
MethodReference methodRef = MethodReference.parse(method);
|
||||||
|
ValueType propertyType = methodRef.getReturnType();
|
||||||
|
int size = getPropertySize(propertyType);
|
||||||
|
currentOffset = ((currentOffset + size - 1) / size + 1) * size;
|
||||||
|
|
||||||
|
PropertyDescriptor propertyDescriptor = new PropertyDescriptor();
|
||||||
|
propertyDescriptor.offset = currentOffset;
|
||||||
|
propertyDescriptor.type = propertyType;
|
||||||
|
layout.put(methodRef, propertyDescriptor);
|
||||||
|
|
||||||
|
currentOffset += size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getPropertySize(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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static class StructureDescriptor {
|
||||||
|
ResourceTypeDescriptor typeDescriptor;
|
||||||
|
Map<MethodReference, PropertyDescriptor> layout = new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
static class PropertyDescriptor {
|
||||||
|
int offset;
|
||||||
|
ValueType type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user