authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-01-17 22:34:13+01:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-01-19 20:01:23+01:00
log28acbdb02ff934fed3363a580128575e7d8c92ee
treefb9e5e49d24353c714754333b6083f88d247daaf
parent9615d7aee7fa0478ad01e4054b620213b73278e1
signaturelock-open Commit is signed but in an unrecognized format.

wasm-linker: Allow for creation of local symbols

The backend can create annonymous local symbols. This can be used for constants that will be passed by reference so it will not have to be lowered to the stack, and then stored into the data section. This also means it's valid to return a pointer to a constant array. Those local symbols that are created, will be managed by the parent decl. Free'ing the parent decl, will also free all of its locals. When a local symbol was created, the index of said symbol will be returned and saved in the `memory` tag of a `WValue` which is then memoized. This means that each 'emit' of this WValue will create a relocation for that constant/symbol and the actual pointer value will be set after relocation phase.

1 files changed, 58 insertions(+), 12 deletions(-)

src/link/Wasm.zig+58-12
......@@ -19,7 +19,7 @@ const trace = @import("../tracy.zig").trace;
1919const build_options = @import("build_options");
2020const wasi_libc = @import("../wasi_libc.zig");
2121const Cache = @import("../Cache.zig");
22const TypedValue = @import("../TypedValue.zig");
22const Type = @import("../type.zig").Type;
2323const LlvmObject = @import("../codegen/llvm.zig").Object;
2424const Air = @import("../Air.zig");
2525const Liveness = @import("../Liveness.zig");
......@@ -306,9 +306,41 @@ fn finishUpdateDecl(self: *Wasm, decl: *Module.Decl, result: CodeGen.Result, cod
306306 if (code.len == 0) return;
307307 const atom: *Atom = &decl.link.wasm;
308308 atom.size = @intCast(u32, code.len);
309 atom.alignment = decl.ty.abiAlignment(self.base.options.target);
310 self.symbols.items[atom.sym_index].name = decl.name;
309311 try atom.code.appendSlice(self.base.allocator, code);
310312}
311313
314/// Creates a new local symbol for a given type (and its bytes it's represented by)
315/// and then append it as a 'contained' atom onto the Decl.
316pub fn createLocalSymbol(self: *Wasm, decl: *Module.Decl, ty: Type, code: []const u8) !u32 {
317 assert(ty.zigTypeTag() != .Fn); // cannot create local symbols for functions
318 var symbol: Symbol = .{
319 .name = "unnamed_local",
320 .flags = 0,
321 .tag = .data,
322 .index = undefined,
323 };
324 symbol.setFlag(.WASM_SYM_BINDING_LOCAL);
325 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
326
327 var atom = Atom.empty;
328 atom.size = @intCast(u32, code.len);
329 atom.alignment = ty.abiAlignment(self.base.options.target);
330 try atom.code.appendSlice(self.base.allocator, code);
331
332 if (self.symbols_free_list.popOrNull()) |index| {
333 atom.sym_index = index;
334 self.symbols.items[index] = symbol;
335 } else {
336 atom.sym_index = @intCast(u32, self.symbols.items.len);
337 self.symbols.appendAssumeCapacity(symbol);
338 }
339
340 try decl.link.wasm.locals.append(self.base.allocator, atom);
341 return atom.sym_index;
342}
343
312344pub fn updateDeclExports(
313345 self: *Wasm,
314346 module: *Module,
......@@ -329,9 +361,12 @@ pub fn freeDecl(self: *Wasm, decl: *Module.Decl) void {
329361 }
330362 const atom = &decl.link.wasm;
331363 self.symbols_free_list.append(self.base.allocator, atom.sym_index) catch {};
332 atom.deinit(self.base.allocator);
333364 _ = self.decls.remove(decl);
334365 self.symbols.items[atom.sym_index].tag = .dead; // to ensure it does not end in the names section
366 for (atom.locals.items) |local_atom| {
367 self.symbols.items[local_atom.sym_index].tag = .dead; // also for any local symbol
368 }
369 atom.deinit(self.base.allocator);
335370
336371 if (decl.isExtern()) {
337372 const import = self.imports.fetchRemove(decl.link.wasm.sym_index).?.value;
......@@ -377,14 +412,16 @@ fn addOrUpdateImport(self: *Wasm, decl: *Module.Decl) !void {
377412 }
378413}
379414
380fn parseDeclIntoAtom(self: *Wasm, decl: *Module.Decl) !void {
381 const atom: *Atom = &decl.link.wasm;
415const Kind = union(enum) {
416 data: void,
417 function: FnData,
418};
419
420/// Parses an Atom and inserts its metadata into the corresponding sections.
421fn parseAtom(self: *Wasm, atom: *Atom, kind: Kind) !void {
382422 const symbol: *Symbol = &self.symbols.items[atom.sym_index];
383 symbol.name = decl.name;
384 atom.alignment = decl.ty.abiAlignment(self.base.options.target);
385 const final_index: u32 = switch (decl.ty.zigTypeTag()) {
386 .Fn => result: {
387 const fn_data = decl.fn_link.wasm;
423 const final_index: u32 = switch (kind) {
424 .function => |fn_data| result: {
388425 const type_index = fn_data.type_index;
389426 const index = @intCast(u32, self.functions.items.len + self.imported_functions_count);
390427 try self.functions.append(self.base.allocator, .{ .type_index = type_index });
......@@ -402,7 +439,7 @@ fn parseDeclIntoAtom(self: *Wasm, decl: *Module.Decl) !void {
402439
403440 break :result self.code_section_index.?;
404441 },
405 else => result: {
442 .data => result: {
406443 const gop = try self.data_segments.getOrPut(self.base.allocator, ".rodata");
407444 const atom_index = if (gop.found_existing) blk: {
408445 self.segments.items[gop.value_ptr.*].size += atom.size;
......@@ -430,7 +467,6 @@ fn parseDeclIntoAtom(self: *Wasm, decl: *Module.Decl) !void {
430467 });
431468 symbol.tag = .data;
432469 symbol.index = info_index;
433 atom.alignment = decl.ty.abiAlignment(self.base.options.target);
434470
435471 break :result atom_index;
436472 },
......@@ -617,7 +653,17 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
617653 var decl_it = self.decls.keyIterator();
618654 while (decl_it.next()) |decl| {
619655 if (decl.*.isExtern()) continue;
620 try self.parseDeclIntoAtom(decl.*);
656 const atom = &decl.*.link.wasm;
657 if (decl.*.ty.zigTypeTag() == .Fn) {
658 try self.parseAtom(atom, .{ .function = decl.*.fn_link.wasm });
659 } else {
660 try self.parseAtom(atom, .data);
661 }
662
663 // also parse atoms for a decl's locals
664 for (atom.locals.items) |*local_atom| {
665 try self.parseAtom(local_atom, .data);
666 }
621667 }
622668
623669 try self.setupMemory();