authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2021-04-04 20:31:35+02:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2021-04-08 22:47:08+02:00
log47f36427887fc7d1646cfb7ed8eeeeb14cd3555b
tree50e8bcf29dce6e4128a53df3fcf6cf9fc51a8f39
parent9fd1dab58230edae11e2798f30ec43704a0c2178
signaturelock-open Commit is signed but in an unrecognized format.

Cleanup


2 files changed, 35 insertions(+), 34 deletions(-)

src/codegen/wasm.zig+5-5
...@@ -622,9 +622,9 @@ pub const Context = struct {...@@ -622,9 +622,9 @@ pub const Context = struct {
622 // Write instructions622 // Write instructions
623 // TODO: check for and handle death of instructions623 // TODO: check for and handle death of instructions
624 const mod_fn = blk: {624 const mod_fn = blk: {
625 if (tv.val.castTag(.function)) |func| break :blk func.data;625 if (typed_value.val.castTag(.function)) |func| break :blk func.data;
626 if (tv.val.castTag(.extern_fn)) |ext_fn| return Result.appended; // don't need code body for extern functions626 if (typed_value.val.castTag(.extern_fn)) |ext_fn| return Result.appended; // don't need code body for extern functions
627 return self.fail(.{ .node_offset = 0 }, "TODO: Wasm codegen for decl type '{s}'", .{tv.ty.tag()});627 return self.fail(.{ .node_offset = 0 }, "TODO: Wasm codegen for decl type '{s}'", .{typed_value.ty.tag()});
628 };628 };
629629
630 // Reserve space to write the size after generating the code as well as space for locals count630 // Reserve space to write the size after generating the code as well as space for locals count
...@@ -686,9 +686,9 @@ pub const Context = struct {...@@ -686,9 +686,9 @@ pub const Context = struct {
686 try self.code.append(@intCast(u8, int_byte));686 try self.code.append(@intCast(u8, int_byte));
687 return Result.appended;687 return Result.appended;
688 }688 }
689 return self.fail(self.decl.src(), "TODO: Implement codegen for int type: '{}'", .{typed_value.ty});689 return self.fail(.{ .node_offset = 0 }, "TODO: Implement codegen for int type: '{}'", .{typed_value.ty});
690 },690 },
691 else => |tag| return self.fail(self.decl.src(), "TODO: Implement zig type codegen for type: '{s}'", .{tag}),691 else => |tag| return self.fail(.{ .node_offset = 0 }, "TODO: Implement zig type codegen for type: '{s}'", .{tag}),
692 }692 }
693 }693 }
694694
src/link/Wasm.zig+30-29
...@@ -38,8 +38,11 @@ pub const DataSection = struct {...@@ -38,8 +38,11 @@ pub const DataSection = struct {
38 /// Every data object will be appended to this list,38 /// Every data object will be appended to this list,
39 /// containing its `Decl`, the data in bytes, and its length.39 /// containing its `Decl`, the data in bytes, and its length.
40 segments: std.ArrayListUnmanaged(struct {40 segments: std.ArrayListUnmanaged(struct {
41 /// The decl that lives inside the 'data' section such as an array
41 decl: *Module.Decl,42 decl: *Module.Decl,
43 /// The contents of the data in bytes
42 data: [*]const u8,44 data: [*]const u8,
45 /// The length of the contents inside the 'data' section
43 len: u32,46 len: u32,
44 }) = .{},47 }) = .{},
4548
...@@ -72,7 +75,7 @@ pub const DataSection = struct {...@@ -72,7 +75,7 @@ pub const DataSection = struct {
72 }75 }
7376
74 /// Returns the index of a declaration and `null` when not found77 /// Returns the index of a declaration and `null` when not found
75 pub fn idx(self: DataSection, decl: *Module.Decl) ?usize {78 pub fn getIdx(self: DataSection, decl: *Module.Decl) ?usize {
76 return for (self.segments.items) |entry, i| {79 return for (self.segments.items) |entry, i| {
77 if (entry.decl == decl) break i;80 if (entry.decl == decl) break i;
78 } else null;81 } else null;
...@@ -145,9 +148,8 @@ pub fn deinit(self: *Wasm) void {...@@ -145,9 +148,8 @@ pub fn deinit(self: *Wasm) void {
145 decl.fn_link.wasm.idx_refs.deinit(self.base.allocator);148 decl.fn_link.wasm.idx_refs.deinit(self.base.allocator);
146 }149 }
147 for (self.data.segments.items) |entry| {150 for (self.data.segments.items) |entry| {
148 entry.decl.fn_link.wasm.functype.deinit(self.base.allocator);151 // decl's that live in data section do not generate idx_refs or func types
149 entry.decl.fn_link.wasm.code.deinit(self.base.allocator);152 entry.decl.fn_link.wasm.code.deinit(self.base.allocator);
150 entry.decl.fn_link.wasm.idx_refs.deinit(self.base.allocator);
151 }153 }
152 self.funcs.deinit(self.base.allocator);154 self.funcs.deinit(self.base.allocator);
153 self.ext_funcs.deinit(self.base.allocator);155 self.ext_funcs.deinit(self.base.allocator);
...@@ -155,15 +157,14 @@ pub fn deinit(self: *Wasm) void {...@@ -155,15 +157,14 @@ pub fn deinit(self: *Wasm) void {
155}157}
156158
157pub fn allocateDeclIndexes(self: *Wasm, decl: *Module.Decl) !void {159pub fn allocateDeclIndexes(self: *Wasm, decl: *Module.Decl) !void {
158 const tv = decl.typed_value.most_recent.typed_value;160 const typed_value = decl.typed_value.most_recent.typed_value;
159 decl.fn_link.wasm = .{};
160161
161 switch (tv.ty.zigTypeTag()) {162 switch (typed_value.ty.zigTypeTag()) {
162 .Array => {163 .Array => {
163 // if the codegen of the given decl contributes to the data segment164 // if the codegen of the given decl contributes to the data segment
164 // we must calculate its data length now so that the data offsets are available165 // we must calculate its data length now so that the data offsets are available
165 // to other decls when called166 // to other decls when called
166 const data_len = calcDataLen(self, tv) catch return error.AnalysisFail;167 const data_len = self.calcDataLen(typed_value);
167 try self.data.segments.append(self.base.allocator, .{168 try self.data.segments.append(self.base.allocator, .{
168 .decl = decl,169 .decl = decl,
169 .data = undefined,170 .data = undefined,
...@@ -175,13 +176,18 @@ pub fn allocateDeclIndexes(self: *Wasm, decl: *Module.Decl) !void {...@@ -175,13 +176,18 @@ pub fn allocateDeclIndexes(self: *Wasm, decl: *Module.Decl) !void {
175 const idx: ?usize = for (self.data.segments.items) |entry, i| {176 const idx: ?usize = for (self.data.segments.items) |entry, i| {
176 if (entry.decl.deletion_flag) break i;177 if (entry.decl.deletion_flag) break i;
177 } else null;178 } else null;
179
178 if (idx) |id| {180 if (idx) |id| {
179 const old_decl = self.data.segments.swapRemove(id); // current decl is now in to-be-deleted decl's spot181 // swap to-be-removed decl with newly added to create a contigious valid data segment
180 // re-append to end of list so it can be cleaned up by `freeDecl`182 const items = self.data.segments.items;
181 try self.data.segments.append(self.base.allocator, old_decl);183 std.mem.swap(
184 std.meta.Child(@TypeOf(items)),
185 &items[id],
186 &items[items.len - 1],
187 );
182 }188 }
183 },189 },
184 .Fn => if (self.getFuncidx(decl) == null) switch (tv.val.tag()) {190 .Fn => if (self.getFuncidx(decl) == null) switch (typed_value.val.tag()) {
185 // dependent on function type, appends it to the correct list191 // dependent on function type, appends it to the correct list
186 .function => try self.funcs.append(self.base.allocator, decl),192 .function => try self.funcs.append(self.base.allocator, decl),
187 .extern_fn => try self.ext_funcs.append(self.base.allocator, decl),193 .extern_fn => try self.ext_funcs.append(self.base.allocator, decl),
...@@ -191,32 +197,26 @@ pub fn allocateDeclIndexes(self: *Wasm, decl: *Module.Decl) !void {...@@ -191,32 +197,26 @@ pub fn allocateDeclIndexes(self: *Wasm, decl: *Module.Decl) !void {
191 }197 }
192}198}
193199
194// TODO, remove this and use the existing error mechanism
195const DataLenError = error{
196 TODO_WASM_CalcDataLenArray,
197 TODO_WASM_CalcDataLen,
198};
199/// Calculates the length of the data segment that will be occupied by the given `TypedValue`200/// Calculates the length of the data segment that will be occupied by the given `TypedValue`
200fn calcDataLen(bin_file: *Wasm, typed_value: TypedValue) DataLenError!u32 {201fn calcDataLen(self: *Wasm, typed_value: TypedValue) u32 {
201 switch (typed_value.ty.zigTypeTag()) {202 switch (typed_value.ty.zigTypeTag()) {
202 .Array => {203 .Array => {
203 if (typed_value.val.castTag(.bytes)) |payload| {204 if (typed_value.val.castTag(.bytes)) |payload| {
204 if (typed_value.ty.sentinel()) |sentinel| {205 if (typed_value.ty.sentinel()) |sentinel| {
205 return @intCast(u32, payload.data.len) + try calcDataLen(bin_file, .{206 return @intCast(u32, payload.data.len) + self.calcDataLen(.{
206 .ty = typed_value.ty.elemType(),207 .ty = typed_value.ty.elemType(),
207 .val = sentinel,208 .val = sentinel,
208 });209 });
209 }210 }
210 return @intCast(u32, payload.data.len);
211 }211 }
212 return error.TODO_WASM_CalcDataLenArray;212 return @intCast(u32, typed_value.ty.arrayLen());
213 },213 },
214 .Int => {214 .Int => {
215 const info = typed_value.ty.intInfo(bin_file.base.options.target);215 const info = typed_value.ty.intInfo(self.base.options.target);
216 return info.bits / 8;216 return std.math.divCeil(u32, info.bits, 8) catch unreachable;
217 },217 },
218 .Pointer => return 4,218 .Pointer => return 4,
219 else => return error.TODO_WASM_CalcDataLen,219 else => unreachable,
220 }220 }
221}221}
222222
...@@ -256,7 +256,7 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {...@@ -256,7 +256,7 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {
256 .Fn => {256 .Fn => {
257 // as locals are patched afterwards, the offsets of funcidx's are off,257 // as locals are patched afterwards, the offsets of funcidx's are off,
258 // here we update them to correct them258 // here we update them to correct them
259 for (decl.fn_link.wasm.idx_refs.items) |*func| {259 for (fn_data.idx_refs.items) |*func| {
260 // For each local, add 6 bytes (count + type)260 // For each local, add 6 bytes (count + type)
261 func.offset += @intCast(u32, context.locals.items.len * 6);261 func.offset += @intCast(u32, context.locals.items.len * 6);
262 }262 }
...@@ -291,7 +291,7 @@ pub fn freeDecl(self: *Wasm, decl: *Module.Decl) void {...@@ -291,7 +291,7 @@ pub fn freeDecl(self: *Wasm, decl: *Module.Decl) void {
291 else => unreachable,291 else => unreachable,
292 }292 }
293 }293 }
294 if (self.data.idx(decl)) |idx| {294 if (self.data.getIdx(decl)) |idx| {
295 _ = self.data.segments.swapRemove(idx);295 _ = self.data.segments.swapRemove(idx);
296 }296 }
297 decl.fn_link.wasm.functype.deinit(self.base.allocator);297 decl.fn_link.wasm.functype.deinit(self.base.allocator);
...@@ -314,6 +314,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {...@@ -314,6 +314,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
314314
315 const file = self.base.file.?;315 const file = self.base.file.?;
316 const header_size = 5 + 1;316 const header_size = 5 + 1;
317 const data_size = self.data.size();
317318
318 // No need to rewrite the magic/version header319 // No need to rewrite the magic/version header
319 try file.setEndPos(@sizeOf(@TypeOf(wasm.magic ++ wasm.version)));320 try file.setEndPos(@sizeOf(@TypeOf(wasm.magic ++ wasm.version)));
...@@ -384,7 +385,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {...@@ -384,7 +385,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
384 }385 }
385386
386 // Memory section387 // Memory section
387 if (self.data.size() != 0) {388 if (data_size != 0) {
388 const header_offset = try reserveVecSectionHeader(file);389 const header_offset = try reserveVecSectionHeader(file);
389 const writer = file.writer();390 const writer = file.writer();
390391
...@@ -434,7 +435,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {...@@ -434,7 +435,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
434 }435 }
435436
436 // export memory if size is not 0437 // export memory if size is not 0
437 if (self.data.size() != 0) {438 if (data_size != 0) {
438 try leb.writeULEB128(writer, @intCast(u32, "memory".len));439 try leb.writeULEB128(writer, @intCast(u32, "memory".len));
439 try writer.writeAll("memory");440 try writer.writeAll("memory");
440 try writer.writeByte(wasm.externalKind(.memory));441 try writer.writeByte(wasm.externalKind(.memory));
...@@ -483,7 +484,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {...@@ -483,7 +484,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
483 }484 }
484485
485 // Data section486 // Data section
486 if (self.data.size() != 0) {487 if (data_size != 0) {
487 const header_offset = try reserveVecSectionHeader(file);488 const header_offset = try reserveVecSectionHeader(file);
488 const writer = file.writer();489 const writer = file.writer();
489 var len: u32 = 0;490 var len: u32 = 0;
...@@ -496,7 +497,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {...@@ -496,7 +497,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
496 try writer.writeByte(wasm.opcode(.end));497 try writer.writeByte(wasm.opcode(.end));
497498
498 // payload size499 // payload size
499 try leb.writeULEB128(writer, self.data.size());500 try leb.writeULEB128(writer, data_size);
500501
501 // write payload502 // write payload
502 for (self.data.segments.items) |entry| try writer.writeAll(entry.data[0..entry.len]);503 for (self.data.segments.items) |entry| try writer.writeAll(entry.data[0..entry.len]);