mirror of
https://github.com/konsoletyper/teavm.git
synced 2024-11-27 01:30:35 +08:00
Wasm backend: implement remaining types of resources
This commit is contained in:
parent
5ce48ce866
commit
097820cc2b
@ -21,6 +21,7 @@ import java.util.List;
|
||||
import java.util.ServiceLoader;
|
||||
import org.teavm.backend.c.TeaVMCHost;
|
||||
import org.teavm.backend.javascript.TeaVMJavaScriptHost;
|
||||
import org.teavm.backend.wasm.TeaVMWasmHost;
|
||||
import org.teavm.classlib.ReflectionSupplier;
|
||||
import org.teavm.classlib.impl.lambda.LambdaMetafactorySubstitutor;
|
||||
import org.teavm.classlib.impl.tz.DateTimeZoneProviderIntrinsic;
|
||||
@ -92,6 +93,11 @@ public class JCLPlugin implements TeaVMPlugin {
|
||||
if (cHost != null) {
|
||||
cHost.addIntrinsic(context -> new DateTimeZoneProviderIntrinsic(context.getProperties()));
|
||||
}
|
||||
|
||||
TeaVMWasmHost wasmHost = host.getExtension(TeaVMWasmHost.class);
|
||||
if (wasmHost != null) {
|
||||
wasmHost.add(context -> new DateTimeZoneProviderIntrinsic(context.getProperties()));
|
||||
}
|
||||
}
|
||||
|
||||
TeaVMPluginUtil.handleNatives(host, Class.class);
|
||||
|
@ -26,6 +26,7 @@ import java.util.Set;
|
||||
import org.teavm.backend.javascript.spi.GeneratedBy;
|
||||
import org.teavm.classlib.impl.Base46;
|
||||
import org.teavm.classlib.impl.CharFlow;
|
||||
import org.teavm.interop.Import;
|
||||
import org.teavm.jso.JSBody;
|
||||
import org.teavm.platform.metadata.MetadataProvider;
|
||||
import org.teavm.platform.metadata.ResourceMap;
|
||||
@ -189,6 +190,7 @@ public final class DateTimeZoneProvider {
|
||||
}
|
||||
|
||||
@JSBody(params = "instant", script = "return new Date(instant).getTimezoneOffset();")
|
||||
@Import(module = "teavm", name = "getNativeOffset")
|
||||
private static native int getNativeOffset(double instant);
|
||||
|
||||
@MetadataProvider(TimeZoneGenerator.class)
|
||||
|
@ -19,9 +19,13 @@ import java.util.Properties;
|
||||
import org.teavm.ast.InvocationExpr;
|
||||
import org.teavm.backend.c.intrinsic.Intrinsic;
|
||||
import org.teavm.backend.c.intrinsic.IntrinsicContext;
|
||||
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.WasmInt32Constant;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
public class DateTimeZoneProviderIntrinsic implements Intrinsic {
|
||||
public class DateTimeZoneProviderIntrinsic implements Intrinsic, WasmIntrinsic {
|
||||
private Properties properties;
|
||||
|
||||
public DateTimeZoneProviderIntrinsic(Properties properties) {
|
||||
@ -43,6 +47,20 @@ public class DateTimeZoneProviderIntrinsic implements Intrinsic {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isApplicable(MethodReference methodReference) {
|
||||
if (!methodReference.getClassName().equals(DateTimeZoneProvider.class.getName())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (methodReference.getName()) {
|
||||
case "timeZoneDetectionEnabled":
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(IntrinsicContext context, InvocationExpr invocation) {
|
||||
switch (invocation.getMethod().getName()) {
|
||||
@ -56,4 +74,16 @@ public class DateTimeZoneProviderIntrinsic implements Intrinsic {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public WasmExpression apply(InvocationExpr invocation, WasmIntrinsicManager manager) {
|
||||
switch (invocation.getMethod().getName()) {
|
||||
case "timeZoneDetectionEnabled": {
|
||||
boolean enabled = properties.getProperty("java.util.TimeZone.autodetect", "false").equals("true");
|
||||
return new WasmInt32Constant(enabled ? 1 : 0);
|
||||
}
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ import org.teavm.interop.Address;
|
||||
import org.teavm.interop.Import;
|
||||
import org.teavm.interop.StaticInit;
|
||||
import org.teavm.interop.Unmanaged;
|
||||
import org.teavm.runtime.RuntimeObject;
|
||||
|
||||
@StaticInit
|
||||
@Unmanaged
|
||||
@ -282,4 +283,97 @@ public final class WasmRuntime {
|
||||
public static void setExceptionHandlerId(Address stackFrame, int id) {
|
||||
getExceptionHandlerPtr(stackFrame).putInt(id);
|
||||
}
|
||||
|
||||
private static int hashCode(RuntimeString string) {
|
||||
int hashCode = 0;
|
||||
int length = string.characters.length;
|
||||
Address chars = Address.ofData(string.characters);
|
||||
for (int i = 0; i < length; ++i) {
|
||||
hashCode = 31 * hashCode + chars.getChar();
|
||||
chars = chars.add(2);
|
||||
}
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
private static boolean equals(RuntimeString first, RuntimeString second) {
|
||||
if (first.characters.length != second.characters.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Address firstChars = Address.ofData(first.characters);
|
||||
Address secondChars = Address.ofData(second.characters);
|
||||
int length = first.characters.length;
|
||||
for (int i = 0; i < length; ++i) {
|
||||
if (firstChars.getChar() != secondChars.getChar()) {
|
||||
return false;
|
||||
}
|
||||
firstChars = firstChars.add(2);
|
||||
secondChars = secondChars.add(2);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static String[] resourceMapKeys(Address map) {
|
||||
String[] result = new String[resourceMapSize(map)];
|
||||
fillResourceMapKeys(map, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int resourceMapSize(Address map) {
|
||||
int result = 0;
|
||||
int sz = map.getInt();
|
||||
Address data = contentStart(map);
|
||||
for (int i = 0; i < sz; ++i) {
|
||||
if (data.getAddress() != null) {
|
||||
result++;
|
||||
}
|
||||
data = data.add(Address.sizeOf() * 2);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void fillResourceMapKeys(Address map, String[] target) {
|
||||
int sz = map.getInt();
|
||||
Address data = contentStart(map);
|
||||
Address targetData = Address.ofData(target);
|
||||
for (int i = 0; i < sz; ++i) {
|
||||
Address entry = data.getAddress();
|
||||
if (entry != null) {
|
||||
targetData.putAddress(entry);
|
||||
targetData = targetData.add(Address.sizeOf());
|
||||
}
|
||||
data = data.add(Address.sizeOf());
|
||||
}
|
||||
}
|
||||
|
||||
private static Address contentStart(Address resource) {
|
||||
return resource.add(Address.sizeOf());
|
||||
}
|
||||
|
||||
public static Address lookupResource(Address map, String string) {
|
||||
RuntimeString runtimeString = Address.ofObject(string).toStructure();
|
||||
int hashCode = hashCode(runtimeString);
|
||||
int sz = map.getInt();
|
||||
Address content = contentStart(map);
|
||||
for (int i = 0; i < sz; ++i) {
|
||||
int index = (hashCode + i) % sz;
|
||||
if (index < 0) {
|
||||
index += sz;
|
||||
}
|
||||
Address entry = content.add(index * Address.sizeOf() * 2);
|
||||
Address key = entry.getAddress();
|
||||
if (key == null) {
|
||||
return null;
|
||||
}
|
||||
if (equals(key.toStructure(), runtimeString)) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static class RuntimeString extends RuntimeObject {
|
||||
char[] characters;
|
||||
}
|
||||
}
|
||||
|
@ -266,6 +266,10 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
||||
int.class, void.class), null).use();
|
||||
dependencyAnalyzer.linkMethod(new MethodReference(WasmRuntime.class, "getCallSiteId", Address.class,
|
||||
int.class), null).use();
|
||||
dependencyAnalyzer.linkMethod(new MethodReference(WasmRuntime.class, "resourceMapKeys", Address.class,
|
||||
String[].class), null).use();
|
||||
dependencyAnalyzer.linkMethod(new MethodReference(WasmRuntime.class, "lookupResource", Address.class,
|
||||
String.class, Address.class), null).use();
|
||||
|
||||
dependencyAnalyzer.linkMethod(new MethodReference(Allocator.class, "allocate",
|
||||
RuntimeClass.class, Address.class), null).use();
|
||||
@ -466,7 +470,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
||||
renderer.setLineNumbersEmitted(debugging);
|
||||
renderer.render(module);
|
||||
try (OutputStream output = buildTarget.createResource(outputName);
|
||||
Writer writer = new OutputStreamWriter(output, "UTF-8")) {
|
||||
Writer writer = new OutputStreamWriter(output, StandardCharsets.UTF_8)) {
|
||||
writer.write(renderer.toString());
|
||||
}
|
||||
}
|
||||
@ -477,7 +481,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
||||
renderer.setMemoryAccessChecked(Boolean.parseBoolean(System.getProperty("wasm.c.assertMemory", "false")));
|
||||
renderer.render(module);
|
||||
try (OutputStream output = buildTarget.createResource(outputName);
|
||||
Writer writer = new OutputStreamWriter(output, "UTF-8")) {
|
||||
Writer writer = new OutputStreamWriter(output, StandardCharsets.UTF_8)) {
|
||||
writer.write(renderer.toString());
|
||||
}
|
||||
}
|
||||
|
@ -41,6 +41,7 @@ import org.teavm.backend.wasm.model.expression.WasmStoreInt64;
|
||||
import org.teavm.interop.Address;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.runtime.RuntimeArray;
|
||||
|
||||
public class AddressIntrinsic implements WasmIntrinsic {
|
||||
private WasmClassGenerator classGenerator;
|
||||
@ -159,13 +160,40 @@ public class AddressIntrinsic implements WasmIntrinsic {
|
||||
.collect(Collectors.toList()));
|
||||
return call;
|
||||
}
|
||||
case "isLessThan": {
|
||||
case "isLessThan":
|
||||
return new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.LT_UNSIGNED,
|
||||
manager.generate(invocation.getArguments().get(0)),
|
||||
manager.generate(invocation.getArguments().get(1)));
|
||||
case "ofData": {
|
||||
ValueType.Array type = (ValueType.Array) invocation.getMethod().parameterType(0);
|
||||
int alignment = getAlignment(type.getItemType());
|
||||
int start = WasmClassGenerator.align(classGenerator.getClassSize(RuntimeArray.class.getName()),
|
||||
alignment);
|
||||
return new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD,
|
||||
manager.generate(invocation.getArguments().get(0)), new WasmInt32Constant(start));
|
||||
}
|
||||
default:
|
||||
throw new IllegalArgumentException(invocation.getMethod().toString());
|
||||
}
|
||||
}
|
||||
|
||||
private static int getAlignment(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;
|
||||
}
|
||||
}
|
||||
|
@ -34,6 +34,9 @@ TeaVM.wasm = function() {
|
||||
function currentTimeMillis() {
|
||||
return new Date().getTime();
|
||||
}
|
||||
function getNativeOffset(instant) {
|
||||
return new Date(instant).getTimezoneOffset();
|
||||
}
|
||||
|
||||
function importDefaults(obj) {
|
||||
obj.teavm = {
|
||||
@ -44,7 +47,8 @@ TeaVM.wasm = function() {
|
||||
isfinite: isFinite,
|
||||
putwchar: putwchar,
|
||||
towlower: towlower,
|
||||
towupper: towupper
|
||||
towupper: towupper,
|
||||
getNativeOffset: getNativeOffset
|
||||
};
|
||||
|
||||
obj.teavmMath = Math;
|
||||
|
@ -82,6 +82,8 @@ public final class Address {
|
||||
|
||||
public static native Address ofData(double[] data);
|
||||
|
||||
public static native Address ofData(Object[] data);
|
||||
|
||||
public static native Address align(Address address, int alignment);
|
||||
|
||||
public static native int sizeOf();
|
||||
|
@ -53,13 +53,17 @@ class BuildTimeResourceProxyBuilder {
|
||||
|
||||
public ProxyFactoryCreation(ResourceTypeDescriptor descriptor) {
|
||||
this.descriptor = descriptor;
|
||||
int index = 0;
|
||||
for (String propertyName : descriptor.getPropertyTypes().keySet()) {
|
||||
propertyIndexes.put(propertyName, index++);
|
||||
}
|
||||
}
|
||||
|
||||
BuildTimeResourceProxyFactory create() {
|
||||
for (Map.Entry<Method, ResourceMethodDescriptor> entry : descriptor.getMethods().entrySet()) {
|
||||
Method method = entry.getKey();
|
||||
ResourceMethodDescriptor methodDescriptor = entry.getValue();
|
||||
int index = getPropertyIndex(methodDescriptor.getPropertyName());
|
||||
int index = propertyIndexes.get(methodDescriptor.getPropertyName());
|
||||
switch (methodDescriptor.getType()) {
|
||||
case GETTER:
|
||||
methods.put(method, new BuildTimeResourceGetter(index));
|
||||
@ -109,9 +113,5 @@ class BuildTimeResourceProxyBuilder {
|
||||
|
||||
return new BuildTimeResourceProxyFactory(methods, initialData, descriptor);
|
||||
}
|
||||
|
||||
private int getPropertyIndex(String propertyName) {
|
||||
return propertyIndexes.computeIfAbsent(propertyName, k -> propertyIndexes.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -166,13 +166,13 @@ public class MetadataCIntrinsic implements Intrinsic {
|
||||
|
||||
for (String propertyName : structure.getPropertyTypes().keySet()) {
|
||||
Class<?> propertyType = structure.getPropertyTypes().get(propertyName);
|
||||
structuresWriter.println(typeToString(context, propertyType) + " " + propertyName + ";");
|
||||
structuresWriter.println(typeToString(propertyType) + " " + propertyName + ";");
|
||||
}
|
||||
|
||||
structuresWriter.outdent().println("} " + structureName + ";");
|
||||
}
|
||||
|
||||
private String typeToString(IntrinsicContext context, Class<?> cls) {
|
||||
private String typeToString(Class<?> cls) {
|
||||
if (cls == boolean.class || cls == byte.class) {
|
||||
return "int8_t";
|
||||
} else if (cls == short.class || cls == char.class) {
|
||||
|
@ -39,6 +39,8 @@ import org.teavm.model.MethodReference;
|
||||
import org.teavm.platform.metadata.MetadataGenerator;
|
||||
import org.teavm.platform.metadata.MetadataProvider;
|
||||
import org.teavm.platform.metadata.Resource;
|
||||
import org.teavm.platform.metadata.ResourceArray;
|
||||
import org.teavm.platform.metadata.ResourceMap;
|
||||
|
||||
public class MetadataIntrinsic implements WasmIntrinsic {
|
||||
private ClassReaderSource classSource;
|
||||
@ -85,6 +87,22 @@ public class MetadataIntrinsic implements WasmIntrinsic {
|
||||
private int writeValue(BinaryWriter writer, WasmStringPool stringPool, Object value) {
|
||||
if (value instanceof String) {
|
||||
return stringPool.getStringPointer((String) value);
|
||||
} else if (value instanceof Boolean) {
|
||||
DataValue dataValue = DataPrimitives.BYTE.createValue();
|
||||
dataValue.setByte(0, (Boolean) value ? (byte) 1 : 0);
|
||||
return writer.append(dataValue);
|
||||
} else if (value instanceof Integer) {
|
||||
DataValue dataValue = DataPrimitives.INT.createValue();
|
||||
dataValue.setInt(0, (Integer) value);
|
||||
return writer.append(dataValue);
|
||||
} else if (value instanceof Long) {
|
||||
DataValue dataValue = DataPrimitives.LONG.createValue();
|
||||
dataValue.setLong(0, (Long) value);
|
||||
return writer.append(dataValue);
|
||||
} else if (value instanceof ResourceMap) {
|
||||
return writeResource(writer, stringPool, (ResourceMap<?>) value);
|
||||
} else if (value instanceof ResourceArray) {
|
||||
return writeResource(writer, stringPool, (ResourceArray<?>) value);
|
||||
} else if (value instanceof ResourceTypeDescriptorProvider && value instanceof Resource) {
|
||||
return writeResource(writer, stringPool, (ResourceTypeDescriptorProvider) value);
|
||||
} else {
|
||||
@ -109,6 +127,90 @@ public class MetadataIntrinsic implements WasmIntrinsic {
|
||||
return address;
|
||||
}
|
||||
|
||||
private int writeResource(BinaryWriter writer, WasmStringPool stringPool, ResourceMap<?> resourceMap) {
|
||||
String[] keys = resourceMap.keys();
|
||||
int tableSize = keys.length * 2;
|
||||
int maxTableSize = Math.min(keys.length * 5 / 2, tableSize + 10);
|
||||
|
||||
String[] bestTable = null;
|
||||
int bestCollisionRatio = 0;
|
||||
while (tableSize <= maxTableSize) {
|
||||
String[] table = new String[tableSize];
|
||||
int maxCollisionRatio = 0;
|
||||
for (String key : keys) {
|
||||
int hashCode = key.hashCode();
|
||||
int collisionRatio = 0;
|
||||
while (true) {
|
||||
int index = mod(hashCode++, table.length);
|
||||
if (table[index] == null) {
|
||||
table[index] = key;
|
||||
break;
|
||||
}
|
||||
collisionRatio++;
|
||||
}
|
||||
maxCollisionRatio = Math.max(maxCollisionRatio, collisionRatio);
|
||||
}
|
||||
|
||||
if (bestTable == null || bestCollisionRatio > maxCollisionRatio) {
|
||||
bestCollisionRatio = maxCollisionRatio;
|
||||
bestTable = table;
|
||||
}
|
||||
|
||||
tableSize++;
|
||||
}
|
||||
|
||||
|
||||
DataValue sizeValue = DataPrimitives.ADDRESS.createValue();
|
||||
int start = writer.append(sizeValue);
|
||||
sizeValue.setAddress(0, bestTable.length);
|
||||
|
||||
DataValue[] keyValues = new DataValue[bestTable.length];
|
||||
DataValue[] valueValues = new DataValue[bestTable.length];
|
||||
for (int i = 0; i < bestTable.length; ++i) {
|
||||
DataValue keyValue = DataPrimitives.ADDRESS.createValue();
|
||||
DataValue valueValue = DataPrimitives.ADDRESS.createValue();
|
||||
writer.append(keyValue);
|
||||
writer.append(valueValue);
|
||||
keyValues[i] = keyValue;
|
||||
valueValues[i] = valueValue;
|
||||
}
|
||||
for (int i = 0; i < bestTable.length; ++i) {
|
||||
String key = bestTable[i];
|
||||
if (key != null) {
|
||||
keyValues[i].setAddress(0, stringPool.getStringPointer(key));
|
||||
valueValues[i].setAddress(0, writeValue(writer, stringPool, resourceMap.get(key)));
|
||||
}
|
||||
}
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
private int writeResource(BinaryWriter writer, WasmStringPool stringPool, ResourceArray<?> resourceArray) {
|
||||
DataValue sizeValue = DataPrimitives.ADDRESS.createValue();
|
||||
int start = writer.append(sizeValue);
|
||||
sizeValue.setAddress(0, resourceArray.size());
|
||||
|
||||
DataValue[] arrayValues = new DataValue[resourceArray.size()];
|
||||
for (int i = 0; i < resourceArray.size(); ++i) {
|
||||
arrayValues[i] = DataPrimitives.ADDRESS.createValue();
|
||||
writer.append(arrayValues[i]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < resourceArray.size(); ++i) {
|
||||
arrayValues[i].setAddress(0, writeValue(writer, stringPool, resourceArray.get(i)));
|
||||
}
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
private static int mod(int a, int b) {
|
||||
a %= b;
|
||||
if (a < 0) {
|
||||
a += b;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
private void writeValueTo(BinaryWriter writer, WasmStringPool stringPool, Class<?> type, DataValue target,
|
||||
int index, Object value) {
|
||||
if (type == String.class) {
|
||||
@ -134,6 +236,10 @@ public class MetadataIntrinsic implements WasmIntrinsic {
|
||||
target.setAddress(index, address);
|
||||
} else if (value == null) {
|
||||
target.setAddress(index, 0);
|
||||
} else if (value instanceof ResourceMap) {
|
||||
target.setAddress(index, writeResource(writer, stringPool, (ResourceMap<?>) value));
|
||||
} else if (value instanceof ResourceArray) {
|
||||
target.setAddress(index, writeResource(writer, stringPool, (ResourceArray<?>) value));
|
||||
} else {
|
||||
throw new IllegalArgumentException("Don't know how to write resource: " + value);
|
||||
}
|
||||
|
@ -21,23 +21,44 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.teavm.ast.InvocationExpr;
|
||||
import org.teavm.backend.wasm.WasmRuntime;
|
||||
import org.teavm.backend.wasm.binary.BinaryWriter;
|
||||
import org.teavm.backend.wasm.generate.WasmClassGenerator;
|
||||
import org.teavm.backend.wasm.intrinsics.WasmIntrinsic;
|
||||
import org.teavm.backend.wasm.intrinsics.WasmIntrinsicManager;
|
||||
import org.teavm.backend.wasm.model.WasmLocal;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
import org.teavm.backend.wasm.model.expression.WasmBlock;
|
||||
import org.teavm.backend.wasm.model.expression.WasmBranch;
|
||||
import org.teavm.backend.wasm.model.expression.WasmCall;
|
||||
import org.teavm.backend.wasm.model.expression.WasmDrop;
|
||||
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||
import org.teavm.backend.wasm.model.expression.WasmGetLocal;
|
||||
import org.teavm.backend.wasm.model.expression.WasmInt32Constant;
|
||||
import org.teavm.backend.wasm.model.expression.WasmInt32Subtype;
|
||||
import org.teavm.backend.wasm.model.expression.WasmInt64Subtype;
|
||||
import org.teavm.backend.wasm.model.expression.WasmIntBinary;
|
||||
import org.teavm.backend.wasm.model.expression.WasmIntBinaryOperation;
|
||||
import org.teavm.backend.wasm.model.expression.WasmIntType;
|
||||
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.backend.wasm.model.expression.WasmSetLocal;
|
||||
import org.teavm.interop.Address;
|
||||
import org.teavm.model.ClassReaderSource;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.platform.metadata.Resource;
|
||||
import org.teavm.platform.metadata.ResourceArray;
|
||||
import org.teavm.platform.metadata.ResourceMap;
|
||||
|
||||
public class ResourceReadIntrinsic implements WasmIntrinsic {
|
||||
private static final MethodReference LOOKUP_METHOD = new MethodReference(WasmRuntime.class,
|
||||
"lookupResource", Address.class, String.class, Address.class);
|
||||
private static final MethodReference KEYS_METHOD = new MethodReference(WasmRuntime.class,
|
||||
"resourceMapKeys", Address.class, String[].class);
|
||||
|
||||
private ClassReaderSource classSource;
|
||||
private ClassLoader classLoader;
|
||||
private Map<String, StructureDescriptor> typeDescriptorCache = new HashMap<>();
|
||||
@ -54,6 +75,12 @@ public class ResourceReadIntrinsic implements WasmIntrinsic {
|
||||
|
||||
@Override
|
||||
public WasmExpression apply(InvocationExpr invocation, WasmIntrinsicManager manager) {
|
||||
if (invocation.getMethod().getClassName().equals(ResourceMap.class.getName())) {
|
||||
return applyForResourceMap(manager, invocation);
|
||||
} else if (invocation.getMethod().getClassName().equals(ResourceArray.class.getName())) {
|
||||
return applyForResourceArray(manager, invocation);
|
||||
}
|
||||
|
||||
StructureDescriptor typeDescriptor = getTypeDescriptor(invocation.getMethod().getClassName());
|
||||
PropertyDescriptor property = typeDescriptor.layout.get(invocation.getMethod());
|
||||
|
||||
@ -82,6 +109,67 @@ public class ResourceReadIntrinsic implements WasmIntrinsic {
|
||||
return new WasmLoadInt32(4, base, WasmInt32Subtype.INT32, property.offset);
|
||||
}
|
||||
|
||||
private WasmExpression applyForResourceArray(WasmIntrinsicManager manager, InvocationExpr invocation) {
|
||||
switch (invocation.getMethod().getName()) {
|
||||
case "get": {
|
||||
WasmExpression map = manager.generate(invocation.getArguments().get(0));
|
||||
WasmExpression index = manager.generate(invocation.getArguments().get(1));
|
||||
WasmExpression offset = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.SHL,
|
||||
index, new WasmInt32Constant(2));
|
||||
WasmExpression address = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD,
|
||||
map, offset);
|
||||
return new WasmLoadInt32(4, address, WasmInt32Subtype.INT32, 4);
|
||||
}
|
||||
case "size":
|
||||
return new WasmLoadInt32(4, manager.generate(invocation.getArguments().get(0)),
|
||||
WasmInt32Subtype.INT32, 0);
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
private WasmExpression applyForResourceMap(WasmIntrinsicManager manager, InvocationExpr invocation) {
|
||||
switch (invocation.getMethod().getName()) {
|
||||
case "keys": {
|
||||
WasmExpression map = manager.generate(invocation.getArguments().get(0));
|
||||
WasmCall call = new WasmCall(manager.getNames().forMethod(KEYS_METHOD));
|
||||
call.getArguments().add(map);
|
||||
return call;
|
||||
}
|
||||
case "has": {
|
||||
WasmExpression map = manager.generate(invocation.getArguments().get(0));
|
||||
WasmExpression key = manager.generate(invocation.getArguments().get(1));
|
||||
WasmCall call = new WasmCall(manager.getNames().forMethod(LOOKUP_METHOD));
|
||||
call.getArguments().add(map);
|
||||
call.getArguments().add(key);
|
||||
return new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.NE, call,
|
||||
new WasmInt32Constant(0));
|
||||
}
|
||||
case "get": {
|
||||
WasmBlock block = new WasmBlock(false);
|
||||
block.setType(WasmType.INT32);
|
||||
|
||||
WasmExpression map = manager.generate(invocation.getArguments().get(0));
|
||||
WasmExpression key = manager.generate(invocation.getArguments().get(1));
|
||||
WasmCall call = new WasmCall(manager.getNames().forMethod(LOOKUP_METHOD));
|
||||
call.getArguments().add(map);
|
||||
call.getArguments().add(key);
|
||||
WasmLocal entryVar = manager.getTemporary(WasmType.INT32);
|
||||
block.getBody().add(new WasmSetLocal(entryVar, call));
|
||||
|
||||
WasmBranch ifNull = new WasmBranch(new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.EQ,
|
||||
new WasmGetLocal(entryVar), new WasmInt32Constant(0)), block);
|
||||
ifNull.setResult(new WasmInt32Constant(0));
|
||||
block.getBody().add(new WasmDrop(ifNull));
|
||||
|
||||
block.getBody().add(new WasmLoadInt32(4, new WasmGetLocal(entryVar), WasmInt32Subtype.INT32, 4));
|
||||
return block;
|
||||
}
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
private StructureDescriptor getTypeDescriptor(String className) {
|
||||
return typeDescriptorCache.computeIfAbsent(className, n -> {
|
||||
Class<?> cls;
|
||||
|
Loading…
Reference in New Issue
Block a user