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;...@@ -19,7 +19,7 @@ const trace = @import("../tracy.zig").trace;
19const build_options = @import("build_options");19const build_options = @import("build_options");
20const wasi_libc = @import("../wasi_libc.zig");20const wasi_libc = @import("../wasi_libc.zig");
21const Cache = @import("../Cache.zig");21const Cache = @import("../Cache.zig");
22const TypedValue = @import("../TypedValue.zig");22const Type = @import("../type.zig").Type;
23const LlvmObject = @import("../codegen/llvm.zig").Object;23const LlvmObject = @import("../codegen/llvm.zig").Object;
24const Air = @import("../Air.zig");24const Air = @import("../Air.zig");
25const Liveness = @import("../Liveness.zig");25const Liveness = @import("../Liveness.zig");
...@@ -306,9 +306,41 @@ fn finishUpdateDecl(self: *Wasm, decl: *Module.Decl, result: CodeGen.Result, cod...@@ -306,9 +306,41 @@ fn finishUpdateDecl(self: *Wasm, decl: *Module.Decl, result: CodeGen.Result, cod
306 if (code.len == 0) return;306 if (code.len == 0) return;
307 const atom: *Atom = &decl.link.wasm;307 const atom: *Atom = &decl.link.wasm;
308 atom.size = @intCast(u32, code.len);308 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;
309 try atom.code.appendSlice(self.base.allocator, code);311 try atom.code.appendSlice(self.base.allocator, code);
310}312}
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
312pub fn updateDeclExports(344pub fn updateDeclExports(
313 self: *Wasm,345 self: *Wasm,
314 module: *Module,346 module: *Module,
...@@ -329,9 +361,12 @@ pub fn freeDecl(self: *Wasm, decl: *Module.Decl) void {...@@ -329,9 +361,12 @@ pub fn freeDecl(self: *Wasm, decl: *Module.Decl) void {
329 }361 }
330 const atom = &decl.link.wasm;362 const atom = &decl.link.wasm;
331 self.symbols_free_list.append(self.base.allocator, atom.sym_index) catch {};363 self.symbols_free_list.append(self.base.allocator, atom.sym_index) catch {};
332 atom.deinit(self.base.allocator);
333 _ = self.decls.remove(decl);364 _ = self.decls.remove(decl);
334 self.symbols.items[atom.sym_index].tag = .dead; // to ensure it does not end in the names section365 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
336 if (decl.isExtern()) {371 if (decl.isExtern()) {
337 const import = self.imports.fetchRemove(decl.link.wasm.sym_index).?.value;372 const import = self.imports.fetchRemove(decl.link.wasm.sym_index).?.value;
...@@ -377,14 +412,16 @@ fn addOrUpdateImport(self: *Wasm, decl: *Module.Decl) !void {...@@ -377,14 +412,16 @@ fn addOrUpdateImport(self: *Wasm, decl: *Module.Decl) !void {
377 }412 }
378}413}
379414
380fn parseDeclIntoAtom(self: *Wasm, decl: *Module.Decl) !void {415const Kind = union(enum) {
381 const atom: *Atom = &decl.link.wasm;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 {
382 const symbol: *Symbol = &self.symbols.items[atom.sym_index];422 const symbol: *Symbol = &self.symbols.items[atom.sym_index];
383 symbol.name = decl.name;423 const final_index: u32 = switch (kind) {
384 atom.alignment = decl.ty.abiAlignment(self.base.options.target);424 .function => |fn_data| result: {
385 const final_index: u32 = switch (decl.ty.zigTypeTag()) {
386 .Fn => result: {
387 const fn_data = decl.fn_link.wasm;
388 const type_index = fn_data.type_index;425 const type_index = fn_data.type_index;
389 const index = @intCast(u32, self.functions.items.len + self.imported_functions_count);426 const index = @intCast(u32, self.functions.items.len + self.imported_functions_count);
390 try self.functions.append(self.base.allocator, .{ .type_index = type_index });427 try self.functions.append(self.base.allocator, .{ .type_index = type_index });
...@@ -402,7 +439,7 @@ fn parseDeclIntoAtom(self: *Wasm, decl: *Module.Decl) !void {...@@ -402,7 +439,7 @@ fn parseDeclIntoAtom(self: *Wasm, decl: *Module.Decl) !void {
402439
403 break :result self.code_section_index.?;440 break :result self.code_section_index.?;
404 },441 },
405 else => result: {442 .data => result: {
406 const gop = try self.data_segments.getOrPut(self.base.allocator, ".rodata");443 const gop = try self.data_segments.getOrPut(self.base.allocator, ".rodata");
407 const atom_index = if (gop.found_existing) blk: {444 const atom_index = if (gop.found_existing) blk: {
408 self.segments.items[gop.value_ptr.*].size += atom.size;445 self.segments.items[gop.value_ptr.*].size += atom.size;
...@@ -430,7 +467,6 @@ fn parseDeclIntoAtom(self: *Wasm, decl: *Module.Decl) !void {...@@ -430,7 +467,6 @@ fn parseDeclIntoAtom(self: *Wasm, decl: *Module.Decl) !void {
430 });467 });
431 symbol.tag = .data;468 symbol.tag = .data;
432 symbol.index = info_index;469 symbol.index = info_index;
433 atom.alignment = decl.ty.abiAlignment(self.base.options.target);
434470
435 break :result atom_index;471 break :result atom_index;
436 },472 },
...@@ -617,7 +653,17 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {...@@ -617,7 +653,17 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
617 var decl_it = self.decls.keyIterator();653 var decl_it = self.decls.keyIterator();
618 while (decl_it.next()) |decl| {654 while (decl_it.next()) |decl| {
619 if (decl.*.isExtern()) continue;655 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 }
621 }667 }
622668
623 try self.setupMemory();669 try self.setupMemory();