lib/choir/src/backends/wasm/emission/module/root.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const std = @import("std");
2 const wasm = @import("../../root.zig");
3 const emission = @import("../root.zig");
4 const section = @import("section/root.zig");
5
6 pub const common = @import("common.zig");
7
8 pub fn preparePlan(
9 plan: *emission.Plan,
10 module: *common.ir.Operation,
11 options: emission.Options,
12 frames: []emission.function.Frame,
13 ) emission.Error!usize {
14 _ = try common.moduleOperation(module);
15 if (options.entry) |entry| {
16 if (plan.functionIndex(entry) == null) return error.FunctionNotFound;
17 }
18
19 try section.code.prepareBodies(plan, module, frames);
20 plan.sections.type = try section.type_section.countBody(plan, module);
21 if (plan.importCount() > 0) {
22 plan.sections.import = try section.import_section.countBody(plan, module);
23 }
24 if (plan.definitionCount() > 0) {
25 plan.sections.function = try section.function_section.countBody(plan, module);
26 plan.sections.code = try section.code.countBody(plan, module);
27 }
28 if (plan.needsMemory()) {
29 plan.sections.memory = try section.memory.countBody();
30 }
31 if (try section.export_section.entryCount(module, options, plan.needsMemory()) > 0) {
32 plan.sections.export_ = try section.export_section.countBody(plan, module, options);
33 }
34 return moduleByteSize(plan);
35 }
36
37 pub fn write(
38 out: anytype,
39 plan: *const emission.Plan,
40 module: *common.ir.Operation,
41 options: emission.Options,
42 frames: []emission.function.Frame,
43 ) emission.Error!void {
44 _ = try common.moduleOperation(module);
45 try wasm.binary.writeHeader(out);
46 try section.type_section.write(out, plan, module);
47 if (plan.importCount() > 0) {
48 try section.import_section.write(out, plan, module);
49 }
50 if (plan.definitionCount() > 0) {
51 try section.function_section.write(out, plan, module);
52 }
53 if (plan.needsMemory()) {
54 try section.memory.write(out, plan);
55 }
56 if (plan.sections.export_ > 0) {
57 try section.export_section.write(out, plan, module, options);
58 }
59 if (plan.definitionCount() > 0) {
60 try section.code.write(out, plan, module, frames);
61 }
62 }
63
64 fn moduleByteSize(plan: *const emission.Plan) emission.Error!usize {
65 var count = wasm.binary.Count{};
66 try wasm.binary.writeHeader(&count);
67 try addSectionSize(&count, .type, plan.sections.type);
68 if (plan.importCount() > 0) {
69 try addSectionSize(&count, .import, plan.sections.import);
70 }
71 if (plan.definitionCount() > 0) {
72 try addSectionSize(&count, .function, plan.sections.function);
73 }
74 if (plan.needsMemory()) {
75 try addSectionSize(&count, .memory, plan.sections.memory);
76 }
77 if (plan.sections.export_ > 0) {
78 try addSectionSize(&count, .export_, plan.sections.export_);
79 }
80 if (plan.definitionCount() > 0) {
81 try addSectionSize(&count, .code, plan.sections.code);
82 }
83 return count.len;
84 }
85
86 fn addSectionSize(
87 count: *wasm.binary.Count,
88 section_id: wasm.binary.Section,
89 body_bytes: usize,
90 ) emission.Error!void {
91 try common.writeSectionHeader(count, section_id, body_bytes);
92 count.len = std.math.add(usize, count.len, body_bytes) catch
93 return error.CapacityOverflow;
94 }