From b6fdabc874ca6cd7bb90378a539f34cc7547f5be Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 17 Jun 2026 13:42:26 +0100 Subject: [PATCH] Parse `custom` sections `target_features` and `name` --- core/rexcode/wasm/module/module.odin | 53 +++++++++++++++ core/rexcode/wasm/module/parse.odin | 96 ++++++++++++++++++++++++++++ core/rexcode/wasm/module/print.odin | 44 +++++++++++-- 3 files changed, 188 insertions(+), 5 deletions(-) diff --git a/core/rexcode/wasm/module/module.odin b/core/rexcode/wasm/module/module.odin index a12ab48d9..a9706ee74 100644 --- a/core/rexcode/wasm/module/module.odin +++ b/core/rexcode/wasm/module/module.odin @@ -90,6 +90,7 @@ Function :: struct { Module :: struct { version: u32, sections: []Section, + customs: []Custom_Section, types: []Func_Type, imports: []Import, functions: []Function, // whole function index space (imports + defined) @@ -101,6 +102,58 @@ Module :: struct { allocator: runtime.Allocator, } + + +// ----------------------------------------------------------------------------- +// Custom Section Layout +// ----------------------------------------------------------------------------- + +Custom_Section :: struct { + section: Section, + variant: union { + Custom_Section_Name, + Custom_Section_Target_Features, + }, +} + +Custom_Section_Name_Function :: struct { + id: u32, + name: string, // borrowed +} + +Custom_Section_Name_Local :: struct { + idx: u32, + name: string, // borrowed +} + +Custom_Section_Name_Function_Locals :: struct { + func_idx: u32, + locals: []Custom_Section_Name_Local, +} + +Custom_Section_Name :: struct { + module_name: string, + functions: []Custom_Section_Name_Function, + locals: []Custom_Section_Name_Function_Locals, +} + +Custom_Section_Target_Feature_Prefix :: enum u8 { + Used = '+', + Disallowed = '-', + Required = '=', +} + +Custom_Section_Target_Feature :: struct { + prefix: Custom_Section_Target_Feature_Prefix, + feature: string, // borrowed +} + + +Custom_Section_Target_Features :: struct { + features: []Custom_Section_Target_Feature, +} + + // ----------------------------------------------------------------------------- // Small display helpers // ----------------------------------------------------------------------------- diff --git a/core/rexcode/wasm/module/parse.odin b/core/rexcode/wasm/module/parse.odin index 44dfc3f89..b4cd4ae99 100644 --- a/core/rexcode/wasm/module/parse.odin +++ b/core/rexcode/wasm/module/parse.odin @@ -191,6 +191,9 @@ parse :: proc(data: []u8, allocator := context.allocator) -> (m: Module, err: Re } } + parse_custom_sections(&m, allocator) or_return + + build_functions(&m, func_typeidx, codes, allocator) or_return apply_name_section(&m) return @@ -289,6 +292,86 @@ parse_code :: proc(r: ^Reader, allocator: runtime.Allocator) -> (out: []Code_Bod return } +@(require_results) +parse_custom_sections :: proc(m: ^Module, allocator: runtime.Allocator) -> Reader_Error { + custom_count := 0 + for &sec in m.sections { + if sec.id == .CUSTOM { + custom_count += 1 + } + } + m.customs = make([]Custom_Section, custom_count, allocator) or_return + custom_index := 0 + for &sec in m.sections { + if sec.id != .CUSTOM { + continue + } + + custom := &m.customs[custom_index] + custom_index += 1 + + custom.section = sec + + section_data := m.data[sec.offset:][:sec.size] + r := reader(section_data, 0) + sec_name := rd_name(&r) or_continue + assert(sec_name == sec.name) + + custom_block: switch sec.name { + case "name": + cname: Custom_Section_Name + defer custom.variant = cname + + for r.off < u32(len(r.data)) { + id := rd_byte(&r) or_return + size := rd_u32(&r) or_return + end_off := r.off+size + defer r.off = end_off + + switch id { + case 0: // module + cname.module_name = rd_name(&r) or_return + case 1: // functions + count := rd_u32(&r) or_return + cname.functions = make([]Custom_Section_Name_Function, count, allocator) or_return + for &func in cname.functions { + func.id = rd_u32(&r) or_return + func.name = rd_name(&r) or_return + } + case 2: // locals + count := rd_u32(&r) or_return + + cname.locals = make([]Custom_Section_Name_Function_Locals, count, allocator) or_return + + for &local_func in cname.locals { + local_func.func_idx = rd_u32(&r) or_return + local_count := rd_u32(&r) or_return + local_func.locals = make([]Custom_Section_Name_Local, local_count, allocator) or_return + for &local in local_func.locals { + local.idx = rd_u32(&r) or_return + local.name = rd_name(&r) or_return + } + } + } + } + + case "target_features": + target_features: Custom_Section_Target_Features + defer custom.variant = target_features + + count := rd_u32(&r) or_return + target_features.features = make([]Custom_Section_Target_Feature, count, allocator) or_return + + for &feature in target_features.features { + feature.prefix = Custom_Section_Target_Feature_Prefix(rd_byte(&r) or_return) + feature.feature = rd_name(&r) or_return + } + } + } + + return nil +} + @(require_results) build_functions :: proc(m: ^Module, func_typeidx: []u32, codes: []Code_Body, allocator: runtime.Allocator) -> runtime.Allocator_Error { num_imports := 0 @@ -393,6 +476,19 @@ module_destroy :: proc(m: ^Module) { delete(f.locals, m.allocator) } } + for c in m.customs { + switch v in c.variant { + case Custom_Section_Name: + for function_locals in v.locals { + delete(function_locals.locals, m.allocator) + } + delete(v.functions, m.allocator) + delete(v.locals, m.allocator) + case Custom_Section_Target_Features: + delete(v.features) + } + } + delete(m.customs, m.allocator) delete(m.sections, m.allocator) delete(m.types, m.allocator) delete(m.imports, m.allocator) diff --git a/core/rexcode/wasm/module/print.odin b/core/rexcode/wasm/module/print.odin index 0d9ee5055..59d7b5da8 100644 --- a/core/rexcode/wasm/module/print.odin +++ b/core/rexcode/wasm/module/print.odin @@ -5,12 +5,12 @@ import "core:os" import "core:fmt" import wasm "../" -print_module :: proc(m: Module) { +print_module :: proc(m: Module, file: ^os.File) { sb := strings.builder_make(context.allocator) defer strings.builder_destroy(&sb) sbprint_module(&sb, m) s := strings.to_string(sb) - os.write_string(os.stdout, s) + os.write_string(file, s) } sbprint_module :: proc(sb: ^strings.Builder, m: Module) { @@ -69,11 +69,45 @@ sbprint_module :: proc(sb: ^strings.Builder, m: Module) { } strings.write_byte(sb, '\n') - data := m.data[sec.offset:][:sec.size] + section_data := m.data[sec.offset:][:sec.size] section_printing: #partial switch sec.id { + case .CUSTOM: + for c in m.customs { + if c.section != sec { + continue + } + switch v in c.variant { + case Custom_Section_Name: + if v.module_name != "" { + fmt.sbprintf(sb, " module: %q\n", v.module_name) + } + if len(v.functions) > 0 { + fmt.sbprintf(sb, " functions:\n") + for f in v.functions { + fmt.sbprintf(sb, " [%d] %q\n", f.id, f.name) + } + } + if len(v.locals) > 0 { + fmt.sbprintf(sb, " locals:\n") + for fl in v.locals { + fmt.sbprintf(sb, " [%d] function\n", fl.func_idx) + for local in fl.locals { + fmt.sbprintf(sb, " [%d] %q\n", local.idx, local.name) + } + } + } + case Custom_Section_Target_Features: + for f in v.features { + fmt.sbprintf(sb, " \"%c%s\"\n", u8(f.prefix), f.feature) + } + } + break + } + strings.write_byte(sb, '\n') + case .DATA: - r := reader(data, 0) + r := reader(section_data, 0) count := rd_u32(&r) or_break section_printing assert(count == sec.count) for i in 0..