| ... | @@ -0,0 +1,998 @@ |
| 1 | //! ZigObject encapsulates the state of the incrementally compiled Zig module. |
| 2 | //! It stores the associated input local and global symbols, allocated atoms, |
| 3 | //! and any relocations that may have been emitted. |
| 4 | //! Think about this as fake in-memory Object file for the Zig module. |
| 5 | |
| 6 | /// List of all `Decl` that are currently alive. |
| 7 | /// Each index maps to the corresponding `Atom.Index`. |
| 8 | decls: std.AutoHashMapUnmanaged(InternPool.DeclIndex, Atom.Index) = .{}, |
| 9 | /// List of function type signatures for this Zig module. |
| 10 | func_types: std.ArrayListUnmanaged(std.wasm.Type) = .{}, |
| 11 | /// Map of symbol locations, represented by its `types.Import`. |
| 12 | imports: std.AutoHashMapUnmanaged(u32, types.Import) = .{}, |
| 13 | /// List of WebAssembly globals. |
| 14 | globals: std.ArrayListUnmanaged(std.wasm.Global) = .{}, |
| 15 | /// Mapping between an `Atom` and its type index representing the Wasm |
| 16 | /// type of the function signature. |
| 17 | atom_types: std.AutoHashMapUnmanaged(Atom.Index, u32) = .{}, |
| 18 | /// List of all symbols generated by Zig code. |
| 19 | symbols: std.ArrayListUnmanaged(Symbol) = .{}, |
| 20 | /// Map from symbol name offset to their index into the `symbols` list. |
| 21 | global_syms: std.AutoHashMapUnmanaged(u32, u32) = .{}, |
| 22 | /// List of symbol indexes which are free to be used. |
| 23 | symbols_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 24 | /// Extra metadata about the linking section, such as alignment of segments and their name. |
| 25 | segment_info: std.ArrayListUnmanage(types.Segment) = &.{}, |
| 26 | /// File encapsulated string table, used to deduplicate strings within the generated file. |
| 27 | string_table: StringTable = .{}, |
| 28 | /// Map for storing anonymous declarations. Each anonymous decl maps to its Atom's index. |
| 29 | anon_decls: std.AutoArrayHashMapUnmanaged(InternPool.Index, Atom.Index) = .{}, |
| 30 | /// Represents the symbol index of the error name table |
| 31 | /// When this is `null`, no code references an error using runtime `@errorName`. |
| 32 | /// During initializion, a symbol with corresponding atom will be created that is |
| 33 | /// used to perform relocations to the pointer of this table. |
| 34 | /// The actual table is populated during `flush`. |
| 35 | error_table_symbol: ?u32 = null, |
| 36 | /// Amount of functions in the `import` sections. |
| 37 | imported_functions_count: u32 = 0, |
| 38 | /// Amount of globals in the `import` section. |
| 39 | imported_globals_count: u32 = 0, |
| 40 | /// Symbol index representing the stack pointer. This will be set upon initializion |
| 41 | /// of a new `ZigObject`. Codegen will make calls into this to create relocations for |
| 42 | /// this symbol each time the stack pointer is moved. |
| 43 | stack_pointer_sym: u32, |
| 44 | |
| 45 | /// Frees and invalidates all memory of the incrementally compiled Zig module. |
| 46 | /// It is illegal behavior to access the `ZigObject` after calling `deinit`. |
| 47 | pub fn deinit(zig_object: *ZigObject, gpa: std.mem.Allocator) void { |
| 48 | for (zig_object.segment_info.values()) |segment_info| { |
| 49 | gpa.free(segment_info.name); |
| 50 | } |
| 51 | |
| 52 | // For decls and anon decls we free the memory of its atoms. |
| 53 | // The memory of atoms parsed from object files is managed by |
| 54 | // the object file itself, and therefore we can skip those. |
| 55 | { |
| 56 | var it = zig_object.decls.valueIterator(); |
| 57 | while (it.next()) |atom_index_ptr| { |
| 58 | const atom = zig_object.getAtomPtr(atom_index_ptr.*); |
| 59 | for (atom.locals.items) |local_index| { |
| 60 | const local_atom = zig_object.getAtomPtr(local_index); |
| 61 | local_atom.deinit(gpa); |
| 62 | } |
| 63 | atom.deinit(gpa); |
| 64 | } |
| 65 | } |
| 66 | { |
| 67 | for (zig_object.anon_decls.values()) |atom_index| { |
| 68 | const atom = zig_object.getAtomPtr(atom_index); |
| 69 | for (atom.locals.items) |local_index| { |
| 70 | const local_atom = zig_object.getAtomPtr(local_index); |
| 71 | local_atom.deinit(gpa); |
| 72 | } |
| 73 | atom.deinit(gpa); |
| 74 | } |
| 75 | } |
| 76 | zig_object.decls.deinit(gpa); |
| 77 | zig_object.anon_decls.deinit(gpa); |
| 78 | zig_object.symbols.deinit(gpa); |
| 79 | zig_object.symbols_free_list.deinit(gpa); |
| 80 | zig_object.segment_info.deinit(gpa); |
| 81 | |
| 82 | zig_object.string_table.deinit(gpa); |
| 83 | zig_object.* = undefined; |
| 84 | } |
| 85 | |
| 86 | /// Allocates a new symbol and returns its index. |
| 87 | /// Will re-use slots when a symbol was freed at an earlier stage. |
| 88 | pub fn allocateSymbol(zig_object: *ZigObject, gpa: std.mem.Allocator) !u32 { |
| 89 | try zig_object.symbols.ensureUnusedCapacity(gpa, 1); |
| 90 | const symbol: Symbol = .{ |
| 91 | .name = std.math.maxInt(u32), // will be set after updateDecl as well as during atom creation for decls |
| 92 | .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL), |
| 93 | .tag = .undefined, // will be set after updateDecl |
| 94 | .index = std.math.maxInt(u32), // will be set during atom parsing |
| 95 | .virtual_address = std.math.maxInt(u32), // will be set during atom allocation |
| 96 | }; |
| 97 | if (zig_object.symbols_free_list.popOrNull()) |index| { |
| 98 | zig_object.symbols.items[index] = symbol; |
| 99 | return index; |
| 100 | } |
| 101 | const index = @as(u32, @intCast(zig_object.symbols.items.len)); |
| 102 | zig_object.symbols.appendAssumeCapacity(symbol); |
| 103 | return index; |
| 104 | } |
| 105 | |
| 106 | // Generate code for the Decl, storing it in memory to be later written to |
| 107 | // the file on flush(). |
| 108 | pub fn updateDecl(zig_object: *ZigObject, wasm_file: *Wasm, mod: *Module, decl_index: InternPool.DeclIndex) !void { |
| 109 | const decl = mod.declPtr(decl_index); |
| 110 | if (decl.val.getFunction(mod)) |_| { |
| 111 | return; |
| 112 | } else if (decl.val.getExternFunc(mod)) |_| { |
| 113 | return; |
| 114 | } |
| 115 | |
| 116 | const gpa = wasm_file.base.comp.gpa; |
| 117 | const atom_index = try zig_object.getOrCreateAtomForDecl(decl_index); |
| 118 | const atom = wasm_file.getAtomPtr(atom_index); |
| 119 | atom.clear(); |
| 120 | |
| 121 | if (decl.isExtern(mod)) { |
| 122 | const variable = decl.getOwnedVariable(mod).?; |
| 123 | const name = mod.intern_pool.stringToSlice(decl.name); |
| 124 | const lib_name = mod.intern_pool.stringToSliceUnwrap(variable.lib_name); |
| 125 | return wasm_file.addOrUpdateImport(name, atom.sym_index, lib_name, null); |
| 126 | } |
| 127 | const val = if (decl.val.getVariable(mod)) |variable| Value.fromInterned(variable.init) else decl.val; |
| 128 | |
| 129 | var code_writer = std.ArrayList(u8).init(gpa); |
| 130 | defer code_writer.deinit(); |
| 131 | |
| 132 | const res = try codegen.generateSymbol( |
| 133 | &wasm_file.base, |
| 134 | decl.srcLoc(mod), |
| 135 | .{ .ty = decl.ty, .val = val }, |
| 136 | &code_writer, |
| 137 | .none, |
| 138 | .{ .parent_atom_index = atom.sym_index }, |
| 139 | ); |
| 140 | |
| 141 | const code = switch (res) { |
| 142 | .ok => code_writer.items, |
| 143 | .fail => |em| { |
| 144 | decl.analysis = .codegen_failure; |
| 145 | try mod.failed_decls.put(mod.gpa, decl_index, em); |
| 146 | return; |
| 147 | }, |
| 148 | }; |
| 149 | |
| 150 | return wasm_file.finishUpdateDecl(decl_index, code, .data); |
| 151 | } |
| 152 | |
| 153 | pub fn updateFunc(zig_object: *ZigObject, wasm_file: *Wasm, mod: *Module, func_index: InternPool.Index, air: Air, liveness: Liveness) !void { |
| 154 | const gpa = wasm_file.base.comp.gpa; |
| 155 | const func = mod.funcInfo(func_index); |
| 156 | const decl_index = func.owner_decl; |
| 157 | const decl = mod.declPtr(decl_index); |
| 158 | const atom_index = try zig_object.getOrCreateAtomForDecl(decl_index); |
| 159 | const atom = wasm_file.getAtomPtr(atom_index); |
| 160 | atom.clear(); |
| 161 | |
| 162 | var code_writer = std.ArrayList(u8).init(gpa); |
| 163 | defer code_writer.deinit(); |
| 164 | const result = try codegen.generateFunction( |
| 165 | &wasm_file.base, |
| 166 | decl.srcLoc(mod), |
| 167 | func_index, |
| 168 | air, |
| 169 | liveness, |
| 170 | &code_writer, |
| 171 | .none, |
| 172 | ); |
| 173 | |
| 174 | const code = switch (result) { |
| 175 | .ok => code_writer.items, |
| 176 | .fail => |em| { |
| 177 | decl.analysis = .codegen_failure; |
| 178 | try mod.failed_decls.put(mod.gpa, decl_index, em); |
| 179 | return; |
| 180 | }, |
| 181 | }; |
| 182 | |
| 183 | return zig_object.finishUpdateDecl(wasm_file, decl_index, code, .function); |
| 184 | } |
| 185 | |
| 186 | fn finishUpdateDecl(zig_object: *ZigObject, wasm_file: *Wasm, decl_index: InternPool.DeclIndex, code: []const u8, symbol_tag: Symbol.Tag) !void { |
| 187 | const gpa = wasm_file.base.comp.gpa; |
| 188 | const mod = wasm_file.base.comp.module.?; |
| 189 | const decl = mod.declPtr(decl_index); |
| 190 | const atom_index = zig_object.decls.get(decl_index).?; |
| 191 | const atom = wasm_file.getAtomPtr(atom_index); |
| 192 | const symbol = &zig_object.symbols.items[atom.sym_index]; |
| 193 | const full_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); |
| 194 | symbol.name = try zig_object.string_table.insert(gpa, full_name); |
| 195 | symbol.tag = symbol_tag; |
| 196 | try atom.code.appendSlice(gpa, code); |
| 197 | try wasm_file.resolved_symbols.put(gpa, atom.symbolLoc(), {}); |
| 198 | |
| 199 | atom.size = @intCast(code.len); |
| 200 | if (code.len == 0) return; |
| 201 | atom.alignment = decl.getAlignment(mod); |
| 202 | } |
| 203 | |
| 204 | /// For a given `InternPool.DeclIndex` returns its corresponding `Atom.Index`. |
| 205 | /// When the index was not found, a new `Atom` will be created, and its index will be returned. |
| 206 | /// The newly created Atom is empty with default fields as specified by `Atom.empty`. |
| 207 | pub fn getOrCreateAtomForDecl(zig_object: *ZigObject, wasm_file: *Wasm, decl_index: InternPool.DeclIndex) !Atom.Index { |
| 208 | const gpa = wasm_file.base.comp.gpa; |
| 209 | const gop = try zig_object.decls.getOrPut(gpa, decl_index); |
| 210 | if (!gop.found_existing) { |
| 211 | const atom_index = try wasm_file.createAtom(); |
| 212 | gop.value_ptr.* = atom_index; |
| 213 | const atom = wasm_file.getAtom(atom_index); |
| 214 | const symbol = atom.symbolLoc().getSymbol(wasm_file); |
| 215 | const mod = wasm_file.base.comp.module.?; |
| 216 | const decl = mod.declPtr(decl_index); |
| 217 | const full_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); |
| 218 | symbol.name = try wasm_file.string_table.insert(gpa, full_name); |
| 219 | } |
| 220 | return gop.value_ptr.*; |
| 221 | } |
| 222 | |
| 223 | pub fn lowerAnonDecl( |
| 224 | zig_object: *ZigObject, |
| 225 | wasm_file: *Wasm, |
| 226 | decl_val: InternPool.Index, |
| 227 | explicit_alignment: InternPool.Alignment, |
| 228 | src_loc: Module.SrcLoc, |
| 229 | ) !codegen.Result { |
| 230 | const gpa = wasm_file.base.comp.gpa; |
| 231 | const gop = try zig_object.anon_decls.getOrPut(gpa, decl_val); |
| 232 | if (!gop.found_existing) { |
| 233 | const mod = wasm_file.base.comp.module.?; |
| 234 | const ty = Type.fromInterned(mod.intern_pool.typeOf(decl_val)); |
| 235 | const tv: TypedValue = .{ .ty = ty, .val = Value.fromInterned(decl_val) }; |
| 236 | var name_buf: [32]u8 = undefined; |
| 237 | const name = std.fmt.bufPrint(&name_buf, "__anon_{d}", .{ |
| 238 | @intFromEnum(decl_val), |
| 239 | }) catch unreachable; |
| 240 | |
| 241 | switch (try zig_object.lowerConst(name, tv, src_loc)) { |
| 242 | .ok => |atom_index| zig_object.anon_decls.values()[gop.index] = atom_index, |
| 243 | .fail => |em| return .{ .fail = em }, |
| 244 | } |
| 245 | } |
| 246 | |
| 247 | const atom = wasm_file.getAtomPtr(zig_object.anon_decls.values()[gop.index]); |
| 248 | atom.alignment = switch (atom.alignment) { |
| 249 | .none => explicit_alignment, |
| 250 | else => switch (explicit_alignment) { |
| 251 | .none => atom.alignment, |
| 252 | else => atom.alignment.maxStrict(explicit_alignment), |
| 253 | }, |
| 254 | }; |
| 255 | return .ok; |
| 256 | } |
| 257 | |
| 258 | /// Lowers a constant typed value to a local symbol and atom. |
| 259 | /// Returns the symbol index of the local |
| 260 | /// The given `decl` is the parent decl whom owns the constant. |
| 261 | pub fn lowerUnnamedConst(zig_object: *ZigObject, wasm_file: *Wasm, tv: TypedValue, decl_index: InternPool.DeclIndex) !u32 { |
| 262 | const gpa = wasm_file.base.comp.gpa; |
| 263 | const mod = wasm_file.base.comp.module.?; |
| 264 | std.debug.assert(tv.ty.zigTypeTag(mod) != .Fn); // cannot create local symbols for functions |
| 265 | const decl = mod.declPtr(decl_index); |
| 266 | |
| 267 | const parent_atom_index = try zig_object.getOrCreateAtomForDecl(decl_index); |
| 268 | const parent_atom = wasm_file.getAtom(parent_atom_index); |
| 269 | const local_index = parent_atom.locals.items.len; |
| 270 | const fqn = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); |
| 271 | const name = try std.fmt.allocPrintZ(gpa, "__unnamed_{s}_{d}", .{ |
| 272 | fqn, local_index, |
| 273 | }); |
| 274 | defer gpa.free(name); |
| 275 | |
| 276 | switch (try zig_object.lowerConst(name, tv, decl.srcLoc(mod))) { |
| 277 | .ok => |atom_index| { |
| 278 | try wasm_file.getAtomPtr(parent_atom_index).locals.append(gpa, atom_index); |
| 279 | return wasm_file.getAtom(atom_index).getSymbolIndex().?; |
| 280 | }, |
| 281 | .fail => |em| { |
| 282 | decl.analysis = .codegen_failure; |
| 283 | try mod.failed_decls.put(mod.gpa, decl_index, em); |
| 284 | return error.CodegenFail; |
| 285 | }, |
| 286 | } |
| 287 | } |
| 288 | |
| 289 | const LowerConstResult = union(enum) { |
| 290 | ok: Atom.Index, |
| 291 | fail: *Module.ErrorMsg, |
| 292 | }; |
| 293 | |
| 294 | fn lowerConst(zig_object: *ZigObject, wasm_file: *Wasm, name: []const u8, tv: TypedValue, src_loc: Module.SrcLoc) !LowerConstResult { |
| 295 | const gpa = wasm_file.base.comp.gpa; |
| 296 | const mod = wasm_file.base.comp.module.?; |
| 297 | |
| 298 | // Create and initialize a new local symbol and atom |
| 299 | const atom_index = try wasm_file.createAtom(); |
| 300 | var value_bytes = std.ArrayList(u8).init(gpa); |
| 301 | defer value_bytes.deinit(); |
| 302 | |
| 303 | const code = code: { |
| 304 | const atom = wasm_file.getAtomPtr(atom_index); |
| 305 | atom.alignment = tv.ty.abiAlignment(mod); |
| 306 | zig_object.symbols.items[atom.sym_index] = .{ |
| 307 | .name = try zig_object.string_table.insert(gpa, name), |
| 308 | .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL), |
| 309 | .tag = .data, |
| 310 | .index = undefined, |
| 311 | .virtual_address = undefined, |
| 312 | }; |
| 313 | |
| 314 | const result = try codegen.generateSymbol( |
| 315 | &wasm_file.base, |
| 316 | src_loc, |
| 317 | tv, |
| 318 | &value_bytes, |
| 319 | .none, |
| 320 | .{ |
| 321 | .parent_atom_index = atom.sym_index, |
| 322 | .addend = null, |
| 323 | }, |
| 324 | ); |
| 325 | break :code switch (result) { |
| 326 | .ok => value_bytes.items, |
| 327 | .fail => |em| { |
| 328 | return .{ .fail = em }; |
| 329 | }, |
| 330 | }; |
| 331 | }; |
| 332 | |
| 333 | const atom = wasm_file.getAtomPtr(atom_index); |
| 334 | atom.size = @intCast(code.len); |
| 335 | try atom.code.appendSlice(gpa, code); |
| 336 | return .{ .ok = atom_index }; |
| 337 | } |
| 338 | |
| 339 | /// Returns the symbol index of the error name table. |
| 340 | /// |
| 341 | /// When the symbol does not yet exist, it will create a new one instead. |
| 342 | pub fn getErrorTableSymbol(zig_object: *ZigObject, wasm_file: *Wasm) !u32 { |
| 343 | if (zig_object.error_table_symbol) |symbol| { |
| 344 | return symbol; |
| 345 | } |
| 346 | |
| 347 | // no error was referenced yet, so create a new symbol and atom for it |
| 348 | // and then return said symbol's index. The final table will be populated |
| 349 | // during `flush` when we know all possible error names. |
| 350 | const gpa = wasm_file.base.gpa; |
| 351 | const sym_index = try zig_object.allocateSymbol(gpa); |
| 352 | const atom_index = try wasm_file.createAtom(sym_index); |
| 353 | const atom = wasm_file.getAtomPtr(atom_index); |
| 354 | const slice_ty = Type.slice_const_u8_sentinel_0; |
| 355 | const mod = wasm_file.base.comp.module.?; |
| 356 | atom.alignment = slice_ty.abiAlignment(mod); |
| 357 | |
| 358 | const sym_name = try zig_object.string_table.insert(gpa, "__zig_err_name_table"); |
| 359 | const symbol = &zig_object.symbols.items[sym_index]; |
| 360 | symbol.* = .{ |
| 361 | .name = sym_name, |
| 362 | .tag = .data, |
| 363 | .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL), |
| 364 | .index = 0, |
| 365 | .virtual_address = undefined, |
| 366 | }; |
| 367 | symbol.mark(); |
| 368 | |
| 369 | log.debug("Error name table was created with symbol index: ({d})", .{sym_index}); |
| 370 | zig_object.error_table_symbol = sym_index; |
| 371 | return sym_index; |
| 372 | } |
| 373 | |
| 374 | /// Populates the error name table, when `error_table_symbol` is not null. |
| 375 | /// |
| 376 | /// This creates a table that consists of pointers and length to each error name. |
| 377 | /// The table is what is being pointed to within the runtime bodies that are generated. |
| 378 | fn populateErrorNameTable(zig_object: *ZigObject, wasm_file: *Wasm) !void { |
| 379 | const symbol_index = zig_object.error_table_symbol orelse return; |
| 380 | const gpa = wasm_file.base.comp.gpa; |
| 381 | const atom_index = wasm_file.symbol_atom.get(.{ .file = null, .index = symbol_index }).?; |
| 382 | |
| 383 | // Rather than creating a symbol for each individual error name, |
| 384 | // we create a symbol for the entire region of error names. We then calculate |
| 385 | // the pointers into the list using addends which are appended to the relocation. |
| 386 | const names_sym_index = try zig_object.allocateSymbol(gpa); |
| 387 | const names_atom_index = try wasm_file.createAtom(names_sym_index); |
| 388 | const names_atom = wasm_file.getAtomPtr(names_atom_index); |
| 389 | names_atom.alignment = .@"1"; |
| 390 | const sym_name = try zig_object.string_table.insert(gpa, "__zig_err_names"); |
| 391 | const names_symbol = &zig_object.symbols.items[names_sym_index]; |
| 392 | names_symbol.* = .{ |
| 393 | .name = sym_name, |
| 394 | .tag = .data, |
| 395 | .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL), |
| 396 | .index = 0, |
| 397 | .virtual_address = undefined, |
| 398 | }; |
| 399 | names_symbol.mark(); |
| 400 | |
| 401 | log.debug("Populating error names", .{}); |
| 402 | |
| 403 | // Addend for each relocation to the table |
| 404 | var addend: u32 = 0; |
| 405 | const mod = wasm_file.base.comp.module.?; |
| 406 | for (mod.global_error_set.keys()) |error_name_nts| { |
| 407 | const atom = wasm_file.getAtomPtr(atom_index); |
| 408 | |
| 409 | const error_name = mod.intern_pool.stringToSlice(error_name_nts); |
| 410 | const len = @as(u32, @intCast(error_name.len + 1)); // names are 0-termianted |
| 411 | |
| 412 | const slice_ty = Type.slice_const_u8_sentinel_0; |
| 413 | const offset = @as(u32, @intCast(atom.code.items.len)); |
| 414 | // first we create the data for the slice of the name |
| 415 | try atom.code.appendNTimes(gpa, 0, 4); // ptr to name, will be relocated |
| 416 | try atom.code.writer(gpa).writeInt(u32, len - 1, .little); |
| 417 | // create relocation to the error name |
| 418 | try atom.relocs.append(gpa, .{ |
| 419 | .index = names_atom.sym_index, |
| 420 | .relocation_type = .R_WASM_MEMORY_ADDR_I32, |
| 421 | .offset = offset, |
| 422 | .addend = @as(i32, @intCast(addend)), |
| 423 | }); |
| 424 | atom.size += @as(u32, @intCast(slice_ty.abiSize(mod))); |
| 425 | addend += len; |
| 426 | |
| 427 | // as we updated the error name table, we now store the actual name within the names atom |
| 428 | try names_atom.code.ensureUnusedCapacity(gpa, len); |
| 429 | names_atom.code.appendSliceAssumeCapacity(error_name); |
| 430 | names_atom.code.appendAssumeCapacity(0); |
| 431 | |
| 432 | log.debug("Populated error name: '{s}'", .{error_name}); |
| 433 | } |
| 434 | names_atom.size = addend; |
| 435 | |
| 436 | // link the atoms with the rest of the binary so they can be allocated |
| 437 | // and relocations will be performed. |
| 438 | try wasm_file.parseAtom(atom_index, .{ .data = .read_only }); |
| 439 | try wasm_file.parseAtom(names_atom_index, .{ .data = .read_only }); |
| 440 | } |
| 441 | |
| 442 | /// Either creates a new import, or updates one if existing. |
| 443 | /// When `type_index` is non-null, we assume an external function. |
| 444 | /// In all other cases, a data-symbol will be created instead. |
| 445 | pub fn addOrUpdateImport( |
| 446 | zig_object: *ZigObject, |
| 447 | wasm_file: *Wasm, |
| 448 | /// Name of the import |
| 449 | name: []const u8, |
| 450 | /// Symbol index that is external |
| 451 | symbol_index: u32, |
| 452 | /// Optional library name (i.e. `extern "c" fn foo() void` |
| 453 | lib_name: ?[:0]const u8, |
| 454 | /// The index of the type that represents the function signature |
| 455 | /// when the extern is a function. When this is null, a data-symbol |
| 456 | /// is asserted instead. |
| 457 | type_index: ?u32, |
| 458 | ) !void { |
| 459 | const gpa = wasm_file.base.comp.gpa; |
| 460 | std.debug.assert(symbol_index != 0); |
| 461 | // For the import name, we use the decl's name, rather than the fully qualified name |
| 462 | // Also mangle the name when the lib name is set and not equal to "C" so imports with the same |
| 463 | // name but different module can be resolved correctly. |
| 464 | const mangle_name = lib_name != null and |
| 465 | !std.mem.eql(u8, lib_name.?, "c"); |
| 466 | const full_name = if (mangle_name) full_name: { |
| 467 | break :full_name try std.fmt.allocPrint(gpa, "{s}|{s}", .{ name, lib_name.? }); |
| 468 | } else name; |
| 469 | defer if (mangle_name) gpa.free(full_name); |
| 470 | |
| 471 | const decl_name_index = try zig_object.string_table.insert(gpa, full_name); |
| 472 | const symbol: *Symbol = &zig_object.symbols.items[symbol_index]; |
| 473 | symbol.setUndefined(true); |
| 474 | symbol.setGlobal(true); |
| 475 | symbol.name = decl_name_index; |
| 476 | if (mangle_name) { |
| 477 | // we specified a specific name for the symbol that does not match the import name |
| 478 | symbol.setFlag(.WASM_SYM_EXPLICIT_NAME); |
| 479 | } |
| 480 | |
| 481 | if (type_index) |ty_index| { |
| 482 | const gop = try zig_object.imports.getOrPut(gpa, symbol_index); |
| 483 | const module_name = if (lib_name) |l_name| blk: { |
| 484 | break :blk l_name; |
| 485 | } else wasm_file.host_name; |
| 486 | if (!gop.found_existing) { |
| 487 | gop.value_ptr.* = .{ |
| 488 | .module_name = try zig_object.string_table.insert(gpa, module_name), |
| 489 | .name = try zig_object.string_table.insert(gpa, name), |
| 490 | .kind = .{ .function = ty_index }, |
| 491 | }; |
| 492 | zig_object.imported_functions_count += 1; |
| 493 | } |
| 494 | } |
| 495 | } |
| 496 | |
| 497 | /// Returns the symbol index from a symbol of which its flag is set global, |
| 498 | /// such as an exported or imported symbol. |
| 499 | /// If the symbol does not yet exist, creates a new one symbol instead |
| 500 | /// and then returns the index to it. |
| 501 | pub fn getGlobalSymbol(zig_object: *ZigObject, wasm_file: *Wasm, name: []const u8) !u32 { |
| 502 | const gpa = wasm_file.base.comp.gpa; |
| 503 | const name_index = try zig_object.string_table.insert(gpa, name); |
| 504 | const gop = try zig_object.global_syms.getOrPut(gpa, name_index); |
| 505 | if (gop.found_existing) { |
| 506 | return gop.value_ptr.index; |
| 507 | } |
| 508 | |
| 509 | var symbol: Symbol = .{ |
| 510 | .name = name_index, |
| 511 | .flags = 0, |
| 512 | .index = undefined, // index to type will be set after merging function symbols |
| 513 | .tag = .function, |
| 514 | .virtual_address = undefined, |
| 515 | }; |
| 516 | symbol.setGlobal(true); |
| 517 | symbol.setUndefined(true); |
| 518 | |
| 519 | const sym_index = if (zig_object.symbol.popOrNull()) |index| index else blk: { |
| 520 | const index: u32 = @intCast(zig_object.symbols.items.len); |
| 521 | try zig_object.symbols.ensureUnusedCapacity(gpa, 1); |
| 522 | zig_object.symbols.items.len += 1; |
| 523 | break :blk index; |
| 524 | }; |
| 525 | zig_object.symbols.items[sym_index] = symbol; |
| 526 | gop.value_ptr.* = .{ .index = sym_index, .file = null }; |
| 527 | return sym_index; |
| 528 | } |
| 529 | |
| 530 | /// For a given decl, find the given symbol index's atom, and create a relocation for the type. |
| 531 | /// Returns the given pointer address |
| 532 | pub fn getDeclVAddr( |
| 533 | zig_object: *ZigObject, |
| 534 | wasm_file: *Wasm, |
| 535 | decl_index: InternPool.DeclIndex, |
| 536 | reloc_info: link.File.RelocInfo, |
| 537 | ) !u64 { |
| 538 | const target = wasm_file.base.comp.root_mod.resolved_target.result; |
| 539 | const gpa = wasm_file.base.comp.gpa; |
| 540 | const mod = wasm_file.base.comp.module.?; |
| 541 | const decl = mod.declPtr(decl_index); |
| 542 | |
| 543 | const target_atom_index = try zig_object.getOrCreateAtomForDecl(wasm_file, decl_index); |
| 544 | const target_symbol_index = wasm_file.getAtom(target_atom_index).sym_index; |
| 545 | |
| 546 | std.debug.assert(reloc_info.parent_atom_index != 0); |
| 547 | const atom_index = wasm_file.symbol_atom.get(.{ .file = null, .index = reloc_info.parent_atom_index }).?; |
| 548 | const atom = wasm_file.getAtomPtr(atom_index); |
| 549 | const is_wasm32 = target.cpu.arch == .wasm32; |
| 550 | if (decl.ty.zigTypeTag(mod) == .Fn) { |
| 551 | std.debug.assert(reloc_info.addend == 0); // addend not allowed for function relocations |
| 552 | try atom.relocs.append(gpa, .{ |
| 553 | .index = target_symbol_index, |
| 554 | .offset = @intCast(reloc_info.offset), |
| 555 | .relocation_type = if (is_wasm32) .R_WASM_TABLE_INDEX_I32 else .R_WASM_TABLE_INDEX_I64, |
| 556 | }); |
| 557 | } else { |
| 558 | try atom.relocs.append(gpa, .{ |
| 559 | .index = target_symbol_index, |
| 560 | .offset = @intCast(reloc_info.offset), |
| 561 | .relocation_type = if (is_wasm32) .R_WASM_MEMORY_ADDR_I32 else .R_WASM_MEMORY_ADDR_I64, |
| 562 | .addend = @intCast(reloc_info.addend), |
| 563 | }); |
| 564 | } |
| 565 | |
| 566 | // we do not know the final address at this point, |
| 567 | // as atom allocation will determine the address and relocations |
| 568 | // will calculate and rewrite this. Therefore, we simply return the symbol index |
| 569 | // that was targeted. |
| 570 | return target_symbol_index; |
| 571 | } |
| 572 | |
| 573 | pub fn getAnonDeclVAddr( |
| 574 | zig_object: *ZigObject, |
| 575 | wasm_file: *Wasm, |
| 576 | decl_val: InternPool.Index, |
| 577 | reloc_info: link.File.RelocInfo, |
| 578 | ) !u64 { |
| 579 | const gpa = wasm_file.base.comp.gpa; |
| 580 | const target = wasm_file.base.comp.root_mod.resolved_target.result; |
| 581 | const atom_index = zig_object.anon_decls.get(decl_val).?; |
| 582 | const target_symbol_index = wasm_file.getAtom(atom_index).getSymbolIndex().?; |
| 583 | |
| 584 | const parent_atom_index = wasm_file.symbol_atom.get(.{ .file = null, .index = reloc_info.parent_atom_index }).?; |
| 585 | const parent_atom = wasm_file.getAtomPtr(parent_atom_index); |
| 586 | const is_wasm32 = target.cpu.arch == .wasm32; |
| 587 | const mod = wasm_file.base.comp.module.?; |
| 588 | const ty = Type.fromInterned(mod.intern_pool.typeOf(decl_val)); |
| 589 | if (ty.zigTypeTag(mod) == .Fn) { |
| 590 | std.debug.assert(reloc_info.addend == 0); // addend not allowed for function relocations |
| 591 | try parent_atom.relocs.append(gpa, .{ |
| 592 | .index = target_symbol_index, |
| 593 | .offset = @intCast(reloc_info.offset), |
| 594 | .relocation_type = if (is_wasm32) .R_WASM_TABLE_INDEX_I32 else .R_WASM_TABLE_INDEX_I64, |
| 595 | }); |
| 596 | } else { |
| 597 | try parent_atom.relocs.append(gpa, .{ |
| 598 | .index = target_symbol_index, |
| 599 | .offset = @intCast(reloc_info.offset), |
| 600 | .relocation_type = if (is_wasm32) .R_WASM_MEMORY_ADDR_I32 else .R_WASM_MEMORY_ADDR_I64, |
| 601 | .addend = @intCast(reloc_info.addend), |
| 602 | }); |
| 603 | } |
| 604 | |
| 605 | // we do not know the final address at this point, |
| 606 | // as atom allocation will determine the address and relocations |
| 607 | // will calculate and rewrite this. Therefore, we simply return the symbol index |
| 608 | // that was targeted. |
| 609 | return target_symbol_index; |
| 610 | } |
| 611 | |
| 612 | pub fn deleteDeclExport( |
| 613 | zig_object: *ZigObject, |
| 614 | wasm_file: *Wasm, |
| 615 | decl_index: InternPool.DeclIndex, |
| 616 | ) void { |
| 617 | const atom_index = zig_object.decls.get(decl_index) orelse return; |
| 618 | const sym_index = wasm_file.getAtom(atom_index).sym_index; |
| 619 | const loc: Wasm.SymbolLoc = .{ .file = null, .index = sym_index }; |
| 620 | const symbol = loc.getSymbol(wasm_file); |
| 621 | std.debug.assert(zig_object.global_syms.remove(symbol.name)); |
| 622 | } |
| 623 | |
| 624 | pub fn updateExports( |
| 625 | zig_object: *ZigObject, |
| 626 | wasm_file: *Wasm, |
| 627 | mod: *Module, |
| 628 | exported: Module.Exported, |
| 629 | exports: []const *Module.Export, |
| 630 | ) !void { |
| 631 | const decl_index = switch (exported) { |
| 632 | .decl_index => |i| i, |
| 633 | .value => |val| { |
| 634 | _ = val; |
| 635 | @panic("TODO: implement Wasm linker code for exporting a constant value"); |
| 636 | }, |
| 637 | }; |
| 638 | const decl = mod.declPtr(decl_index); |
| 639 | const atom_index = try zig_object.getOrCreateAtomForDecl(decl_index); |
| 640 | const atom = wasm_file.getAtom(atom_index); |
| 641 | const atom_sym = atom.symbolLoc().getSymbol(wasm_file).*; |
| 642 | const gpa = mod.gpa; |
| 643 | |
| 644 | for (exports) |exp| { |
| 645 | if (mod.intern_pool.stringToSliceUnwrap(exp.opts.section)) |section| { |
| 646 | try mod.failed_exports.putNoClobber(gpa, exp, try Module.ErrorMsg.create( |
| 647 | gpa, |
| 648 | decl.srcLoc(mod), |
| 649 | "Unimplemented: ExportOptions.section '{s}'", |
| 650 | .{section}, |
| 651 | )); |
| 652 | continue; |
| 653 | } |
| 654 | |
| 655 | const exported_decl_index = switch (exp.exported) { |
| 656 | .value => { |
| 657 | try mod.failed_exports.putNoClobber(gpa, exp, try Module.ErrorMsg.create( |
| 658 | gpa, |
| 659 | decl.srcLoc(mod), |
| 660 | "Unimplemented: exporting a named constant value", |
| 661 | .{}, |
| 662 | )); |
| 663 | continue; |
| 664 | }, |
| 665 | .decl_index => |i| i, |
| 666 | }; |
| 667 | const exported_atom_index = try zig_object.getOrCreateAtomForDecl(exported_decl_index); |
| 668 | const exported_atom = wasm_file.getAtom(exported_atom_index); |
| 669 | // const export_name = try zig_object.string_table.put(gpa, mod.intern_pool.stringToSlice(exp.opts.name)); |
| 670 | const sym_loc = exported_atom.symbolLoc(); |
| 671 | const symbol = sym_loc.getSymbol(wasm_file); |
| 672 | symbol.setGlobal(true); |
| 673 | symbol.setUndefined(false); |
| 674 | symbol.index = atom_sym.index; |
| 675 | symbol.tag = atom_sym.tag; |
| 676 | symbol.name = atom_sym.name; |
| 677 | |
| 678 | switch (exp.opts.linkage) { |
| 679 | .Internal => { |
| 680 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); |
| 681 | symbol.setFlag(.WASM_SYM_BINDING_WEAK); |
| 682 | }, |
| 683 | .Weak => { |
| 684 | symbol.setFlag(.WASM_SYM_BINDING_WEAK); |
| 685 | }, |
| 686 | .Strong => {}, // symbols are strong by default |
| 687 | .LinkOnce => { |
| 688 | try mod.failed_exports.putNoClobber(gpa, exp, try Module.ErrorMsg.create( |
| 689 | gpa, |
| 690 | decl.srcLoc(mod), |
| 691 | "Unimplemented: LinkOnce", |
| 692 | .{}, |
| 693 | )); |
| 694 | continue; |
| 695 | }, |
| 696 | } |
| 697 | |
| 698 | // TODO: Revisit this |
| 699 | // if (zig_object.global_syms.get(export_name)) |existing_loc| { |
| 700 | // if (existing_loc.index == atom.sym_index) continue; |
| 701 | // const existing_sym: Symbol = existing_loc.getSymbol(wasm_file).*; |
| 702 | |
| 703 | // if (!existing_sym.isUndefined()) blk: { |
| 704 | // if (symbol.isWeak()) { |
| 705 | // try wasm_file.discarded.put(gpa, existing_loc, sym_loc); |
| 706 | // continue; // to-be-exported symbol is weak, so we keep the existing symbol |
| 707 | // } |
| 708 | |
| 709 | // // new symbol is not weak while existing is, replace existing symbol |
| 710 | // if (existing_sym.isWeak()) { |
| 711 | // break :blk; |
| 712 | // } |
| 713 | // // When both the to-be-exported symbol and the already existing symbol |
| 714 | // // are strong symbols, we have a linker error. |
| 715 | // // In the other case we replace one with the other. |
| 716 | // try mod.failed_exports.put(gpa, exp, try Module.ErrorMsg.create( |
| 717 | // gpa, |
| 718 | // decl.srcLoc(mod), |
| 719 | // \\LinkError: symbol '{}' defined multiple times |
| 720 | // \\ first definition in '{s}' |
| 721 | // \\ next definition in '{s}' |
| 722 | // , |
| 723 | // .{ exp.opts.name.fmt(&mod.intern_pool), wasm_file.name, wasm_file.name }, |
| 724 | // )); |
| 725 | // continue; |
| 726 | // } |
| 727 | |
| 728 | // // in this case the existing symbol must be replaced either because it's weak or undefined. |
| 729 | // try wasm.discarded.put(gpa, existing_loc, sym_loc); |
| 730 | // _ = wasm.imports.remove(existing_loc); |
| 731 | // _ = wasm.undefs.swapRemove(existing_sym.name); |
| 732 | // } |
| 733 | |
| 734 | // // Ensure the symbol will be exported using the given name |
| 735 | // if (!mod.intern_pool.stringEqlSlice(exp.opts.name, sym_loc.getName(wasm))) { |
| 736 | // try wasm.export_names.put(gpa, sym_loc, export_name); |
| 737 | // } |
| 738 | |
| 739 | // try wasm.globals.put( |
| 740 | // gpa, |
| 741 | // export_name, |
| 742 | // sym_loc, |
| 743 | // ); |
| 744 | } |
| 745 | } |
| 746 | |
| 747 | pub fn freeDecl(zig_object: *ZigObject, wasm_file: *Wasm, decl_index: InternPool.DeclIndex) void { |
| 748 | const gpa = wasm_file.base.comp.gpa; |
| 749 | const mod = wasm_file.base.comp.module.?; |
| 750 | const decl = mod.declPtr(decl_index); |
| 751 | const atom_index = zig_object.decls.get(decl_index).?; |
| 752 | const atom = wasm_file.getAtomPtr(atom_index); |
| 753 | zig_object.symbols_free_list.append(gpa, atom.sym_index) catch {}; |
| 754 | _ = zig_object.decls.remove(decl_index); |
| 755 | zig_object.symbols.items[atom.sym_index].tag = .dead; |
| 756 | for (atom.locals.items) |local_atom_index| { |
| 757 | const local_atom = wasm_file.getAtom(local_atom_index); |
| 758 | const local_symbol = &zig_object.symbols.items[local_atom.sym_index]; |
| 759 | local_symbol.tag = .dead; // also for any local symbol |
| 760 | zig_object.symbols_free_list.append(gpa, local_atom.sym_index) catch {}; |
| 761 | std.denug.assert(wasm_file.symbol_atom.remove(local_atom.symbolLoc())); |
| 762 | } |
| 763 | |
| 764 | if (decl.isExtern(mod)) { |
| 765 | _ = zig_object.imports.remove(atom.getSymbolIndex().?); |
| 766 | } |
| 767 | _ = wasm_file.symbol_atom.remove(atom.symbolLoc()); |
| 768 | |
| 769 | // if (wasm.dwarf) |*dwarf| { |
| 770 | // dwarf.freeDecl(decl_index); |
| 771 | // } |
| 772 | |
| 773 | if (atom.next) |next_atom_index| { |
| 774 | const next_atom = wasm_file.getAtomPtr(next_atom_index); |
| 775 | next_atom.prev = atom.prev; |
| 776 | atom.next = null; |
| 777 | } |
| 778 | if (atom.prev) |prev_index| { |
| 779 | const prev_atom = wasm_file.getAtomPtr(prev_index); |
| 780 | prev_atom.next = atom.next; |
| 781 | atom.prev = null; |
| 782 | } |
| 783 | } |
| 784 | |
| 785 | pub fn getTypeIndex(zig_object: *const ZigObject, func_type: std.wasm.Type) ?u32 { |
| 786 | var index: u32 = 0; |
| 787 | while (index < zig_object.func_types.items.len) : (index += 1) { |
| 788 | if (zig_object.func_types.items[index].eql(func_type)) return index; |
| 789 | } |
| 790 | return null; |
| 791 | } |
| 792 | |
| 793 | /// Searches for a matching function signature. When no matching signature is found, |
| 794 | /// a new entry will be made. The value returned is the index of the type within `wasm.func_types`. |
| 795 | pub fn putOrGetFuncType(zig_object: *ZigObject, gpa: std.mem.Allocator, func_type: std.wasm.Type) !u32 { |
| 796 | if (zig_object.getTypeIndex(func_type)) |index| { |
| 797 | return index; |
| 798 | } |
| 799 | |
| 800 | // functype does not exist. |
| 801 | const index: u32 = @intCast(zig_object.func_types.items.len); |
| 802 | const params = try gpa.dupe(std.wasm.Valtype, func_type.params); |
| 803 | errdefer gpa.free(params); |
| 804 | const returns = try gpa.dupe(std.wasm.Valtype, func_type.returns); |
| 805 | errdefer gpa.free(returns); |
| 806 | try zig_object.func_types.append(gpa, .{ |
| 807 | .params = params, |
| 808 | .returns = returns, |
| 809 | }); |
| 810 | return index; |
| 811 | } |
| 812 | |
| 813 | /// Kind represents the type of an Atom, which is only |
| 814 | /// used to parse a decl into an Atom to define in which section |
| 815 | /// or segment it should be placed. |
| 816 | const Kind = union(enum) { |
| 817 | /// Represents the segment the data symbol should |
| 818 | /// be inserted into. |
| 819 | /// TODO: Add TLS segments |
| 820 | data: enum { |
| 821 | read_only, |
| 822 | uninitialized, |
| 823 | initialized, |
| 824 | }, |
| 825 | function: void, |
| 826 | |
| 827 | /// Returns the segment name the data kind represents. |
| 828 | /// Asserts `kind` has its active tag set to `data`. |
| 829 | fn segmentName(kind: Kind) []const u8 { |
| 830 | switch (kind.data) { |
| 831 | .read_only => return ".rodata.", |
| 832 | .uninitialized => return ".bss.", |
| 833 | .initialized => return ".data.", |
| 834 | } |
| 835 | } |
| 836 | }; |
| 837 | |
| 838 | /// Parses an Atom and inserts its metadata into the corresponding sections. |
| 839 | pub fn parseAtom(zig_object: *ZigObject, wasm_file: *Wasm, atom_index: Atom.Index, kind: Kind) !void { |
| 840 | // TODO: Revisit |
| 841 | _ = zig_object; |
| 842 | _ = wasm_file; |
| 843 | _ = atom_index; |
| 844 | _ = kind; |
| 845 | // const comp = wasm.base.comp; |
| 846 | // const gpa = comp.gpa; |
| 847 | // const shared_memory = comp.config.shared_memory; |
| 848 | // const import_memory = comp.config.import_memory; |
| 849 | // const atom = wasm.getAtomPtr(atom_index); |
| 850 | // const symbol = (SymbolLoc{ .file = null, .index = atom.sym_index }).getSymbol(wasm); |
| 851 | // const do_garbage_collect = wasm.base.gc_sections; |
| 852 | |
| 853 | // if (symbol.isDead() and do_garbage_collect) { |
| 854 | // // Prevent unreferenced symbols from being parsed. |
| 855 | // return; |
| 856 | // } |
| 857 | |
| 858 | // const final_index: u32 = switch (kind) { |
| 859 | // .function => result: { |
| 860 | // const index: u32 = @intCast(wasm.functions.count() + wasm.imported_functions_count); |
| 861 | // const type_index = wasm.atom_types.get(atom_index).?; |
| 862 | // try wasm.functions.putNoClobber( |
| 863 | // gpa, |
| 864 | // .{ .file = null, .index = index }, |
| 865 | // .{ .func = .{ .type_index = type_index }, .sym_index = atom.sym_index }, |
| 866 | // ); |
| 867 | // symbol.tag = .function; |
| 868 | // symbol.index = index; |
| 869 | |
| 870 | // if (wasm.code_section_index == null) { |
| 871 | // wasm.code_section_index = @intCast(wasm.segments.items.len); |
| 872 | // try wasm.segments.append(gpa, .{ |
| 873 | // .alignment = atom.alignment, |
| 874 | // .size = atom.size, |
| 875 | // .offset = 0, |
| 876 | // .flags = 0, |
| 877 | // }); |
| 878 | // } |
| 879 | |
| 880 | // break :result wasm.code_section_index.?; |
| 881 | // }, |
| 882 | // .data => result: { |
| 883 | // const segment_name = try std.mem.concat(gpa, u8, &.{ |
| 884 | // kind.segmentName(), |
| 885 | // wasm.string_table.get(symbol.name), |
| 886 | // }); |
| 887 | // errdefer gpa.free(segment_name); |
| 888 | // const segment_info: types.Segment = .{ |
| 889 | // .name = segment_name, |
| 890 | // .alignment = atom.alignment, |
| 891 | // .flags = 0, |
| 892 | // }; |
| 893 | // symbol.tag = .data; |
| 894 | |
| 895 | // // when creating an object file, or importing memory and the data belongs in the .bss segment |
| 896 | // // we set the entire region of it to zeroes. |
| 897 | // // We do not have to do this when exporting the memory (the default) because the runtime |
| 898 | // // will do it for us, and we do not emit the bss segment at all. |
| 899 | // if ((wasm.base.comp.config.output_mode == .Obj or import_memory) and kind.data == .uninitialized) { |
| 900 | // @memset(atom.code.items, 0); |
| 901 | // } |
| 902 | |
| 903 | // const should_merge = wasm.base.comp.config.output_mode != .Obj; |
| 904 | // const gop = try wasm.data_segments.getOrPut(gpa, segment_info.outputName(should_merge)); |
| 905 | // if (gop.found_existing) { |
| 906 | // const index = gop.value_ptr.*; |
| 907 | // wasm.segments.items[index].size += atom.size; |
| 908 | |
| 909 | // symbol.index = @intCast(wasm.segment_info.getIndex(index).?); |
| 910 | // // segment info already exists, so free its memory |
| 911 | // gpa.free(segment_name); |
| 912 | // break :result index; |
| 913 | // } else { |
| 914 | // const index: u32 = @intCast(wasm.segments.items.len); |
| 915 | // var flags: u32 = 0; |
| 916 | // if (shared_memory) { |
| 917 | // flags |= @intFromEnum(Segment.Flag.WASM_DATA_SEGMENT_IS_PASSIVE); |
| 918 | // } |
| 919 | // try wasm.segments.append(gpa, .{ |
| 920 | // .alignment = atom.alignment, |
| 921 | // .size = 0, |
| 922 | // .offset = 0, |
| 923 | // .flags = flags, |
| 924 | // }); |
| 925 | // gop.value_ptr.* = index; |
| 926 | |
| 927 | // const info_index: u32 = @intCast(wasm.segment_info.count()); |
| 928 | // try wasm.segment_info.put(gpa, index, segment_info); |
| 929 | // symbol.index = info_index; |
| 930 | // break :result index; |
| 931 | // } |
| 932 | // }, |
| 933 | // }; |
| 934 | |
| 935 | // const segment: *Segment = &wasm.segments.items[final_index]; |
| 936 | // segment.alignment = segment.alignment.max(atom.alignment); |
| 937 | |
| 938 | // try wasm.appendAtomAtIndex(final_index, atom_index); |
| 939 | } |
| 940 | |
| 941 | /// Generates an atom containing the global error set' size. |
| 942 | /// This will only be generated if the symbol exists. |
| 943 | fn setupErrorsLen(zig_object: *ZigObject, wasm_file: *Wasm) !void { |
| 944 | const gpa = wasm_file.base.comp.gpa; |
| 945 | const loc = zig_object.findGlobalSymbol("__zig_errors_len") orelse return; |
| 946 | |
| 947 | const errors_len = wasm_file.base.comp.module.?.global_error_set.count(); |
| 948 | // overwrite existing atom if it already exists (maybe the error set has increased) |
| 949 | // if not, allcoate a new atom. |
| 950 | const atom_index = if (wasm_file.symbol_atom.get(loc)) |index| blk: { |
| 951 | const atom = wasm_file.getAtomPtr(index); |
| 952 | if (atom.next) |next_atom_index| { |
| 953 | const next_atom = wasm_file.getAtomPtr(next_atom_index); |
| 954 | next_atom.prev = atom.prev; |
| 955 | atom.next = null; |
| 956 | } |
| 957 | if (atom.prev) |prev_index| { |
| 958 | const prev_atom = wasm_file.getAtomPtr(prev_index); |
| 959 | prev_atom.next = atom.next; |
| 960 | atom.prev = null; |
| 961 | } |
| 962 | atom.deinit(gpa); |
| 963 | break :blk index; |
| 964 | } else new_atom: { |
| 965 | const atom_index: Atom.Index = @intCast(wasm_file.managed_atoms.items.len); |
| 966 | try wasm_file.symbol_atom.put(gpa, loc, atom_index); |
| 967 | try wasm_file.managed_atoms.append(gpa, undefined); |
| 968 | break :new_atom atom_index; |
| 969 | }; |
| 970 | const atom = wasm_file.getAtomPtr(atom_index); |
| 971 | atom.* = Atom.empty; |
| 972 | atom.sym_index = loc.index; |
| 973 | atom.size = 2; |
| 974 | try atom.code.writer(gpa).writeInt(u16, @intCast(errors_len), .little); |
| 975 | |
| 976 | // try wasm.parseAtom(atom_index, .{ .data = .read_only }); |
| 977 | } |
| 978 | |
| 979 | const build_options = @import("build_options"); |
| 980 | const builtin = @import("builtin"); |
| 981 | const codegen = @import("../../codegen.zig"); |
| 982 | const link = @import("../../link.zig"); |
| 983 | const log = std.log.scoped(.zig_object); |
| 984 | const std = @import("std"); |
| 985 | const types = @import("types.zig"); |
| 986 | |
| 987 | const Air = @import("../../Air.zig"); |
| 988 | const Atom = @import("Atom.zig"); |
| 989 | const InternPool = @import("../../InternPool.zig"); |
| 990 | const Liveness = @import("../../Liveness.zig"); |
| 991 | const Module = @import("../../Module.zig"); |
| 992 | const StringTable = @import("../StringTable.zig"); |
| 993 | const Symbol = @import("Symbol.zig"); |
| 994 | const Type = @import("../../type.zig").Type; |
| 995 | const TypedValue = @import("../../TypedValue.zig"); |
| 996 | const Value = @import("../../value.zig").Value; |
| 997 | const Wasm = @import("../Wasm.zig"); |
| 998 | const ZigObject = @This(); |