refactor codegen to use writer struct

This commit is contained in:
Awal Garg 2018-01-02 22:30:58 +05:30 committed by Fabian
parent 9dc4ff6973
commit 74e6500bf1
8 changed files with 356 additions and 375 deletions

View file

@ -26,52 +26,53 @@ extern uint16_t* const reg16;
extern int8_t* const reg8s;
extern int16_t* const reg16s;
extern int32_t* const reg32s;
extern Writer cs;
static void jit_resolve_modrm32_(int32_t);
static void jit_resolve_modrm16_(int32_t);
void gen_increment_instruction_pointer(int32_t n)
{
push_i32((int32_t)instruction_pointer); // store address of ip
push_i32(&cs, (int32_t)instruction_pointer); // store address of ip
load_i32((int32_t)instruction_pointer); // load ip
push_i32(n); // load value to add to it
add_i32();
load_i32(&cs, (int32_t)instruction_pointer); // load ip
push_i32(&cs, n); // load value to add to it
add_i32(&cs);
store_i32(); // store it back in
store_i32(&cs); // store it back in
}
void gen_set_previous_eip()
{
push_i32((int32_t)previous_ip); // store address of previous ip
load_i32((int32_t)instruction_pointer); // load ip
store_i32(); // store it as previous ip
push_i32(&cs, (int32_t)previous_ip); // store address of previous ip
load_i32(&cs, (int32_t)instruction_pointer); // load ip
store_i32(&cs); // store it as previous ip
}
void gen_fn0(char* fn, uint8_t fn_len)
{
int32_t fn_idx = get_fn_index(fn, fn_len, FN0_TYPE_INDEX);
call_fn(fn_idx);
call_fn(&cs, fn_idx);
}
void gen_fn1(char* fn, uint8_t fn_len, int32_t arg0)
{
int32_t fn_idx = get_fn_index(fn, fn_len, FN1_TYPE_INDEX);
push_i32(arg0);
call_fn(fn_idx);
push_i32(&cs, arg0);
call_fn(&cs, fn_idx);
}
void gen_fn2(char* fn, uint8_t fn_len, int32_t arg0, int32_t arg1)
{
int32_t fn_idx = get_fn_index(fn, fn_len, FN2_TYPE_INDEX);
push_i32(arg0);
push_i32(arg1);
call_fn(fn_idx);
push_i32(&cs, arg0);
push_i32(&cs, arg1);
call_fn(&cs, fn_idx);
}
void gen_drop()
{
cs_write_u8(OP_DROP);
write_raw_u8(&cs, OP_DROP);
}
#define MODRM_ENTRY(n, work)\
@ -98,30 +99,30 @@ void gen_drop()
static void inline gen_modrm_entry_0(int32_t fn_idx, int32_t reg16_idx_1, int32_t reg16_idx_2, int32_t imm)
{
// generates: fn( ( reg1 + reg2 + imm ) & 0xFFFF )
load_u16(reg16_idx_1);
load_u16(reg16_idx_2);
add_i32();
load_u16(&cs, reg16_idx_1);
load_u16(&cs, reg16_idx_2);
add_i32(&cs);
push_i32(imm);
add_i32();
push_i32(&cs, imm);
add_i32(&cs);
push_i32(0xFFFF);
and_i32();
push_i32(&cs, 0xFFFF);
and_i32(&cs);
call_fn(fn_idx);
call_fn(&cs, fn_idx);
}
static void gen_modrm_entry_1(int32_t fn_idx, int32_t reg16_idx, int32_t imm)
{
// generates: fn ( ( reg + imm ) & 0xFFFF )
load_u16(reg16_idx);
push_i32(imm);
add_i32();
load_u16(&cs, reg16_idx);
push_i32(&cs, imm);
add_i32(&cs);
push_i32(0xFFFF);
and_i32();
push_i32(&cs, 0xFFFF);
and_i32(&cs);
call_fn(fn_idx);
call_fn(&cs, fn_idx);
}
static void jit_resolve_modrm16_(int32_t modrm_byte)
@ -141,7 +142,7 @@ static void jit_resolve_modrm16_(int32_t modrm_byte)
MODRM_ENTRY16_1(5, ds, (int32_t)(reg16 + DI))
// special case
MODRM_ENTRY(0x00 | 6, call_fn_with_arg(ds, read_imm16()))
MODRM_ENTRY(0x00 | 6, call_fn_with_arg(&cs, ds, read_imm16()))
MODRM_ENTRY(0x40 | 6, gen_modrm_entry_1(ss, (int32_t)(reg16 + BP), read_imm8s()))
MODRM_ENTRY(0x80 | 6, gen_modrm_entry_1(ss, (int32_t)(reg16 + BP), read_imm16()))
@ -154,9 +155,9 @@ static void jit_resolve_modrm16_(int32_t modrm_byte)
void gen_resolve_modrm16(int32_t modrm_byte)
{
push_u32(RESULT_LOC);
push_u32(&cs, RESULT_LOC);
jit_resolve_modrm16_(modrm_byte);
store_i32();
store_i32(&cs);
}
#define MODRM_ENTRY32_0(row, seg, reg)\
@ -167,11 +168,11 @@ void gen_resolve_modrm16(int32_t modrm_byte)
static void gen_modrm32_entry(int32_t fn_idx, int32_t reg32s_idx, int32_t imm)
{
// generates: fn ( reg + imm )
load_i32(reg32s_idx);
push_i32(imm);
add_i32();
load_i32(&cs, reg32s_idx);
push_i32(&cs, imm);
add_i32(&cs);
call_fn(fn_idx);
call_fn(&cs, fn_idx);
}
static void jit_resolve_sib(bool mod)
@ -214,21 +215,21 @@ static void jit_resolve_sib(bool mod)
// Where base is accessed from memory if base_is_mem_access or written as a constant otherwise
dbg_assert(seg < 16);
cs_write_u8(OP_I32CONST);
cs_write_u8(seg);
write_raw_u8(&cs, OP_I32CONST);
write_raw_u8(&cs, seg);
call_fn(fn_get_seg_prefix_idx);
call_fn(&cs, fn_get_seg_prefix_idx);
if(base_is_mem_access)
{
load_i32(base_addr);
load_i32(&cs, base_addr);
}
else
{
push_i32(base);
push_i32(&cs, base);
}
add_i32();
add_i32(&cs);
// We now have to generate an offset value to add
@ -242,27 +243,27 @@ static void jit_resolve_sib(bool mod)
uint8_t s = sib_byte >> 6 & 3;
load_i32((int32_t)(reg32s + m));
load_i32(&cs, (int32_t)(reg32s + m));
// We don't use push_u32 here either since s will fit in 1 byte
cs_write_u8(OP_I32CONST);
cs_write_u8(s);
shl_i32();
write_raw_u8(&cs, OP_I32CONST);
write_raw_u8(&cs, s);
shl_i32(&cs);
add_i32();
add_i32(&cs);
}
static void modrm32_special_case_1()
{
jit_resolve_sib(true);
push_i32(read_imm8s());
add_i32();
push_i32(&cs, read_imm8s());
add_i32(&cs);
}
static void modrm32_special_case_2()
{
jit_resolve_sib(true);
push_i32(read_imm32s());
add_i32();
push_i32(&cs, read_imm32s());
add_i32(&cs);
}
static void jit_resolve_modrm32_(int32_t modrm_byte)
@ -281,7 +282,7 @@ static void jit_resolve_modrm32_(int32_t modrm_byte)
MODRM_ENTRY(0x00 | 4, jit_resolve_sib(false))
MODRM_ENTRY(0x40 | 4, modrm32_special_case_1())
MODRM_ENTRY(0x80 | 4, modrm32_special_case_2())
MODRM_ENTRY(0x00 | 5, call_fn_with_arg(ds, read_imm32s()))
MODRM_ENTRY(0x00 | 5, call_fn_with_arg(&cs, ds, read_imm32s()))
MODRM_ENTRY(0x40 | 5, gen_modrm32_entry(ss, (int32_t)(reg32s + EBP), read_imm8s()))
MODRM_ENTRY(0x80 | 5, gen_modrm32_entry(ss, (int32_t)(reg32s + EBP), read_imm32s()))
@ -295,9 +296,9 @@ static void jit_resolve_modrm32_(int32_t modrm_byte)
void gen_resolve_modrm32(int32_t modrm_byte)
{
push_i32(RESULT_LOC);
push_i32(&cs, RESULT_LOC);
jit_resolve_modrm32_(modrm_byte);
store_i32();
store_i32(&cs);
}
#undef MODRM_ENTRY
@ -314,10 +315,10 @@ void gen_modrm_fn1(char* fn, uint8_t fn_len, int32_t modrm_byte, int32_t arg0)
jit_resolve_modrm16_(modrm_byte);
}
push_i32(arg0);
push_i32(&cs, arg0);
int32_t fn_idx = get_fn_index(fn, fn_len, FN2_RET_TYPE_INDEX);
call_fn(fn_idx);
call_fn(&cs, fn_idx);
}
void gen_modrm_fn0(char* fn, uint8_t fn_len, int32_t modrm_byte)
@ -333,6 +334,6 @@ void gen_modrm_fn0(char* fn, uint8_t fn_len, int32_t modrm_byte)
}
int32_t fn_idx = get_fn_index(fn, fn_len, FN1_RET_TYPE_INDEX);
call_fn(fn_idx);
call_fn(&cs, fn_idx);
}

View file

@ -1,15 +0,0 @@
#pragma once
#include <stdint.h>
void gen_fn0(char* fn, uint8_t fn_len);
void gen_fn1(char* fn, uint8_t fn_len, int32_t arg0);
void gen_fn2(char* fn, uint8_t fn_len, int32_t arg0, int32_t arg1);
void gen_modrm_fn0(char* fn, uint8_t fn_len, int32_t modrm_byte);
void gen_modrm_fn1(char* fn, uint8_t fn_len, int32_t modrm_byte, int32_t arg0);
void gen_resolve_modrm16(int32_t modrm_byte);
void gen_resolve_modrm32(int32_t modrm_byte);
void gen_increment_instruction_pointer(int32_t n);
void gen_set_previous_eip();
void gen_drop();

View file

@ -5,184 +5,12 @@
#include "cstring.h"
#include "const.h"
#include "wasm_opcodes.h"
#include "codegen_util.h"
#include "codegen.h"
#include "util.h"
#include "module_init.h"
uint8_t* cs_ptr = code_section;
static void write_type_section()
{
write_u8(SC_TYPE);
uint8_t* ptr_section_size = op_ptr;
write_u8(0);
write_u8(6); // number of type descriptors
// FN0
write_u8(TYPE_FUNC);
write_u8(0); // no args
write_u8(0); // no return val
// FN1
write_u8(TYPE_FUNC);
write_u8(1);
write_u8(TYPE_I32);
write_u8(0);
// FN2
write_u8(TYPE_FUNC);
write_u8(2);
write_u8(TYPE_I32);
write_u8(TYPE_I32);
write_u8(0);
// FN0_RET
write_u8(TYPE_FUNC);
write_u8(0);
write_u8(1);
write_u8(TYPE_I32);
// FN1_RET
write_u8(TYPE_FUNC);
write_u8(1);
write_u8(TYPE_I32);
write_u8(1);
write_u8(TYPE_I32);
// FN2_RET
write_u8(TYPE_FUNC);
write_u8(2);
write_u8(TYPE_I32);
write_u8(TYPE_I32);
write_u8(1);
write_u8(TYPE_I32);
*ptr_section_size = (op_ptr - 1) - ptr_section_size;
}
// Import table
static uint8_t* ptr_import_count = (uint8_t*) 0;
static uint8_t* ptr_import_entries = (uint8_t*) 0;
static uint8_t* ptr_import_table_size = (uint8_t*) 0;
// The import table size is written in leb encoding, which we can't read by simple dereferencing so
// we store the actual value separately. This is needed since we reserve two bytes for the import
// table size as it can exceed 127
// Default value is one as the section starts with containing one byte for the import count
static uint32_t import_table_size = 1;
// Goes over the import block to find index of an import entry by function name
// Returns -1 if not found
static int32_t get_import_index(char* fn, uint8_t fn_len)
{
uint8_t* offset = ptr_import_entries;
for(int32_t i = 0; i < *ptr_import_count; i++)
{
offset += 1; // skip length of module name
offset += 1; // skip module name itself
uint8_t len = *offset++;
char* name = (char*) offset;
if (len == fn_len && strncmp(name, fn, fn_len) == 0)
{
return i;
}
offset += len; // skip the string
offset += 1; // skip import kind
offset += 1; // skip type index
}
return -1;
}
static void set_import_table_size(uint16_t size)
{
import_table_size = size;
write_fixed_leb16_to_ptr(ptr_import_table_size, size);
}
static void write_import_section_preamble()
{
write_u8(SC_IMPORT);
ptr_import_table_size = op_ptr; // store current pointer location to write into later on
write_u8(1 | 0b10000000); write_u8(0); // 1 in 2 byte leb
// same as above but for count of entries
ptr_import_count = op_ptr;
write_u8(0);
// here after starts the actual list of imports
ptr_import_entries = op_ptr;
}
static void write_memory_import()
{
write_u8(1);
write_u8('e');
write_u8(1);
write_u8('m');
write_u8(EXT_MEMORY);
write_u8(0); // memory flag, 0 for no maximum memory limit present
write_u32(256); // initial memory length of 256 pages, takes 2 bytes in leb128
*ptr_import_count += 1;
set_import_table_size(import_table_size + 1 + 1 + 1 + 1 + 1 + 1 + 2);
}
static uint8_t write_import_entry(char* fn_name, uint8_t fn_name_len, uint8_t type_index)
{
write_u8(1); // length of module name
write_u8('e'); // module name
write_u8(fn_name_len);
for (uint8_t i = 0; i < fn_name_len; i++)
{
write_u8(fn_name[i]);
}
write_u8(EXT_FUNCTION);
write_u8(type_index);
*ptr_import_count += 1;
set_import_table_size(import_table_size + 1 + 1 + 1 + fn_name_len + 1 + 1);
return *ptr_import_count - 1;
}
static void write_function_section()
{
write_u8(SC_FUNCTION);
write_u8(2); // length of this section
write_u8(1); // count of signature indices
write_u8(FN0_TYPE_INDEX); // we export one function which is nullary
}
static void write_export_section()
{
write_u8(SC_EXPORT);
write_u8(1 + 1 + 1 + 1 + 1); // size of this section
write_u8(1); // count of table: just one function exported
write_u8(1); // length of exported function name
write_u8('f'); // function name
write_u8(EXT_FUNCTION);
// index of the exported function
// function space starts with imports. index of last import is import count - 1
// the last import however is a memory, so we subtract one from that
write_u8(*ptr_import_count - 1);
}
int32_t get_fn_index(char* fn, uint8_t fn_len, uint8_t type_index)
{
int32_t fn_idx = get_import_index(fn, fn_len);
if (fn_idx == -1)
{
return write_import_entry(fn, fn_len, type_index);
}
return fn_idx;
}
static Writer op = { .start = (uint8_t* const) 2048, .ptr = (uint8_t*) 2048, .len = 1024 };
Writer cs = { .start = (uint8_t* const) 3072, .ptr = (uint8_t*) 3072, .len = 1024 };
static uint8_t* op_ptr_reset_location;
static uint32_t import_table_size_reset_value;
@ -191,10 +19,10 @@ static uint32_t initial_import_count;
void gen_init()
{
// wasm magic header
write_u8(0); write_u8('a'); write_u8('s'); write_u8('m');
write_raw_u8(&op, 0); write_raw_u8(&op, 'a'); write_raw_u8(&op, 's'); write_raw_u8(&op, 'm');
// wasm version in leb128, 4 bytes
write_u8(WASM_VERSION); write_u8(0); write_u8(0); write_u8(0);
write_raw_u8(&op, WASM_VERSION); write_raw_u8(&op, 0); write_raw_u8(&op, 0); write_raw_u8(&op, 0);
write_type_section();
write_import_section_preamble();
@ -213,28 +41,19 @@ void gen_init()
assert(_fn_get_seg_prefix_idx == fn_get_seg_prefix_idx);
// store state of current pointers etc. so we can reset them later
op_ptr_reset_location = op_ptr;
op_ptr_reset_location = op.ptr;
initial_import_count = *ptr_import_count;
import_table_size_reset_value = import_table_size;
}
void gen_reset()
{
op_ptr = op_ptr_reset_location;
cs_ptr = code_section;
op.ptr = op_ptr_reset_location;
cs.ptr = cs.start;
*ptr_import_count = initial_import_count;
import_table_size = import_table_size_reset_value;
}
static void copy_code_section()
{
uint8_t* offset = code_section;
while (offset < cs_ptr)
{
write_u8(*offset++);
}
}
uintptr_t gen_finish()
{
write_memory_import();
@ -245,33 +64,33 @@ uintptr_t gen_finish()
uint8_t* ptr_fn_body_size = (uint8_t*) 0; // this as well
// write code section preamble
write_u8(SC_CODE);
ptr_code_section_size = op_ptr; // we will write to this location later
write_u8(0); write_u8(0); // write temp val for now using 2 bytes
write_raw_u8(&op, SC_CODE);
ptr_code_section_size = op.ptr; // we will write to this location later
write_raw_u8(&op, 0); write_raw_u8(&op, 0); // write temp val for now using 2 bytes
write_u8(1); // number of function bodies: just 1
write_raw_u8(&op, 1); // number of function bodies: just 1
// same as above but for body size of the function
ptr_fn_body_size = op_ptr;
write_u8(0); write_u8(0);
ptr_fn_body_size = op.ptr;
write_raw_u8(&op, 0); write_raw_u8(&op, 0);
write_u8(0); // count of locals, none
write_raw_u8(&op, 0); // count of locals, none
copy_code_section();
// write code section epilogue
write_u8(OP_END);
write_raw_u8(&op, OP_END);
// write the actual sizes to the pointer locations stored above. We subtract 1 from the actual
// value because the ptr itself points to two bytes
write_fixed_leb16_to_ptr(ptr_fn_body_size, ((op_ptr - 1) - ptr_fn_body_size) - 1);
write_fixed_leb16_to_ptr(ptr_code_section_size, ((op_ptr - 1) - ptr_code_section_size) - 1);
write_fixed_leb16_to_ptr(ptr_fn_body_size, ((op.ptr - 1) - ptr_fn_body_size) - 1);
write_fixed_leb16_to_ptr(ptr_code_section_size, ((op.ptr - 1) - ptr_code_section_size) - 1);
return (uintptr_t) op_ptr;
return (uintptr_t) op.ptr;
}
uintptr_t gen_get_final_offset()
{
return (uintptr_t) op_ptr;
return (uintptr_t) op.ptr;
}

View file

@ -1,6 +1,7 @@
#pragma once
#include <stdint.h>
#include "util.h"
#define FN0_TYPE_INDEX 0
#define FN1_TYPE_INDEX 1
@ -13,10 +14,21 @@ static uint8_t const fn_get_seg_prefix_ds_idx = 0;
static uint8_t const fn_get_seg_prefix_ss_idx = 1;
static uint8_t const fn_get_seg_prefix_idx = 2;
int32_t get_fn_index(char* fn, uint8_t fn_len, uint8_t type_index);
void gen_init(void);
void gen_reset(void);
uintptr_t gen_finish(void);
uintptr_t gen_get_final_offset(void);
int32_t get_fn_index(char* fn, uint8_t fn_len, uint8_t type_index);
void gen_fn0(char* fn, uint8_t fn_len);
void gen_fn1(char* fn, uint8_t fn_len, int32_t arg0);
void gen_fn2(char* fn, uint8_t fn_len, int32_t arg0, int32_t arg1);
void gen_modrm_fn0(char* fn, uint8_t fn_len, int32_t modrm_byte);
void gen_modrm_fn1(char* fn, uint8_t fn_len, int32_t modrm_byte, int32_t arg0);
void gen_resolve_modrm16(int32_t modrm_byte);
void gen_resolve_modrm32(int32_t modrm_byte);
void gen_increment_instruction_pointer(int32_t n);
void gen_set_previous_eip();
void gen_drop();

View file

@ -1,48 +0,0 @@
#pragma once
#include <stdint.h>
#include "util.h"
static uint8_t* const output = (uint8_t* const) 2048;
// pointer to next free byte slot in output buffer, incremented as we write along in the buffer
static uint8_t* op_ptr = output;
static uint8_t* const code_section = output + 1024;
extern uint8_t* cs_ptr;
// JS can keep strings at this location for passing them to wasm
//XXX: figure out a better location for this
static uint8_t* const str_input = code_section - 32;
static void inline write_u8(uint8_t x)
{
*op_ptr++ = x;
}
static void inline cs_write_u8(uint8_t x)
{
*cs_ptr++ = x;
}
static void inline write_i32(int32_t x)
{
op_ptr = _write_leb_i32(op_ptr, x);
}
static void inline cs_write_i32(int32_t x)
{
cs_ptr = _write_leb_i32(cs_ptr, x);
}
static void inline write_u32(uint32_t x)
{
op_ptr = _write_leb_u32(op_ptr, x);
}
static void inline cs_write_u32(uint32_t x)
{
cs_ptr = _write_leb_u32(cs_ptr, x);
}

View file

@ -0,0 +1,192 @@
#pragma once
#include<stdint.h>
#include "util.h"
static Writer op;
extern Writer cs;
static void write_type_section()
{
write_raw_u8(&op, SC_TYPE);
uint8_t* ptr_section_size = op.ptr;
write_raw_u8(&op, 0);
write_raw_u8(&op, 6); // number of type descriptors
// FN0
write_raw_u8(&op, TYPE_FUNC);
write_raw_u8(&op, 0); // no args
write_raw_u8(&op, 0); // no return val
// FN1
write_raw_u8(&op, TYPE_FUNC);
write_raw_u8(&op, 1);
write_raw_u8(&op, TYPE_I32);
write_raw_u8(&op, 0);
// FN2
write_raw_u8(&op, TYPE_FUNC);
write_raw_u8(&op, 2);
write_raw_u8(&op, TYPE_I32);
write_raw_u8(&op, TYPE_I32);
write_raw_u8(&op, 0);
// FN0_RET
write_raw_u8(&op, TYPE_FUNC);
write_raw_u8(&op, 0);
write_raw_u8(&op, 1);
write_raw_u8(&op, TYPE_I32);
// FN1_RET
write_raw_u8(&op, TYPE_FUNC);
write_raw_u8(&op, 1);
write_raw_u8(&op, TYPE_I32);
write_raw_u8(&op, 1);
write_raw_u8(&op, TYPE_I32);
// FN2_RET
write_raw_u8(&op, TYPE_FUNC);
write_raw_u8(&op, 2);
write_raw_u8(&op, TYPE_I32);
write_raw_u8(&op, TYPE_I32);
write_raw_u8(&op, 1);
write_raw_u8(&op, TYPE_I32);
*ptr_section_size = (op.ptr - 1) - ptr_section_size;
}
// Import table
static uint8_t* ptr_import_count = (uint8_t*) 0;
static uint8_t* ptr_import_entries = (uint8_t*) 0;
static uint8_t* ptr_import_table_size = (uint8_t*) 0;
// The import table size is written in leb encoding, which we can't read by simple dereferencing so
// we store the actual value separately. This is needed since we reserve two bytes for the import
// table size as it can exceed 127
// Default value is one as the section starts with containing one byte for the import count
static uint32_t import_table_size = 1;
// Goes over the import block to find index of an import entry by function name
// Returns -1 if not found
static int32_t get_import_index(char* fn, uint8_t fn_len)
{
uint8_t* offset = ptr_import_entries;
for(int32_t i = 0; i < *ptr_import_count; i++)
{
offset += 1; // skip length of module name
offset += 1; // skip module name itself
uint8_t len = *offset++;
char* name = (char*) offset;
if (len == fn_len && strncmp(name, fn, fn_len) == 0)
{
return i;
}
offset += len; // skip the string
offset += 1; // skip import kind
offset += 1; // skip type index
}
return -1;
}
static void set_import_table_size(uint16_t size)
{
import_table_size = size;
write_fixed_leb16_to_ptr(ptr_import_table_size, size);
}
static void write_import_section_preamble()
{
write_raw_u8(&op, SC_IMPORT);
ptr_import_table_size = op.ptr; // store current pointer location to write into later on
write_raw_u8(&op, 1 | 0b10000000); write_raw_u8(&op, 0); // 1 in 2 byte leb
// same as above but for count of entries
ptr_import_count = op.ptr;
write_raw_u8(&op, 0);
// here after starts the actual list of imports
ptr_import_entries = op.ptr;
}
static void write_memory_import()
{
write_raw_u8(&op, 1);
write_raw_u8(&op, 'e');
write_raw_u8(&op, 1);
write_raw_u8(&op, 'm');
write_raw_u8(&op, EXT_MEMORY);
write_raw_u8(&op, 0); // memory flag, 0 for no maximum memory limit present
write_leb_u32(&op, 256); // initial memory length of 256 pages, takes 2 bytes in leb128
*ptr_import_count += 1;
set_import_table_size(import_table_size + 1 + 1 + 1 + 1 + 1 + 1 + 2);
}
static uint8_t write_import_entry(char* fn_name, uint8_t fn_name_len, uint8_t type_index)
{
write_raw_u8(&op, 1); // length of module name
write_raw_u8(&op, 'e'); // module name
write_raw_u8(&op, fn_name_len);
for (uint8_t i = 0; i < fn_name_len; i++)
{
write_raw_u8(&op, fn_name[i]);
}
write_raw_u8(&op, EXT_FUNCTION);
write_raw_u8(&op, type_index);
*ptr_import_count += 1;
set_import_table_size(import_table_size + 1 + 1 + 1 + fn_name_len + 1 + 1);
return *ptr_import_count - 1;
}
static void write_function_section()
{
write_raw_u8(&op, SC_FUNCTION);
write_raw_u8(&op, 2); // length of this section
write_raw_u8(&op, 1); // count of signature indices
write_raw_u8(&op, FN0_TYPE_INDEX); // we export one function which is nullary
}
static void write_export_section()
{
write_raw_u8(&op, SC_EXPORT);
write_raw_u8(&op, 1 + 1 + 1 + 1 + 1); // size of this section
write_raw_u8(&op, 1); // count of table: just one function exported
write_raw_u8(&op, 1); // length of exported function name
write_raw_u8(&op, 'f'); // function name
write_raw_u8(&op, EXT_FUNCTION);
// index of the exported function
// function space starts with imports. index of last import is import count - 1
// the last import however is a memory, so we subtract one from that
write_raw_u8(&op, *ptr_import_count - 1);
}
int32_t get_fn_index(char* fn, uint8_t fn_len, uint8_t type_index)
{
int32_t fn_idx = get_import_index(fn, fn_len);
if (fn_idx == -1)
{
return write_import_entry(fn, fn_len, type_index);
}
return fn_idx;
}
static void copy_code_section()
{
uint8_t* offset = cs.start;
while (offset < cs.ptr)
{
write_raw_u8(&op, *offset++);
}
}

View file

@ -8,21 +8,13 @@
#define dbg_assert(condition) { if(DEBUG) { if(!(condition)) dbg_log(#condition); assert(condition); } }
#define dbg_assert_message(condition, message) { if(DEBUG && !(condition)) { dbg_log(message); assert(false); } }
static uint8_t* _write_leb_u32(uint8_t* ptr, uint32_t v)
{
do {
uint8_t byte = v & 0b1111111; // get last 7 bits
v >>= 7; // shift them away from the value
if (v != 0)
{
byte |= 0b10000000; // turn on MSB
}
*ptr++ = byte;
} while (v != 0);
return ptr;
}
typedef struct Writer {
uint8_t* const start;
uint8_t* ptr;
uint32_t const len;
} Writer;
static uint8_t* _write_leb_i32(uint8_t* ptr, int32_t v)
static void write_leb_i32(Writer* writer, int32_t v)
{
// Super complex stuff. See the following:
// https://en.wikipedia.org/wiki/LEB128#Encode_signed_integer
@ -48,9 +40,26 @@ static uint8_t* _write_leb_i32(uint8_t* ptr, int32_t v)
{
byte |= 0b10000000; // turn on MSB
}
*ptr++ = byte;
*(writer->ptr)++ = byte;
}
return ptr;
}
static void write_leb_u32(Writer* writer, uint32_t v)
{
do {
uint8_t byte = v & 0b1111111; // get last 7 bits
v >>= 7; // shift them away from the value
if (v != 0)
{
byte |= 0b10000000; // turn on MSB
}
*(writer->ptr)++ = byte;
} while (v != 0);
}
static void inline write_raw_u8(Writer* writer, uint8_t v)
{
*(writer->ptr)++ = v;
}
static void inline write_fixed_leb16_to_ptr(uint8_t* ptr, uint16_t x)
@ -60,3 +69,14 @@ static void inline write_fixed_leb16_to_ptr(uint8_t* ptr, uint16_t x)
*(ptr + 1) = x >> 7;
}
/*123456789012345678901234567890123456789012345678901234567890123456789012345
0 @@@@@@@@ @@@@@@@@@ @@ @ @@@@@@@@@ @@@@@@@ @ @ 0
0 @ @ @ @ @ @ @ @ @ 0
0 @ @ @ @ @ @ @ @ @ 0
0 @@@@@@ @ @ @ @ @ @ @@@@@@@ 0
0 @ @ @ @ @ @ @ @ @ 0
0 @ @ @ @ @ @ @ @ @ 0
0 @ @ @ @ @ @ @ @ @ 0
0 @ @@@@@@@@@ @ @@ @@@@@@@@@ @@@@@@@ @ @ 0
123456789012345678901234567890123456789012345678901234567890123456789012345*/

View file

@ -3,69 +3,69 @@
#include <stdint.h>
#include "wasm_opcodes.h"
#include "codegen_util.h"
#include "util.h"
static void inline push_i32(int32_t v)
static void inline push_i32(Writer* w, int32_t v)
{
cs_write_u8(OP_I32CONST);
cs_write_i32(v);
write_raw_u8(w, OP_I32CONST);
write_leb_i32(w, v);
}
static void inline push_u32(uint32_t v)
static void inline push_u32(Writer* w, uint32_t v)
{
cs_write_u8(OP_I32CONST);
cs_write_u32(v);
write_raw_u8(w, OP_I32CONST);
write_leb_u32(w, v);
}
static void inline load_u16(uint32_t addr)
static void inline load_u16(Writer* w, uint32_t addr)
{
cs_write_u8(OP_I32CONST);
cs_write_u32(addr);
cs_write_u8(OP_I32LOAD16U);
cs_write_u8(MEM_IMM_ALIGNMENT);
cs_write_u8(MEM_IMM_OFFSET);
write_raw_u8(w, OP_I32CONST);
write_leb_u32(w, addr);
write_raw_u8(w, OP_I32LOAD16U);
write_raw_u8(w, MEM_IMM_ALIGNMENT);
write_raw_u8(w, MEM_IMM_OFFSET);
}
static void inline load_i32(uint32_t addr)
static void inline load_i32(Writer* w, uint32_t addr)
{
cs_write_u8(OP_I32CONST);
cs_write_u32(addr);
cs_write_u8(OP_I32LOAD);
cs_write_u8(MEM_IMM_ALIGNMENT);
cs_write_u8(MEM_IMM_OFFSET);
write_raw_u8(w, OP_I32CONST);
write_leb_u32(w, addr);
write_raw_u8(w, OP_I32LOAD);
write_raw_u8(w, MEM_IMM_ALIGNMENT);
write_raw_u8(w, MEM_IMM_OFFSET);
}
static void inline store_i32()
static void inline store_i32(Writer* w)
{
cs_write_u8(OP_I32STORE);
cs_write_u8(MEM_IMM_ALIGNMENT);
cs_write_u8(MEM_IMM_OFFSET);
write_raw_u8(w, OP_I32STORE);
write_raw_u8(w, MEM_IMM_ALIGNMENT);
write_raw_u8(w, MEM_IMM_OFFSET);
}
static void inline add_i32()
static void inline add_i32(Writer* w)
{
cs_write_u8(OP_I32ADD);
write_raw_u8(w, OP_I32ADD);
}
static void inline and_i32()
static void inline and_i32(Writer* w)
{
cs_write_u8(OP_I32AND);
write_raw_u8(w, OP_I32AND);
}
static void inline shl_i32()
static void inline shl_i32(Writer* w)
{
cs_write_u8(OP_I32SHL);
write_raw_u8(w, OP_I32SHL);
}
static void inline call_fn(uint8_t fn_idx)
static void inline call_fn(Writer* w, uint8_t fn_idx)
{
cs_write_u8(OP_CALL);
cs_write_u8(fn_idx);
write_raw_u8(w, OP_CALL);
write_raw_u8(w, fn_idx);
}
static void inline call_fn_with_arg(uint8_t fn_idx, int32_t arg0)
static void inline call_fn_with_arg(Writer* w, uint8_t fn_idx, int32_t arg0)
{
push_i32(arg0);
call_fn(fn_idx);
push_i32(w, arg0);
call_fn(w, fn_idx);
}