Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Primitive, non boxing, long array based MStack #531

Merged
merged 28 commits into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,13 +140,13 @@ when we want to go back to Java. This export function takes an `i32` argument. W
on the return value to get back the Java integer:

```java
Value result = iterFact.apply(Value.i32(5))[0];
System.out.println("Result: " + result.asInt()); // should print 120 (5!)
long result = iterFact.apply(5)[0];
System.out.println("Result: " + result); // should print 120 (5!)
```

<!--
```java
writeResultFile("factorial.result", "" + result.asInt());
writeResultFile("factorial.result", "" + result);
```
-->

Expand Down Expand Up @@ -192,7 +192,7 @@ Memory memory = instance.memory();
String message = "Hello, World!";
int len = message.getBytes().length;
// allocate {len} bytes of memory, this returns a pointer to that memory
int ptr = alloc.apply(Value.i32(len))[0].asInt();
int ptr = (int) alloc.apply(len)[0];
// We can now write the message to the module's memory:
memory.writeString(ptr, message);
```
Expand All @@ -201,14 +201,14 @@ Now we can call `countVowels` with this pointer to the string. It will do it's j
call `dealloc` to free that memory in the module. Though the module could do this itself if you want:

```java
Value result = countVowels.apply(Value.i32(ptr), Value.i32(len))[0];
dealloc.apply(Value.i32(ptr), Value.i32(len));
assert(3 == result.asInt()); // 3 vowels in Hello, World!
var result = countVowels.apply(ptr, len)[0];
dealloc.apply(ptr, len);
assert(3L == result); // 3 vowels in Hello, World!
```

<!--
```java
writeResultFile("countVowels.result", "" + result.asInt());
writeResultFile("countVowels.result", "" + result);
```
-->

Expand Down Expand Up @@ -253,9 +253,9 @@ import com.dylibso.chicory.wasm.types.ValueType;
var func = new HostFunction(
"console",
"log",
(Instance instance, Value... args) -> { // decompiled is: console_log(13, 0);
var len = args[0].asInt();
var offset = args[1].asInt();
(Instance instance, long... args) -> { // decompiled is: console_log(13, 0);
var len = (int) args[0];
var offset = (int) args[1];
var message = instance.memory().readString(offset, len);
println(message);
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

// https://github.com/WebAssembly/spec/blob/ee82c8e50c5106e0cedada0a083d4cc4129034a2/interpreter/host/spectest.ml
public final class Spectest {
private static final WasmFunctionHandle noop = (Instance instance, Value... args) -> null;
private static final WasmFunctionHandle noop = (Instance instance, long... args) -> null;

private Spectest() {}

Expand Down
1 change: 0 additions & 1 deletion aot/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-util</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.approvaltests</groupId>
Expand Down
24 changes: 11 additions & 13 deletions aot/src/main/java/com/dylibso/chicory/aot/AotEmitters.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import static com.dylibso.chicory.aot.AotMethods.CHECK_INTERRUPTION;
import static com.dylibso.chicory.aot.AotMethods.INSTANCE_READ_GLOBAL;
import static com.dylibso.chicory.aot.AotMethods.INSTANCE_SET_ELEMENT;
import static com.dylibso.chicory.aot.AotMethods.INSTANCE_WRITE_GLOBAL;
import static com.dylibso.chicory.aot.AotMethods.MEMORY_COPY;
import static com.dylibso.chicory.aot.AotMethods.MEMORY_DROP;
import static com.dylibso.chicory.aot.AotMethods.MEMORY_FILL;
Expand Down Expand Up @@ -31,12 +30,14 @@
import static com.dylibso.chicory.aot.AotMethods.TABLE_SET;
import static com.dylibso.chicory.aot.AotMethods.TABLE_SIZE;
import static com.dylibso.chicory.aot.AotMethods.THROW_OUT_OF_BOUNDS_MEMORY_ACCESS;
import static com.dylibso.chicory.aot.AotMethods.WRITE_GLOBAL;
import static com.dylibso.chicory.aot.AotUtil.StackSize;
import static com.dylibso.chicory.aot.AotUtil.boxer;
import static com.dylibso.chicory.aot.AotUtil.callIndirectMethodName;
import static com.dylibso.chicory.aot.AotUtil.callIndirectMethodType;
import static com.dylibso.chicory.aot.AotUtil.emitInvokeStatic;
import static com.dylibso.chicory.aot.AotUtil.emitInvokeVirtual;
import static com.dylibso.chicory.aot.AotUtil.emitJvmToLong;
import static com.dylibso.chicory.aot.AotUtil.emitLongToJvm;
import static com.dylibso.chicory.aot.AotUtil.emitPop;
import static com.dylibso.chicory.aot.AotUtil.jvmType;
import static com.dylibso.chicory.aot.AotUtil.loadTypeOpcode;
Expand All @@ -45,7 +46,6 @@
import static com.dylibso.chicory.aot.AotUtil.methodTypeFor;
import static com.dylibso.chicory.aot.AotUtil.stackSize;
import static com.dylibso.chicory.aot.AotUtil.storeTypeOpcode;
import static com.dylibso.chicory.aot.AotUtil.unboxer;
import static com.dylibso.chicory.aot.AotUtil.validateArgumentType;
import static com.dylibso.chicory.wasm.types.Value.REF_NULL_VALUE;

Expand Down Expand Up @@ -218,21 +218,19 @@ public static void GLOBAL_GET(AotContext ctx, AnnotatedInstruction ins, MethodVi
asm.visitLdcInsn(globalIndex);
emitInvokeVirtual(asm, INSTANCE_READ_GLOBAL);

Method unboxer = unboxer(ctx.globalTypes().get(globalIndex));
emitInvokeVirtual(asm, unboxer);
var globalType = ctx.globalTypes().get(globalIndex);
emitLongToJvm(asm, ctx.globalTypes().get(globalIndex));

ctx.pushStackSize(stackSize(unboxer.getReturnType()));
ctx.pushStackSize(stackSize(globalType));
}

public static void GLOBAL_SET(AotContext ctx, AnnotatedInstruction ins, MethodVisitor asm) {
int globalIndex = (int) ins.operand(0);

emitInvokeStatic(asm, boxer(ctx.globalTypes().get(globalIndex)));
asm.visitVarInsn(Opcodes.ALOAD, ctx.instanceSlot());
asm.visitInsn(Opcodes.SWAP);
emitJvmToLong(asm, ctx.globalTypes().get(globalIndex));
asm.visitLdcInsn(globalIndex);
asm.visitInsn(Opcodes.SWAP);
emitInvokeVirtual(asm, INSTANCE_WRITE_GLOBAL);
asm.visitVarInsn(Opcodes.ALOAD, ctx.instanceSlot());
emitInvokeStatic(asm, WRITE_GLOBAL);
}

public static void TABLE_GET(AotContext ctx, AnnotatedInstruction ins, MethodVisitor asm) {
Expand Down Expand Up @@ -772,8 +770,8 @@ private static void emitUnboxResult(MethodVisitor asm, AotContext ctx, List<Valu
ValueType type = types.get(i);
asm.visitVarInsn(Opcodes.ALOAD, ctx.tempSlot());
asm.visitLdcInsn(i);
asm.visitInsn(Opcodes.AALOAD);
emitInvokeVirtual(asm, unboxer(type));
asm.visitInsn(Opcodes.LALOAD);
emitLongToJvm(asm, type);
}
}
}
43 changes: 21 additions & 22 deletions aot/src/main/java/com/dylibso/chicory/aot/AotMachine.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,24 @@
import static com.dylibso.chicory.aot.AotMethods.CHECK_INTERRUPTION;
import static com.dylibso.chicory.aot.AotMethods.INSTANCE_CALL_HOST_FUNCTION;
import static com.dylibso.chicory.aot.AotMethods.THROW_TRAP_EXCEPTION;
import static com.dylibso.chicory.aot.AotUtil.boxer;
import static com.dylibso.chicory.aot.AotUtil.boxerHandle;
import static com.dylibso.chicory.aot.AotUtil.callIndirectMethodName;
import static com.dylibso.chicory.aot.AotUtil.callIndirectMethodType;
import static com.dylibso.chicory.aot.AotUtil.defaultValue;
import static com.dylibso.chicory.aot.AotUtil.emitInvokeStatic;
import static com.dylibso.chicory.aot.AotUtil.emitInvokeVirtual;
import static com.dylibso.chicory.aot.AotUtil.emitJvmToLong;
import static com.dylibso.chicory.aot.AotUtil.emitLongToJvm;
import static com.dylibso.chicory.aot.AotUtil.emitPop;
import static com.dylibso.chicory.aot.AotUtil.jvmReturnType;
import static com.dylibso.chicory.aot.AotUtil.jvmToLongHandle;
import static com.dylibso.chicory.aot.AotUtil.jvmTypes;
import static com.dylibso.chicory.aot.AotUtil.loadTypeOpcode;
import static com.dylibso.chicory.aot.AotUtil.localType;
import static com.dylibso.chicory.aot.AotUtil.longToJvmHandle;
import static com.dylibso.chicory.aot.AotUtil.methodNameFor;
import static com.dylibso.chicory.aot.AotUtil.methodTypeFor;
import static com.dylibso.chicory.aot.AotUtil.slotCount;
import static com.dylibso.chicory.aot.AotUtil.storeTypeOpcode;
import static com.dylibso.chicory.aot.AotUtil.unboxer;
import static com.dylibso.chicory.aot.AotUtil.unboxerHandle;
import static com.dylibso.chicory.wasm.types.Instruction.EMPTY_OPERANDS;
import static java.lang.invoke.MethodHandles.filterArguments;
import static java.lang.invoke.MethodHandles.filterReturnValue;
Expand Down Expand Up @@ -52,7 +52,6 @@
import com.dylibso.chicory.wasm.types.GlobalImport;
import com.dylibso.chicory.wasm.types.Instruction;
import com.dylibso.chicory.wasm.types.OpCode;
import com.dylibso.chicory.wasm.types.Value;
import com.dylibso.chicory.wasm.types.ValueType;
import java.io.PrintWriter;
import java.lang.invoke.MethodHandle;
Expand Down Expand Up @@ -354,9 +353,9 @@ private static List<FunctionType> getFunctionTypes(Module module) {
}

@Override
public Value[] call(int funcId, Value[] args) throws ChicoryException {
public long[] call(int funcId, long[] args) throws ChicoryException {
try {
return (Value[]) compiledFunctions[funcId].invokeExact(args);
return (long[]) compiledFunctions[funcId].invokeExact(args);
} catch (ChicoryException e) {
// propagate ChicoryExceptions
throw e;
Expand Down Expand Up @@ -528,19 +527,19 @@ private static MethodHandle adaptSignature(FunctionType type, MethodHandle handl
var argTypes = type.params();
var argHandlers = new MethodHandle[type.params().size()];
for (int i = 0; i < argHandlers.length; i++) {
argHandlers[i] = unboxerHandle(argTypes.get(i));
argHandlers[i] = longToJvmHandle(argTypes.get(i));
}
MethodHandle result = filterArguments(handle, 0, argHandlers);
result = result.asSpreader(Value[].class, argTypes.size());
result = result.asSpreader(long[].class, argTypes.size());

if (type.returns().isEmpty()) {
return result.asType(result.type().changeReturnType(Value[].class));
return result.asType(result.type().changeReturnType(long[].class));
}
if (type.returns().size() > 1) {
return result;
}
result = filterReturnValue(result, boxerHandle(type.returns().get(0)));
return filterReturnValue(result, ValueWrapper.HANDLE);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think ValueWrapper is unused now

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

now it's a LongArrayWrapper to: long -> long[]

result = filterReturnValue(result, jvmToLongHandle(type.returns().get(0)));
return filterReturnValue(result, LongArrayWrapper.HANDLE);
}

private static void emitConstructor(ClassVisitor writer) {
Expand Down Expand Up @@ -592,16 +591,16 @@ private static void compileHostFunction(int funcId, FunctionType type, MethodVis

private static void emitBoxArguments(MethodVisitor asm, List<ValueType> types) {
int slot = 0;
// box the arguments into Value[]
// box the arguments into long[]
asm.visitLdcInsn(types.size());
asm.visitTypeInsn(Opcodes.ANEWARRAY, getInternalName(Value.class));
asm.visitIntInsn(Opcodes.NEWARRAY, Opcodes.T_LONG); // long
for (int i = 0; i < types.size(); i++) {
asm.visitInsn(Opcodes.DUP);
asm.visitLdcInsn(i);
ValueType valueType = types.get(i);
asm.visitVarInsn(loadTypeOpcode(valueType), slot);
emitInvokeStatic(asm, boxer(valueType));
asm.visitInsn(Opcodes.AASTORE);
emitJvmToLong(asm, valueType);
asm.visitInsn(Opcodes.LASTORE);
slot += slotCount(valueType);
}
}
Expand All @@ -610,13 +609,13 @@ private static void emitUnboxResult(FunctionType type, MethodVisitor asm) {
Class<?> returnType = jvmReturnType(type);
if (returnType == void.class) {
asm.visitInsn(Opcodes.RETURN);
} else if (returnType == Value[].class) {
} else if (returnType == long[].class) {
asm.visitInsn(Opcodes.ARETURN);
} else {
// unbox the result from Value[0]
// unbox the result from long[0]
asm.visitLdcInsn(0);
asm.visitInsn(Opcodes.AALOAD);
emitInvokeVirtual(asm, unboxer(type.returns().get(0)));
asm.visitInsn(Opcodes.LALOAD);
emitLongToJvm(asm, type.returns().get(0));
asm.visitInsn(returnTypeOpcode(type));
}
}
Expand Down Expand Up @@ -879,7 +878,7 @@ private FunctionType blockType(Instruction ins) {
}

private static MethodType valueMethodType(List<ValueType> types) {
return methodType(Value[].class, jvmTypes(types));
return methodType(long[].class, jvmTypes(types));
}

private static String valueMethodName(List<ValueType> types) {
Expand All @@ -891,7 +890,7 @@ private static String valueMethodName(List<ValueType> types) {

private static int returnTypeOpcode(FunctionType type) {
Class<?> returnType = jvmReturnType(type);
if (returnType == Value[].class) {
if (returnType == long[].class) {
return Opcodes.ARETURN;
}
if (returnType == int.class) {
Expand Down
24 changes: 15 additions & 9 deletions aot/src/main/java/com/dylibso/chicory/aot/AotMethods.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
import com.dylibso.chicory.wasm.exceptions.ChicoryException;
import com.dylibso.chicory.wasm.types.Element;
import com.dylibso.chicory.wasm.types.FunctionType;
import com.dylibso.chicory.wasm.types.Value;
import java.lang.reflect.Method;
import java.util.List;

Expand All @@ -22,7 +21,7 @@ public final class AotMethods {
static final Method CALL_INDIRECT;
static final Method INSTANCE_CALL_HOST_FUNCTION;
static final Method INSTANCE_READ_GLOBAL;
static final Method INSTANCE_WRITE_GLOBAL;
static final Method WRITE_GLOBAL;
static final Method INSTANCE_SET_ELEMENT;
static final Method MEMORY_COPY;
static final Method MEMORY_FILL;
Expand Down Expand Up @@ -60,15 +59,17 @@ public final class AotMethods {
CALL_INDIRECT =
AotMethods.class.getMethod(
"callIndirect",
Value[].class,
long[].class,
int.class,
int.class,
int.class,
Instance.class);
INSTANCE_CALL_HOST_FUNCTION =
Instance.class.getMethod("callHostFunction", int.class, Value[].class);
Instance.class.getMethod("callHostFunction", int.class, long[].class);
INSTANCE_READ_GLOBAL = Instance.class.getMethod("readGlobal", int.class);
INSTANCE_WRITE_GLOBAL = Instance.class.getMethod("writeGlobal", int.class, Value.class);
WRITE_GLOBAL =
AotMethods.class.getMethod(
"writeGlobal", long.class, int.class, Instance.class);
INSTANCE_SET_ELEMENT = Instance.class.getMethod("setElement", int.class, Element.class);
MEMORY_COPY =
AotMethods.class.getMethod(
Expand Down Expand Up @@ -165,13 +166,13 @@ public final class AotMethods {
private AotMethods() {}

@UsedByGeneratedCode
public static Value[] callIndirect(
Value[] args, int typeId, int funcTableIdx, int tableIdx, Instance instance) {
public static long[] callIndirect(
long[] args, int typeId, int funcTableIdx, int tableIdx, Instance instance) {
TableInstance table = instance.table(tableIdx);

instance = requireNonNullElse(table.instance(funcTableIdx), instance);

int funcId = table.ref(funcTableIdx).asFuncRef();
int funcId = table.ref(funcTableIdx);
if (funcId == REF_NULL_VALUE) {
throw new ChicoryException("uninitialized element " + funcTableIdx);
}
Expand All @@ -193,7 +194,7 @@ public static boolean isRefNull(int ref) {

@UsedByGeneratedCode
public static int tableGet(int index, int tableIndex, Instance instance) {
return OpcodeImpl.TABLE_GET(instance, tableIndex, index).asFuncRef();
return (int) OpcodeImpl.TABLE_GET(instance, tableIndex, index);
}

@UsedByGeneratedCode
Expand Down Expand Up @@ -341,4 +342,9 @@ public static void checkInterruption() {
throw new ChicoryException("Thread interrupted");
}
}

@UsedByGeneratedCode
public static void writeGlobal(long value, int index, Instance instance) {
instance.writeGlobal(index, value);
}
}
Loading
Loading