summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOrangerot <purple@orangerot.dev>2025-05-12 00:52:51 +0200
committerOrangerot <purple@orangerot.dev>2025-05-12 00:52:51 +0200
commit3f13610b960311d653c696aff913e11948fb9ec4 (patch)
treec68475e288fa651742b4e148884352ed13f896ce
parent47406b5defae9d4ec6a94aeee9454514d835d42b (diff)
feat: use types of values in stack and instructionstyped-values
-rw-r--r--wai.c161
1 files changed, 121 insertions, 40 deletions
diff --git a/wai.c b/wai.c
index 147d626..336294f 100644
--- a/wai.c
+++ b/wai.c
@@ -27,7 +27,10 @@
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <sys/stat.h>
+#include <inttypes.h>
+#include <sys/types.h>
enum section {
Section_Custom,
@@ -47,11 +50,10 @@ enum section {
#define STACK_CAPACITY 1024
struct stack {
- double items[STACK_CAPACITY];
- size_t count;
+ u_char items[STACK_CAPACITY];
+ size_t bytes;
};
-
struct module {
struct type_t *types;
u_char *funcs[128];
@@ -72,7 +74,6 @@ enum INSTRUCTION {
INSTR_CALL = 0x10,
INSTR_ELSE = 0x05,
INSTR_END = 0x0b,
- INSTR_F64 = 0x7C,
INSTR_F64_CONST = 0x44,
INSTR_F64_LT = 0x63,
INSTR_F64_MUL = 0xa2,
@@ -91,26 +92,81 @@ enum TYPE {
TYPE_EXTERNREF = 0x6F
};
+static const int TYPE_SIZE[] = {
+ [TYPE_I32] = 4,
+ [TYPE_I64] = 8,
+ [TYPE_F32] = 4,
+ [TYPE_F64] = 8,
+ [TYPE_V128] = 16,
+ [TYPE_FUNCREF] = 16,
+ [TYPE_EXTERNREF] = 16
+};
+
+struct value_t {
+ enum TYPE type;
+ union {
+ int32_t i32;
+ int64_t i64;
+ float f32;
+ double f64;
+ __int128 v128;
+ int64_t funcref;
+ int64_t extref;
+ } value;
+};
+
#define incr(i, len) i++; if (i >= len) {return -1;}
-void stack_push(struct stack *s, double a) {
- s->items[s->count++] = a;
+void stack_push(struct stack *s, const struct value_t *value) {
+ size_t type_size = TYPE_SIZE[value->type];
+ memcpy(&(s->items[s->bytes]), &value->value, type_size);
+ s->items[s->bytes + type_size] = value->type;
+ s->bytes += type_size + 1;
+
printf("stack: ");
- for (int i = 0; i < s->count; i++) {
- printf("%f, ", s->items[i]);
+ for (int i = s->bytes - 1; i > 0; i -= TYPE_SIZE[s->items[i]] + 1) {
+ enum TYPE t = s->items[i];
+ size_t type_size = TYPE_SIZE[t];
+ void *value = &s->items[i - type_size];
+
+ switch (t) {
+ case TYPE_I32:
+ printf("%d (I32)", *(int32_t*)value);
+ break;
+ case TYPE_I64:
+ printf("%ld (I32)", *(int64_t*)value);
+ break;
+ case TYPE_F32:
+ printf("%f (F32)", *(float*)value);
+ break;
+ case TYPE_F64:
+ printf("%f (F64)", *(double*)value);
+ break;
+ case TYPE_V128:
+ printf("%ld (V128)", *(__int128*)value);
+ break;
+ case TYPE_FUNCREF:
+ printf("%ld (EREF)", *(int64_t*)value);
+ break;
+ case TYPE_EXTERNREF:
+ printf("%ld (EREF)", *(int64_t*)value);
+ break;
+ }
+ printf(", ");
}
printf("\n");
}
-double stack_pop(struct stack *s) {
- s->count--;
- return s->items[s->count];
-}
-
-double stack_top(struct stack *s) {
- return s->items[s->count-1];
+void stack_top(struct stack *s, struct value_t *value) {
+ value->type = s->items[s->bytes-1];
+ memcpy(&value->value, &(s->items[s->bytes - 1 - TYPE_SIZE[value->type]]), TYPE_SIZE[value->type]);
}
+void stack_pop(struct stack *s, struct value_t *value) {
+ stack_top(s, value);
+ s->bytes -= TYPE_SIZE[value->type] + 1;
+}
+
int parse_type(u_char *binary, int len) {
int i = 0;
enum TYPE param = binary[i];
@@ -136,47 +192,71 @@ int parse_instruction(struct module *module, u_char *binary, double param, int l
int i = 0;
enum INSTRUCTION instr = (u_char) binary[i];
u_char *instr_addr = &binary[i];
+ struct value_t a = {0};
+ struct value_t b = {0};
+ struct value_t result = {0};
+
incr(i, len);
switch (instr) {
- case INSTR_CALL:
- int a = binary[i];
+ case INSTR_CALL: {
+ int func_index = binary[i];
incr(i, len);
- parse_function(module, module->funcs[a], stack_pop(&module->stack), len);
+ stack_pop(&module->stack, &a);
+ parse_function(module, module->funcs[func_index], a.value.f64, len);
break;
+ }
case INSTR_ELSE:
printf("reached else instruction: impossible!\n");
case INSTR_END:
break;
- case INSTR_F64:
- break;
case INSTR_F64_CONST:
- double k = *(double*)&binary[i];
- stack_push(&module->stack, k);
+ result.type = TYPE_F64;
+ result.value.f64 = *(double*)&binary[i];
i += 8;
+ stack_push(&module->stack, &result);
break;
case INSTR_F64_LT: {
- double b = stack_pop(&module->stack);
- double a = stack_pop(&module->stack);
- stack_push(&module->stack, a < b);
+ stack_pop(&module->stack, &a);
+ stack_pop(&module->stack, &b);
+ if (a.type != TYPE_F64 || b.type != TYPE_F64)
+ printf("Wrong types!\n");
+ result.type = TYPE_F64;
+ result.value.f64 = b.value.f64 < a.value.f64;
+ stack_push(&module->stack, &result);
break;
}
case INSTR_F64_MUL: {
- double b = stack_pop(&module->stack);
- double a = stack_pop(&module->stack);
- stack_push(&module->stack, a * b);
+ stack_pop(&module->stack, &a);
+ stack_pop(&module->stack, &b);
+ if (a.type != TYPE_F64 || b.type != TYPE_F64)
+ printf("Wrong types!\n");
+ result.type = TYPE_F64;
+ result.value.f64 = a.value.f64 * b.value.f64;
+ stack_push(&module->stack, &result);
break;
}
case INSTR_F64_SUB: {
- double b = stack_pop(&module->stack);
- double a = stack_pop(&module->stack);
- stack_push(&module->stack, a - b);
+ stack_pop(&module->stack, &a);
+ stack_pop(&module->stack, &b);
+ if (a.type != TYPE_F64 || b.type != TYPE_F64)
+ printf("Wrong types!\n");
+ result.type = TYPE_F64;
+ result.value.f64 = b.value.f64 - a.value.f64;
+ stack_push(&module->stack, &result);
break;
}
case INSTR_IF: {
- double a = stack_pop(&module->stack);
+ stack_pop(&module->stack, &a);
+ enum TYPE condition_type = binary[i];
+ incr(i, len);
+ if (a.type != condition_type)
+ printf("Wrong types!\n");
+
while (binary[i] != INSTR_ELSE) {
- if (a) {
+ // TODO test condition with correct type.
+ // This might not matter since all types are false with 0x0
+ if (a.value.i64) {
i += parse_instruction(module, &binary[i], param, len);
} else {
incr(i, len);
@@ -184,7 +264,7 @@ int parse_instruction(struct module *module, u_char *binary, double param, int l
}
incr(i, len);
while (binary[i] != INSTR_END) {
- if (a) {
+ if (a.value.i64) {
incr(i, len);
} else {
i += parse_instruction(module, &binary[i], param, len);
@@ -193,11 +273,12 @@ int parse_instruction(struct module *module, u_char *binary, double param, int l
incr(i, len);
break;
}
- case INSTR_LOCAL_GET:
+ case INSTR_LOCAL_GET: {
int local_index = binary[i];
incr(i, len);
- stack_push(&module->stack, param);
+ stack_push(&module->stack, &(struct value_t) {.value.f64 = param, .type = TYPE_F64});
break;
+ }
default:
printf("unknown instruction! %x at %lx\n", instr, instr_addr - module->binary);
exit(1);
@@ -299,7 +380,7 @@ int parse_section(struct module *module, u_char *binary, int len) {
module->funcs[function_i] = &binary[i];
i += parse_function(module, &binary[i], 4, len);
}
- printf("result: %f\n", module->stack.items[0]);
+ // printf("result: %f\n", module->stack.items[0]);
break;
case Section_Data:
break;
@@ -316,9 +397,9 @@ int parse_section(struct module *module, u_char *binary, int len) {
int parse_module(u_char *binary, size_t len) {
int i = 0;
- u_char *magic = "\0asm";
+ char *magic = "\0asm";
while (i < 4) {
- if (binary[i] != magic[i]) {
+ if ((char) binary[i] != magic[i]) {
fprintf(stderr, "no wasm magic\n");
return 0;
}
@@ -355,7 +436,7 @@ int main(int argc, char **argv) {
stat(argv[1], &st);
printf("size: %ld\n", st.st_size);
- unsigned char *binary = malloc(st.st_size);
+ u_char *binary = malloc(st.st_size);
fread(binary, st.st_size, st.st_size, file);
if (parse_module(binary, st.st_size) == -1) {