mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 00:04:10 -08:00
wasm: support ServiceLoader
This commit is contained in:
parent
70d0658b47
commit
401fcabeae
|
@ -84,6 +84,11 @@ public class JCLPlugin implements TeaVMPlugin {
|
|||
if (cHost != null) {
|
||||
cHost.addGenerator(new ServiceLoaderCSupport());
|
||||
}
|
||||
|
||||
var wasmHost = host.getExtension(TeaVMWasmHost.class);
|
||||
if (wasmHost != null) {
|
||||
wasmHost.add(new ServiceLoaderWasmSupport());
|
||||
}
|
||||
}
|
||||
|
||||
if (!isBootstrap()) {
|
||||
|
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* Copyright 2023 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.classlib.impl;
|
||||
|
||||
import java.util.ServiceLoader;
|
||||
import org.teavm.ast.InvocationExpr;
|
||||
import org.teavm.backend.wasm.WasmRuntime;
|
||||
import org.teavm.backend.wasm.binary.DataPrimitives;
|
||||
import org.teavm.backend.wasm.binary.DataStructure;
|
||||
import org.teavm.backend.wasm.intrinsics.WasmIntrinsic;
|
||||
import org.teavm.backend.wasm.intrinsics.WasmIntrinsicFactory;
|
||||
import org.teavm.backend.wasm.intrinsics.WasmIntrinsicFactoryContext;
|
||||
import org.teavm.backend.wasm.intrinsics.WasmIntrinsicManager;
|
||||
import org.teavm.backend.wasm.model.expression.WasmCall;
|
||||
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||
import org.teavm.backend.wasm.model.expression.WasmInt32Constant;
|
||||
import org.teavm.dependency.DependencyAnalyzer;
|
||||
import org.teavm.interop.Address;
|
||||
import org.teavm.interop.Structure;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.runtime.Allocator;
|
||||
import org.teavm.runtime.GC;
|
||||
import org.teavm.runtime.RuntimeArray;
|
||||
import org.teavm.runtime.RuntimeClass;
|
||||
import org.teavm.runtime.RuntimeObject;
|
||||
|
||||
public class ServiceLoaderWasmSupport implements WasmIntrinsicFactory {
|
||||
private static final DataStructure ENTRY = new DataStructure(
|
||||
(byte) 4,
|
||||
DataPrimitives.ADDRESS,
|
||||
DataPrimitives.INT
|
||||
);
|
||||
private static final MethodReference CREATE_SERVICES_METHOD = new MethodReference(
|
||||
ServiceLoaderWasmSupport.class, "createServices", Address.class, Address.class);
|
||||
|
||||
@Override
|
||||
public WasmIntrinsic create(WasmIntrinsicFactoryContext context) {
|
||||
return new ServiceLoaderIntrinsic(context.getServices().getService(ServiceLoaderInformation.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contributeDependencies(DependencyAnalyzer analyzer) {
|
||||
analyzer.linkMethod(CREATE_SERVICES_METHOD);
|
||||
}
|
||||
|
||||
private static class ServiceLoaderIntrinsic implements WasmIntrinsic {
|
||||
private ServiceLoaderInformation information;
|
||||
|
||||
ServiceLoaderIntrinsic(ServiceLoaderInformation information) {
|
||||
this.information = information;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isApplicable(MethodReference methodReference) {
|
||||
return methodReference.getClassName().equals(ServiceLoader.class.getName())
|
||||
&& methodReference.getName().equals("loadServices");
|
||||
}
|
||||
|
||||
@Override
|
||||
public WasmExpression apply(InvocationExpr invocation, WasmIntrinsicManager manager) {
|
||||
var table = createServiceData(manager);
|
||||
var tableArg = new WasmInt32Constant(table);
|
||||
var serviceClassAddress = manager.generate(invocation.getArguments().get(0));
|
||||
return new WasmCall(manager.getNames().forMethod(CREATE_SERVICES_METHOD), tableArg,
|
||||
serviceClassAddress);
|
||||
}
|
||||
|
||||
private int createServiceData(WasmIntrinsicManager manager) {
|
||||
var writer = manager.getBinaryWriter();
|
||||
return writer.writeMap(
|
||||
information.serviceTypes().toArray(new String[0]),
|
||||
cls -> manager.getClassPointer(ValueType.object(cls)),
|
||||
cls -> manager.getClassPointer(ValueType.object(cls)),
|
||||
cls -> {
|
||||
var implementations = information.serviceImplementations(cls);
|
||||
var result = writer.getAddress();
|
||||
var count = DataPrimitives.INT.createValue();
|
||||
writer.append(count);
|
||||
count.setInt(0, implementations.size());
|
||||
|
||||
for (var implementation : implementations) {
|
||||
var entry = ENTRY.createValue();
|
||||
writer.append(entry);
|
||||
|
||||
var implPointer = manager.getClassPointer(ValueType.object(implementation));
|
||||
entry.setAddress(0, implPointer);
|
||||
|
||||
var constructorName = manager.getNames().forMethod(new MethodReference(
|
||||
implementation, "<init>", ValueType.VOID
|
||||
));
|
||||
entry.setInt(1, manager.getFunctionPointer(constructorName));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static RuntimeObject createServices(Address table, RuntimeClass cls) {
|
||||
var entry = WasmRuntime.lookupResource(table, cls.toAddress());
|
||||
if (entry == null) {
|
||||
return null;
|
||||
}
|
||||
entry = entry.add(Address.sizeOf()).getAddress();
|
||||
var size = entry.getInt();
|
||||
entry = entry.add(4);
|
||||
RuntimeArray result = Allocator.allocateArray(cls, size).toStructure();
|
||||
var resultData = WasmRuntime.align(result.toAddress().add(Structure.sizeOf(RuntimeArray.class)),
|
||||
Address.sizeOf());
|
||||
for (var i = 0; i < size; ++i) {
|
||||
RuntimeObject obj = Allocator.allocate(entry.getAddress().toStructure()).toStructure();
|
||||
entry = entry.add(Address.sizeOf());
|
||||
WasmRuntime.callFunctionFromTable(entry.getInt(), obj);
|
||||
entry = entry.add(4);
|
||||
resultData.putAddress(obj.toAddress());
|
||||
resultData = resultData.add(Address.sizeOf());
|
||||
GC.writeBarrier(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -31,14 +31,13 @@ public class TDate implements TComparable<TDate> {
|
|||
private long value;
|
||||
|
||||
static {
|
||||
if (PlatformDetector.isLowLevel()) {
|
||||
if (PlatformDetector.isC()) {
|
||||
initLowLevel();
|
||||
}
|
||||
}
|
||||
|
||||
@Import(name = "teavm_date_init")
|
||||
@RuntimeInclude("date.h")
|
||||
@UnsupportedOn(Platforms.WEBASSEMBLY)
|
||||
@NoSideEffects
|
||||
@Unmanaged
|
||||
private static native void initLowLevel();
|
||||
|
|
|
@ -234,6 +234,7 @@ public final class WasmRuntime {
|
|||
return resource.add(Address.sizeOf());
|
||||
}
|
||||
|
||||
@Unmanaged
|
||||
public static Address lookupResource(Address map, String string) {
|
||||
RuntimeString runtimeString = Address.ofObject(string).toStructure();
|
||||
int hashCode = hashCode(runtimeString);
|
||||
|
@ -256,6 +257,30 @@ public final class WasmRuntime {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Unmanaged
|
||||
public static Address lookupResource(Address map, Address key) {
|
||||
int sz = map.getInt();
|
||||
Address content = contentStart(map);
|
||||
var hash = key.toInt();
|
||||
for (int i = 0; i < sz; ++i) {
|
||||
int index = (hash + i) % sz;
|
||||
if (index < 0) {
|
||||
index += sz;
|
||||
}
|
||||
var entry = content.add(index * Address.sizeOf() * 2);
|
||||
var entryKey = entry.getAddress();
|
||||
if (entryKey == null) {
|
||||
return null;
|
||||
}
|
||||
if (key == entryKey) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static native void callFunctionFromTable(int index, RuntimeObject instance);
|
||||
|
||||
static class RuntimeString extends RuntimeObject {
|
||||
char[] characters;
|
||||
}
|
||||
|
|
|
@ -348,6 +348,8 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
|||
String[].class)).use();
|
||||
dependencyAnalyzer.linkMethod(new MethodReference(WasmRuntime.class, "lookupResource", Address.class,
|
||||
String.class, Address.class)).use();
|
||||
dependencyAnalyzer.linkMethod(new MethodReference(WasmRuntime.class, "lookupResource", Address.class,
|
||||
int.class, Address.class)).use();
|
||||
dependencyAnalyzer.linkMethod(new MethodReference(WasmRuntime.class, "printString",
|
||||
String.class, void.class)).use();
|
||||
dependencyAnalyzer.linkMethod(new MethodReference(WasmRuntime.class, "printInt",
|
||||
|
@ -408,6 +410,10 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
|||
}
|
||||
|
||||
dependencyAnalyzer.addDependencyListener(new StringsDependencyListener());
|
||||
|
||||
for (var intrinsic : additionalIntrinsics) {
|
||||
intrinsic.contributeDependencies(dependencyAnalyzer);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -18,6 +18,8 @@ package org.teavm.backend.wasm.binary;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.function.ToIntFunction;
|
||||
import java.util.function.ToLongFunction;
|
||||
|
||||
public class BinaryWriter {
|
||||
private int address;
|
||||
|
@ -173,4 +175,70 @@ public class BinaryWriter {
|
|||
result[offset++] = (byte) (v >> 56);
|
||||
return offset;
|
||||
}
|
||||
|
||||
public <T> int writeMap(T[] keys, ToIntFunction<T> hashCodeF, ToLongFunction<T> keyWriter,
|
||||
ToLongFunction<T> valueWriter) {
|
||||
int tableSize = keys.length * 2;
|
||||
int maxTableSize = Math.min(keys.length * 5 / 2, tableSize + 10);
|
||||
|
||||
Object[] bestTable = null;
|
||||
int bestCollisionRatio = 0;
|
||||
while (tableSize <= maxTableSize) {
|
||||
var table = new Object[tableSize];
|
||||
int maxCollisionRatio = 0;
|
||||
for (var key : keys) {
|
||||
int hashCode = hashCodeF.applyAsInt(key);
|
||||
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++;
|
||||
}
|
||||
|
||||
var sizeValue = DataPrimitives.ADDRESS.createValue();
|
||||
int start = append(sizeValue);
|
||||
sizeValue.setAddress(0, bestTable.length);
|
||||
|
||||
var keyValues = new DataValue[bestTable.length];
|
||||
var valueValues = new DataValue[bestTable.length];
|
||||
for (int i = 0; i < bestTable.length; ++i) {
|
||||
var keyValue = DataPrimitives.ADDRESS.createValue();
|
||||
var valueValue = DataPrimitives.ADDRESS.createValue();
|
||||
append(keyValue);
|
||||
append(valueValue);
|
||||
keyValues[i] = keyValue;
|
||||
valueValues[i] = valueValue;
|
||||
}
|
||||
for (int i = 0; i < bestTable.length; ++i) {
|
||||
@SuppressWarnings("unchecked")
|
||||
var key = (T) bestTable[i];
|
||||
if (key != null) {
|
||||
keyValues[i].setAddress(0, keyWriter.applyAsLong(key));
|
||||
valueValues[i].setAddress(0, valueWriter.applyAsLong(key));
|
||||
}
|
||||
}
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
private static int mod(int a, int b) {
|
||||
a %= b;
|
||||
if (a < 0) {
|
||||
a += b;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,6 +65,7 @@ public class WasmClassGenerator {
|
|||
private BinaryWriter binaryWriter;
|
||||
private Map<MethodReference, Integer> functions = new HashMap<>();
|
||||
private List<String> functionTable = new ArrayList<>();
|
||||
private ObjectIntMap<String> functionIdMap = new ObjectIntHashMap<>();
|
||||
private VirtualTableProvider vtableProvider;
|
||||
private TagRegistry tagRegistry;
|
||||
private WasmStringPool stringPool;
|
||||
|
@ -222,9 +223,8 @@ public class WasmClassGenerator {
|
|||
binaryData.data = wrapper.getValue(0);
|
||||
binaryData.data.setInt(CLASS_SIZE, 4);
|
||||
binaryData.data.setAddress(CLASS_ITEM_TYPE, itemBinaryData.start);
|
||||
binaryData.data.setInt(CLASS_IS_INSTANCE, functionTable.size());
|
||||
binaryData.data.setInt(CLASS_IS_INSTANCE, getFunctionPointer(names.forSupertypeFunction(type)));
|
||||
binaryData.data.setInt(CLASS_CANARY, RuntimeClass.computeCanary(4, 0));
|
||||
functionTable.add(names.forSupertypeFunction(type));
|
||||
binaryData.data.setAddress(CLASS_NAME, stringPool.getStringPointer(type.toString().replace('/', '.')));
|
||||
binaryData.data.setAddress(CLASS_SIMPLE_NAME, 0);
|
||||
binaryData.data.setInt(CLASS_INIT, -1);
|
||||
|
@ -238,10 +238,9 @@ public class WasmClassGenerator {
|
|||
private DataValue createPrimitiveClassData(DataValue value, int size, ValueType type) {
|
||||
value.setInt(CLASS_SIZE, size);
|
||||
value.setInt(CLASS_FLAGS, RuntimeClass.PRIMITIVE);
|
||||
value.setInt(CLASS_IS_INSTANCE, functionTable.size());
|
||||
value.setInt(CLASS_IS_INSTANCE, getFunctionPointer(names.forSupertypeFunction(type)));
|
||||
value.setAddress(CLASS_SIMPLE_NAME, 0);
|
||||
value.setInt(CLASS_INIT, -1);
|
||||
functionTable.add(names.forSupertypeFunction(type));
|
||||
|
||||
String name;
|
||||
if (type == ValueType.VOID) {
|
||||
|
@ -282,10 +281,20 @@ public class WasmClassGenerator {
|
|||
return value;
|
||||
}
|
||||
|
||||
public List<String> getFunctionTable() {
|
||||
public Iterable<? extends String> getFunctionTable() {
|
||||
return functionTable;
|
||||
}
|
||||
|
||||
public int getFunctionPointer(String name) {
|
||||
var result = functionIdMap.getOrDefault(name, -1);
|
||||
if (result < 0) {
|
||||
result = functionTable.size();
|
||||
functionTable.add(name);
|
||||
functionIdMap.put(name, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private DataValue createStructure(ClassBinaryData binaryData) {
|
||||
String parent = binaryData.cls.getParent();
|
||||
int parentPtr = !binaryData.isInferface && parent != null
|
||||
|
@ -316,8 +325,7 @@ public class WasmClassGenerator {
|
|||
header.setInt(CLASS_CANARY, RuntimeClass.computeCanary(occupiedSize, tag));
|
||||
int nameAddress = requirements.name() ? stringPool.getStringPointer(name) : 0;
|
||||
header.setAddress(CLASS_NAME, nameAddress);
|
||||
header.setInt(CLASS_IS_INSTANCE, functionTable.size());
|
||||
functionTable.add(names.forSupertypeFunction(ValueType.object(name)));
|
||||
header.setInt(CLASS_IS_INSTANCE, getFunctionPointer(names.forSupertypeFunction(ValueType.object(name))));
|
||||
header.setAddress(CLASS_PARENT, parentPtr);
|
||||
|
||||
ClassReader cls = processedClassSource.get(name);
|
||||
|
@ -372,8 +380,7 @@ public class WasmClassGenerator {
|
|||
if (cls != null && binaryData.start >= 0
|
||||
&& cls.getMethod(new MethodDescriptor("<clinit>", ValueType.VOID)) != null
|
||||
&& classInitializerInfo.isDynamicInitializer(name)) {
|
||||
header.setInt(CLASS_INIT, functionTable.size());
|
||||
functionTable.add(names.forClassInitializer(name));
|
||||
header.setInt(CLASS_INIT, getFunctionPointer(names.forClassInitializer(name)));
|
||||
} else {
|
||||
header.setInt(CLASS_INIT, -1);
|
||||
}
|
||||
|
@ -450,11 +457,8 @@ public class WasmClassGenerator {
|
|||
if (method != null) {
|
||||
VirtualTableEntry entry = vtable.getEntry(method);
|
||||
if (entry != null) {
|
||||
methodIndex = functions.computeIfAbsent(entry.getImplementor(), implementor -> {
|
||||
int result = functionTable.size();
|
||||
functionTable.add(names.forMethod(implementor));
|
||||
return result;
|
||||
});
|
||||
methodIndex = functions.computeIfAbsent(entry.getImplementor(),
|
||||
implementor -> getFunctionPointer(names.forMethod(implementor)));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1654,6 +1654,16 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
public int getStaticField(FieldReference field) {
|
||||
return classGenerator.getFieldOffset(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getClassPointer(ValueType type) {
|
||||
return classGenerator.getClassPointer(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFunctionPointer(String name) {
|
||||
return classGenerator.getFunctionPointer(name);
|
||||
}
|
||||
};
|
||||
|
||||
private WasmLocal getTemporary(WasmType type) {
|
||||
|
|
|
@ -15,7 +15,12 @@
|
|||
*/
|
||||
package org.teavm.backend.wasm.intrinsics;
|
||||
|
||||
import org.teavm.dependency.DependencyAnalyzer;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface WasmIntrinsicFactory {
|
||||
WasmIntrinsic create(WasmIntrinsicFactoryContext context);
|
||||
|
||||
default void contributeDependencies(DependencyAnalyzer analyzer) {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import org.teavm.backend.wasm.model.WasmType;
|
|||
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||
import org.teavm.diagnostics.Diagnostics;
|
||||
import org.teavm.model.FieldReference;
|
||||
import org.teavm.model.ValueType;
|
||||
|
||||
public interface WasmIntrinsicManager {
|
||||
WasmExpression generate(Expr expr);
|
||||
|
@ -40,5 +41,9 @@ public interface WasmIntrinsicManager {
|
|||
|
||||
int getStaticField(FieldReference field);
|
||||
|
||||
int getClassPointer(ValueType type);
|
||||
|
||||
int getFunctionPointer(String name);
|
||||
|
||||
void releaseTemporary(WasmLocal local);
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.teavm.backend.wasm.model.expression.WasmExpression;
|
|||
import org.teavm.backend.wasm.model.expression.WasmFloatBinary;
|
||||
import org.teavm.backend.wasm.model.expression.WasmFloatBinaryOperation;
|
||||
import org.teavm.backend.wasm.model.expression.WasmFloatType;
|
||||
import org.teavm.backend.wasm.model.expression.WasmIndirectCall;
|
||||
import org.teavm.backend.wasm.model.expression.WasmIntBinary;
|
||||
import org.teavm.backend.wasm.model.expression.WasmIntBinaryOperation;
|
||||
import org.teavm.backend.wasm.model.expression.WasmIntType;
|
||||
|
@ -40,6 +41,7 @@ public class WasmRuntimeIntrinsic implements WasmIntrinsic {
|
|||
case "gtu":
|
||||
case "ltu":
|
||||
case "initStack":
|
||||
case "callFunctionFromTable":
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
@ -61,6 +63,11 @@ public class WasmRuntimeIntrinsic implements WasmIntrinsic {
|
|||
case "gtu":
|
||||
return comparison(WasmIntBinaryOperation.GT_UNSIGNED, WasmFloatBinaryOperation.GT,
|
||||
invocation, manager);
|
||||
case "callFunctionFromTable": {
|
||||
var call = new WasmIndirectCall(manager.generate(invocation.getArguments().get(0)));
|
||||
call.getArguments().add(manager.generate(invocation.getArguments().get(1)));
|
||||
return call;
|
||||
}
|
||||
default:
|
||||
throw new IllegalArgumentException(invocation.getMethod().getName());
|
||||
}
|
||||
|
|
|
@ -120,61 +120,12 @@ class MetadataIntrinsic implements WasmIntrinsic {
|
|||
}
|
||||
|
||||
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;
|
||||
return writer.writeMap(
|
||||
resourceMap.keys(),
|
||||
String::hashCode,
|
||||
stringPool::getStringPointer,
|
||||
key -> writeValue(writer, stringPool, resourceMap.get(key))
|
||||
);
|
||||
}
|
||||
|
||||
private int writeResource(BinaryWriter writer, WasmStringPool stringPool, ResourceArray<?> resourceArray) {
|
||||
|
@ -195,14 +146,6 @@ class MetadataIntrinsic implements WasmIntrinsic {
|
|||
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) {
|
||||
|
|
Loading…
Reference in New Issue
Block a user