diff options
| author | Hanjie Wu <hanjiew@andrew.cmu.edu> | 2022-12-08 17:45:55 -0500 |
|---|---|---|
| committer | Hanjie Wu <hanjiew@andrew.cmu.edu> | 2022-12-08 17:45:55 -0500 |
| commit | a054755b62e660d3d8aba42fdb0a992e2d215599 (patch) | |
| tree | 5f2e793527f75240800b31025f4c4c1f58be23ab /weerun_parse.cpp | |
JIT implementation
Diffstat (limited to 'weerun_parse.cpp')
| -rw-r--r-- | weerun_parse.cpp | 394 |
1 files changed, 394 insertions, 0 deletions
diff --git a/weerun_parse.cpp b/weerun_parse.cpp new file mode 100644 index 0000000..2e2a5df --- /dev/null +++ b/weerun_parse.cpp @@ -0,0 +1,394 @@ +#include <algorithm> +#include <csignal> +#include <cstdlib> +#include <cstring> +#include <vector> + +#include "weerun.hpp" +#include "weerun_jit.hpp" + +template <typename T> +T decode(buffer_t* buf); + +template <typename T> +std::vector<T> decode_vector(buffer_t* buf); + +void parse_custom_section(wasm_module_t* module, buffer_t* buf); +void parse_type_section(wasm_module_t* module, buffer_t* buf); +void parse_import_section(wasm_module_t* module, buffer_t* buf); +void parse_function_section(wasm_module_t* module, buffer_t* buf); +void parse_table_section(wasm_module_t* module, buffer_t* buf); +void parse_memory_section(wasm_module_t* module, buffer_t* buf); +void parse_global_section(wasm_module_t* module, buffer_t* buf); +void parse_export_section(wasm_module_t* module, buffer_t* buf); +void parse_start_section(wasm_module_t* module, buffer_t* buf); +void parse_element_section(wasm_module_t* module, buffer_t* buf); +void parse_code_section(wasm_module_t* module, buffer_t* buf); +void parse_data_section(wasm_module_t* module, buffer_t* buf); + +extern "C" wasm_module_t* parse(buffer_t* buf) { + buf->ptr += 8; // magic and version + wasm_module_t* module = new wasm_module_t(); + module->num_import_funcs_ = 0; + module->have_start_ = false; + while (buf->ptr != buf->end) { + byte type = read_u8(buf); + switch (type) { + case 0: + parse_custom_section(module, buf); + break; + case WASM_SECT_TYPE: + parse_type_section(module, buf); + break; + case WASM_SECT_IMPORT: + parse_import_section(module, buf); + break; + case WASM_SECT_FUNCTION: + parse_function_section(module, buf); + break; + case WASM_SECT_TABLE: + parse_table_section(module, buf); + break; + case WASM_SECT_MEMORY: + parse_memory_section(module, buf); + break; + case WASM_SECT_GLOBAL: + parse_global_section(module, buf); + break; + case WASM_SECT_EXPORT: + parse_export_section(module, buf); + break; + case WASM_SECT_START: + parse_start_section(module, buf); + break; + case WASM_SECT_ELEMENT: + parse_element_section(module, buf); + break; + case WASM_SECT_CODE: + parse_code_section(module, buf); + break; + case WASM_SECT_DATA: + parse_data_section(module, buf); + break; + default: + assert(0); + } + } + return module; +} + +wasm_instance_t* active_instance; +uint32_t jit = 1; + +extern "C" wasm_typed_value_t run(const byte* start, + const byte* end, + uint32_t num_args, + wasm_value_t* args) { + buffer_t onstack_buf = {start, start, end}; + wasm_module_t* module = parse(&onstack_buf); + wasm_instance_t* instance = module->create_instance(); + wasm_value_t result; + if (jit != 0) { + result = + instance->run_jit(std::vector<wasm_value_t>(args, args + num_args)); + } else { + result = instance->run(std::vector<wasm_value_t>(args, args + num_args)); + } + wasm_typed_value_t tr = {module->funcs_[module->main_index_].sig_->ret_[0], + result}; + delete instance; + delete module; + return tr; +} + +void parse_custom_section(wasm_module_t* module, buffer_t* buf) { + (void)module; + uint32_t size = read_u32leb(buf); + const byte* section_end = buf->ptr + size; + std::string name = decode<std::string>(buf); + buf->ptr = section_end; + return; +} + +void parse_type_section(wasm_module_t* module, buffer_t* buf) { + read_u32leb(buf); + module->sigs_ = decode_vector<wasm_func_decl_t>(buf); +} + +void parse_import_section(wasm_module_t* module, buffer_t* buf) { + read_u32leb(buf); + std::vector<wasm_import_decl_t> imports = + decode_vector<wasm_import_decl_t>(buf); + // create imported functions + for (wasm_import_decl_t& imp : imports) { + switch (imp.type_) { + case wasm_import_decl_t::type::FUNCTION: { + std::string name = imp.module_ + "." + imp.name_; + auto result = g_runtime_funcs.find(name); + if (result == g_runtime_funcs.end()) { + std::cout << "error: " << name << " cannot be imported"; + throw std::runtime_error(name + " not found"); + } + wasm_func_t f; + f.sig_ = &module->sigs_[imp.funcindex_]; + f.typeid_ = imp.funcindex_; + f.run_ = result->second.run_; + f.run_jit_ = result->second.run_jit_; + module->funcs_.push_back(f); + module->num_import_funcs_++; + break; + } + default: + break; + } + } +} + +void parse_function_section(wasm_module_t* module, buffer_t* buf) { + read_u32leb(buf); + std::vector<uint32_t> funcidxs = decode_vector<uint32_t>(buf); + // create function objects + for (uint32_t func : funcidxs) { + wasm_func_t f; + f.sig_ = &module->sigs_[func]; + f.typeid_ = func; + f.run_ = nullptr; + module->funcs_.push_back(f); + } +} + +void parse_table_section(wasm_module_t* module, buffer_t* buf) { + read_u32leb(buf); + std::vector<wasm_table_decl_t> tables = decode_vector<wasm_table_decl_t>(buf); + module->table_ = tables[0]; +} + +void parse_memory_section(wasm_module_t* module, buffer_t* buf) { + read_u32leb(buf); + std::vector<wasm_memory_decl_t> memories = + decode_vector<wasm_memory_decl_t>(buf); + module->mem_limits_ = memories[0]; +} + +void parse_global_section(wasm_module_t* module, buffer_t* buf) { + read_u32leb(buf); + module->globals_ = decode_vector<wasm_global_t>(buf); +} + +void parse_export_section(wasm_module_t* module, buffer_t* buf) { + read_u32leb(buf); + std::vector<wasm_export_t> exps = decode_vector<wasm_export_t>(buf); + // we assume that the module only exports a main function + module->main_index_ = exps[0].idx_; +} + +void parse_start_section(wasm_module_t* module, buffer_t* buf) { + read_u32leb(buf); + module->have_start_ = true; + module->start_index_ = read_u32leb(buf); +} + +void parse_element_section(wasm_module_t* module, buffer_t* buf) { + read_u32leb(buf); + module->elems_ = decode_vector<wasm_elem_decl_t>(buf); +} + +std::vector<wasm_code_decl_t> decode_vector_code_decl(buffer_t* buf, + wasm_module_t* module); + +void parse_code_section(wasm_module_t* module, buffer_t* buf) { + read_u32leb(buf); + std::vector<wasm_code_decl_t> codes = decode_vector_code_decl(buf, module); + // start from the first non-imported functions + uint32_t funcidx = module->num_import_funcs_; + for (wasm_code_decl_t& code : codes) { + module->funcs_[funcidx].locals_ = code.locals_; + module->funcs_[funcidx].code_ = code.code_; + funcidx++; + } +} + +void parse_data_section(wasm_module_t* module, buffer_t* buf) { + read_u32leb(buf); + module->datas_ = decode_vector<wasm_data_decl_t>(buf); +} + +wasm_instance_t* wasm_module_t::create_instance() { + wasm_instance_t* instance = new wasm_instance_t(); + instance->module_ = this; + + // initialize memory using data + instance->memory_.resize(mem_limits_.init_ * wasm_page_size, 0); + for (wasm_data_decl_t& data : datas_) { + byte* mem = instance->memory_.data(); + std::memcpy(mem + data.offset_, data.data_.data(), data.data_.size()); + } + + // initialize global variables + instance->globals_.resize(globals_.size()); + for (uint32_t i = 0; i < globals_.size(); i++) { + switch (globals_[i].type_.type_) { + case WASM_TYPE_I32: + instance->globals_[i].val.i32 = globals_[i].val_.i32; + break; + case WASM_TYPE_F64: + instance->globals_[i].val.f64 = globals_[i].val_.f64; + break; + default: + instance->globals_[i].val.ref = globals_[i].val_.ref; + break; + } + } + + // initialize table + instance->table_.resize(table_.init_, nullptr); + for (wasm_elem_decl_t& elem : elems_) { + instance->ensure_table(elem.offset_ + elem.funcidx_.size()); + wasm_func_t** p = &instance->table_[elem.offset_]; + for (uint32_t funcidx : elem.funcidx_) { + *p = &funcs_[funcidx]; + p++; + } + } + instance->jit_table_.resize(instance->table_.size(), {-1, nullptr}); + return instance; +} + +void wasm_instance_t::push_value(wasm_value_t v) { + value_stack_.push_back(v); +} + +wasm_value_t wasm_instance_t::pop_value() { + wasm_value_t result = value_stack_.back(); + value_stack_.pop_back(); + return result; +} + +void wasm_instance_t::branch(uint32_t to_off) { + cur_frame_->pc_.ptr = cur_frame_->pc_.start + to_off; +} + +void wasm_instance_t::push_frame(wasm_func_t* f) { + if (f->run_ != nullptr) { + // runtime functions + f->run_(this); + return; + } + + // create a frame for function f + wasm_stack_frame_t frame; + frame.f_ = f; + + // locals contains arguments and f's own locals + uint32_t num_args = f->sig_->args_.size(); + frame.locals_.resize(num_args); + // move argument from stack + for (int i = num_args - 1; i >= 0; i--) { + frame.locals_[i] = pop_value(); + } + // initialize locals + for (wasm_local_decl_t& local : f->locals_) { + wasm_value_t v; + switch (local.type_) { + case WASM_TYPE_I32: + v.val.i32 = 0; + break; + case WASM_TYPE_F64: + v.val.f64 = 0; + break; + case WASM_TYPE_EXTERNREF: + v.val.ref = nullptr; + } + for (uint32_t i = 0; i < local.count_; i++) { + frame.locals_.push_back(v); + } + } + + // set pc to the start of function bytecode + frame.pc_.start = frame.pc_.ptr = f->code_.data(); + frame.pc_.end = frame.pc_.start + f->code_.size(); + frames_.push_back(frame); + + // update current frame + cur_frame_ = &frames_.back(); +} + +void wasm_instance_t::pop_frame() { + // pop the from when a funtcion reaches the end + frames_.pop_back(); + cur_frame_ = &frames_.back(); +} + +wasm_value_t wasm_instance_t::run(std::vector<wasm_value_t> args) { + if (module_->have_start_ == true) { + run_function(module_->start_index_); + } + // create the frame for main() + for (wasm_value_t& v : args) { + value_stack_.push_back(v); + } + active_instance = this; + run_function(module_->main_index_); + // return the value on stack; + return value_stack_.back(); +} + +wasm_value_t wasm_instance_t::run_jit(std::vector<wasm_value_t> args) { + wasm_jit_t jit(1 << 20); // 1M code size + jit.compile_instance(this); + + active_instance = this; + if (module_->have_start_ == true) { + jit.run_fn(module_->start_index_, nullptr, nullptr); + } + wasm_value_t r; + jit.run_fn(module_->main_index_, args.data(), &r); + return r; +} + +void wasm_instance_t::run_function(uint32_t funcidx) { + trapped = WASM_TRAP_REASON_NOTRAP; + push_frame(&module_->funcs_[funcidx]); + + // start interpretation + while (trapped == WASM_TRAP_REASON_NOTRAP) { + byte opcode = read_u8(&cur_frame_->pc_); + const wasm_inst_desc_t* desc = &g_inst_desc[opcode]; + desc->run(this, opcode); + } + + if (trapped != WASM_TRAP_REASON_FUNCEND) { + std::cout << "!trap" << std::endl; + std::exit(0); + } +} + +void wasm_instance_t::trap(uint32_t reason) { + trapped = reason; +} + +uint32_t wasm_instance_t::read_u32leb() { + return ::read_u32leb(&cur_frame_->pc_); +} + +int32_t wasm_instance_t::read_i32leb() { + return ::read_i32leb(&cur_frame_->pc_); +} + +double wasm_instance_t::read_double() { + double result = *(double*)(cur_frame_->pc_.ptr); + cur_frame_->pc_.ptr += sizeof(double); + return result; +} + +byte wasm_instance_t::read_byte() { + byte result = *(byte*)(cur_frame_->pc_.ptr); + cur_frame_->pc_.ptr += sizeof(byte); + return result; +} + +void wasm_instance_t::ensure_table(uint32_t offset) { + if (table_.size() < offset) { + table_.resize(offset, nullptr); + } +} |
