mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -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) {
|
||||
System.out.println(Integer.parseInt("123"));
|
||||
testFibonacci();
|
||||
testClasses();
|
||||
testVirtualCall();
|
||||
|
@ -38,7 +39,7 @@ public final class Example {
|
|||
testArrayIsObject();
|
||||
testIsAssignableFrom();
|
||||
testExceptions();
|
||||
testBigInteger();
|
||||
//testBigInteger();
|
||||
testGC();
|
||||
}
|
||||
|
||||
|
|
|
@ -23,9 +23,14 @@ public class WasmLoadFloat32 extends WasmExpression implements WasmMemoryAccess
|
|||
private int offset;
|
||||
|
||||
public WasmLoadFloat32(int alignment, WasmExpression index) {
|
||||
this(alignment, index, 0);
|
||||
}
|
||||
|
||||
public WasmLoadFloat32(int alignment, WasmExpression index, int offset) {
|
||||
Objects.requireNonNull(index);
|
||||
this.alignment = alignment;
|
||||
this.index = index;
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
public int getAlignment() {
|
||||
|
|
|
@ -23,9 +23,14 @@ public class WasmLoadFloat64 extends WasmExpression implements WasmMemoryAccess
|
|||
private int offset;
|
||||
|
||||
public WasmLoadFloat64(int alignment, WasmExpression index) {
|
||||
this(alignment, index, 0);
|
||||
}
|
||||
|
||||
public WasmLoadFloat64(int alignment, WasmExpression index, int offset) {
|
||||
Objects.requireNonNull(index);
|
||||
this.alignment = alignment;
|
||||
this.index = index;
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
public int getAlignment() {
|
||||
|
|
|
@ -24,11 +24,16 @@ public class WasmLoadInt32 extends WasmExpression implements WasmMemoryAccess {
|
|||
private int offset;
|
||||
|
||||
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(convertFrom);
|
||||
this.alignment = alignment;
|
||||
this.index = index;
|
||||
this.convertFrom = convertFrom;
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
public int getAlignment() {
|
||||
|
|
|
@ -24,11 +24,16 @@ public class WasmLoadInt64 extends WasmExpression implements WasmMemoryAccess {
|
|||
private int offset;
|
||||
|
||||
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(convertFrom);
|
||||
this.alignment = alignment;
|
||||
this.index = index;
|
||||
this.convertFrom = convertFrom;
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
public int getAlignment() {
|
||||
|
|
|
@ -18,7 +18,9 @@ package org.teavm.model;
|
|||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonValue;
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
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
|
||||
|
@ -162,6 +164,12 @@ public class MethodReference implements Serializable {
|
|||
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() {
|
||||
return getDescriptor().signatureToString();
|
||||
}
|
||||
|
|
|
@ -112,7 +112,7 @@ public class MetadataIntrinsic implements WasmIntrinsic {
|
|||
private void writeValueTo(BinaryWriter writer, WasmStringPool stringPool, Class<?> type, DataValue target,
|
||||
int index, Object value) {
|
||||
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) {
|
||||
target.setByte(index, (boolean) value ? (byte) 1 : 0);
|
||||
} else if (type == byte.class) {
|
||||
|
@ -132,6 +132,8 @@ public class MetadataIntrinsic implements WasmIntrinsic {
|
|||
} else if (value instanceof ResourceTypeDescriptorProvider && value instanceof Resource) {
|
||||
int address = writeResource(writer, stringPool, (ResourceTypeDescriptorProvider) value);
|
||||
target.setAddress(index, address);
|
||||
} else if (value == null) {
|
||||
target.setAddress(index, 0);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Don't know how to write resource: " + value);
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ public class PlatformPlugin implements TeaVMPlugin {
|
|||
if (wasmHost != null) {
|
||||
wasmHost.add(ctx -> new MetadataIntrinsic(ctx.getClassSource(), ctx.getClassLoader(), ctx.getServices(),
|
||||
ctx.getProperties()));
|
||||
wasmHost.add(ctx -> new ResourceReadIntrinsic(ctx.getClassSource()));
|
||||
wasmHost.add(ctx -> new ResourceReadIntrinsic(ctx.getClassSource(), ctx.getClassLoader()));
|
||||
}
|
||||
|
||||
host.add(new AsyncMethodProcessor());
|
||||
|
|
|
@ -15,19 +15,34 @@
|
|||
*/
|
||||
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.backend.wasm.intrinsics.WasmIntrinsic;
|
||||
import org.teavm.backend.wasm.intrinsics.WasmIntrinsicManager;
|
||||
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.MethodReference;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.platform.metadata.Resource;
|
||||
|
||||
public class ResourceReadIntrinsic implements WasmIntrinsic {
|
||||
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.classLoader = classLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -37,6 +52,112 @@ public class ResourceReadIntrinsic implements WasmIntrinsic {
|
|||
|
||||
@Override
|
||||
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