diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/arch/wasm/CodeGen.zig | 69 | ||||
| -rw-r--r-- | src/codegen.zig | 4 | ||||
| -rw-r--r-- | src/link/Wasm.zig | 94 |
3 files changed, 84 insertions, 83 deletions
diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 877db4b623..aa44dc2bc8 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -2938,49 +2938,31 @@ fn wrapOperand(func: *CodeGen, operand: WValue, ty: Type) InnerError!WValue { return WValue{ .stack = {} }; } -fn lowerParentPtr(func: *CodeGen, ptr_val: Value) InnerError!WValue { +fn lowerParentPtr(func: *CodeGen, ptr_val: Value, offset: u32) InnerError!WValue { const mod = func.bin_file.base.options.module.?; const ptr = mod.intern_pool.indexToKey(ptr_val.ip_index).ptr; switch (ptr.addr) { .decl => |decl_index| { - return func.lowerParentPtrDecl(ptr_val, decl_index, 0); + return func.lowerParentPtrDecl(ptr_val, decl_index, offset); }, .mut_decl => |mut_decl| { const decl_index = mut_decl.decl; - return func.lowerParentPtrDecl(ptr_val, decl_index, 0); - }, - .int, .eu_payload => |tag| return func.fail("TODO: Implement lowerParentPtr for {}", .{tag}), - .opt_payload => |base_ptr| { - return func.lowerParentPtr(base_ptr.toValue()); + return func.lowerParentPtrDecl(ptr_val, decl_index, offset); }, + .eu_payload => |tag| return func.fail("TODO: Implement lowerParentPtr for {}", .{tag}), + .int => |base| return func.lowerConstant(base.toValue(), Type.usize), + .opt_payload => |base_ptr| return func.lowerParentPtr(base_ptr.toValue(), offset), .comptime_field => unreachable, .elem => |elem| { const index = elem.index; const elem_type = mod.intern_pool.typeOf(elem.base).toType().elemType2(mod); - const offset = index * elem_type.abiSize(mod); - const array_ptr = try func.lowerParentPtr(elem.base.toValue()); - - return switch (array_ptr) { - .memory => |ptr_| WValue{ - .memory_offset = .{ - .pointer = ptr_, - .offset = @intCast(u32, offset), - }, - }, - .memory_offset => |mem_off| WValue{ - .memory_offset = .{ - .pointer = mem_off.pointer, - .offset = @intCast(u32, offset) + mem_off.offset, - }, - }, - else => unreachable, - }; + const elem_offset = index * elem_type.abiSize(mod); + return func.lowerParentPtr(elem.base.toValue(), @intCast(u32, elem_offset + offset)); }, .field => |field| { const parent_ty = mod.intern_pool.typeOf(field.base).toType().childType(mod); - const parent_ptr = try func.lowerParentPtr(field.base.toValue()); - const offset = switch (parent_ty.zigTypeTag(mod)) { + const field_offset = switch (parent_ty.zigTypeTag(mod)) { .Struct => switch (parent_ty.containerLayout(mod)) { .Packed => parent_ty.packedStructFieldByteOffset(@intCast(usize, field.index), mod), else => parent_ty.structFieldOffset(@intCast(usize, field.index), mod), @@ -2993,8 +2975,7 @@ fn lowerParentPtr(func: *CodeGen, ptr_val: Value) InnerError!WValue { if (layout.payload_align > layout.tag_align) break :blk 0; // tag is stored first so calculate offset from where payload starts - const offset = @intCast(u32, std.mem.alignForwardGeneric(u64, layout.tag_size, layout.tag_align)); - break :blk offset; + break :blk @intCast(u32, std.mem.alignForwardGeneric(u64, layout.tag_size, layout.tag_align)); }, }, .Pointer => switch (parent_ty.ptrSize(mod)) { @@ -3007,22 +2988,7 @@ fn lowerParentPtr(func: *CodeGen, ptr_val: Value) InnerError!WValue { }, else => unreachable, }; - - return switch (parent_ptr) { - .memory => |ptr_| WValue{ - .memory_offset = .{ - .pointer = ptr_, - .offset = @intCast(u32, offset), - }, - }, - .memory_offset => |mem_off| WValue{ - .memory_offset = .{ - .pointer = mem_off.pointer, - .offset = @intCast(u32, offset) + mem_off.offset, - }, - }, - else => unreachable, - }; + return func.lowerParentPtr(field.base.toValue(), @intCast(u32, offset + field_offset)); }, } } @@ -3042,6 +3008,17 @@ fn lowerDeclRefValue(func: *CodeGen, tv: TypedValue, decl_index: Module.Decl.Ind } const decl = mod.declPtr(decl_index); + // check if decl is an alias to a function, in which case we + // want to lower the actual decl, rather than the alias itself. + if (decl.val.getFunction(mod)) |func_val| { + if (func_val.owner_decl != decl_index) { + return func.lowerDeclRefValue(tv, func_val.owner_decl, offset); + } + } else if (decl.val.getExternFunc(mod)) |func_val| { + if (func_val.decl != decl_index) { + return func.lowerDeclRefValue(tv, func_val.decl, offset); + } + } if (decl.ty.zigTypeTag(mod) != .Fn and !decl.ty.hasRuntimeBitsIgnoreComptime(mod)) { return WValue{ .imm32 = 0xaaaaaaaa }; } @@ -3230,7 +3207,7 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue { .decl => |decl| return func.lowerDeclRefValue(.{ .ty = ty, .val = val }, decl, 0), .mut_decl => |mut_decl| return func.lowerDeclRefValue(.{ .ty = ty, .val = val }, mut_decl.decl, 0), .int => |int| return func.lowerConstant(int.toValue(), mod.intern_pool.typeOf(int).toType()), - .opt_payload, .elem, .field => return func.lowerParentPtr(val), + .opt_payload, .elem, .field => return func.lowerParentPtr(val, 0), else => return func.fail("Wasm TODO: lowerConstant for other const addr tag {}", .{ptr.addr}), }, .opt => if (ty.optionalReprIsPayload(mod)) { diff --git a/src/codegen.zig b/src/codegen.zig index d446200a3b..6145d8778b 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -598,6 +598,10 @@ pub fn generateSymbol( .fail => |em| return Result{ .fail = em }, } } + + if (layout.padding > 0) { + try code.writer().writeByteNTimes(0, layout.padding); + } }, .memoized_call => unreachable, } diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 5126033995..f911074473 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -1703,6 +1703,7 @@ pub fn updateDeclExports( const decl = mod.declPtr(decl_index); const atom_index = try wasm.getOrCreateAtomForDecl(decl_index); const atom = wasm.getAtom(atom_index); + const atom_sym = atom.symbolLoc().getSymbol(wasm).*; const gpa = mod.gpa; for (exports) |exp| { @@ -1716,43 +1717,21 @@ pub fn updateDeclExports( continue; } - const export_name = try wasm.string_table.put(wasm.base.allocator, mod.intern_pool.stringToSlice(exp.opts.name)); - if (wasm.globals.getPtr(export_name)) |existing_loc| { - if (existing_loc.index == atom.sym_index) continue; - const existing_sym: Symbol = existing_loc.getSymbol(wasm).*; - - const exp_is_weak = exp.opts.linkage == .Internal or exp.opts.linkage == .Weak; - // When both the to-be-exported symbol and the already existing symbol - // are strong symbols, we have a linker error. - // In the other case we replace one with the other. - if (!exp_is_weak and !existing_sym.isWeak()) { - try mod.failed_exports.put(gpa, exp, try Module.ErrorMsg.create( - gpa, - decl.srcLoc(mod), - \\LinkError: symbol '{}' defined multiple times - \\ first definition in '{s}' - \\ next definition in '{s}' - , - .{ exp.opts.name.fmt(&mod.intern_pool), wasm.name, wasm.name }, - )); - continue; - } else if (exp_is_weak) { - continue; // to-be-exported symbol is weak, so we keep the existing symbol - } else { - // TODO: Revisit this, why was this needed? - existing_loc.index = atom.sym_index; - existing_loc.file = null; - // exp.link.wasm.sym_index = existing_loc.index; - } - } - const exported_atom_index = try wasm.getOrCreateAtomForDecl(exp.exported_decl); const exported_atom = wasm.getAtom(exported_atom_index); + const export_name = try wasm.string_table.put(wasm.base.allocator, mod.intern_pool.stringToSlice(exp.opts.name)); const sym_loc = exported_atom.symbolLoc(); const symbol = sym_loc.getSymbol(wasm); + symbol.setGlobal(true); + symbol.setUndefined(false); + symbol.index = atom_sym.index; + symbol.tag = atom_sym.tag; + symbol.name = atom_sym.name; + switch (exp.opts.linkage) { .Internal => { symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); + symbol.setFlag(.WASM_SYM_BINDING_WEAK); }, .Weak => { symbol.setFlag(.WASM_SYM_BINDING_WEAK); @@ -1768,22 +1747,52 @@ pub fn updateDeclExports( continue; }, } + + if (wasm.globals.get(export_name)) |existing_loc| { + if (existing_loc.index == atom.sym_index) continue; + const existing_sym: Symbol = existing_loc.getSymbol(wasm).*; + + if (!existing_sym.isUndefined()) blk: { + if (symbol.isWeak()) { + try wasm.discarded.put(wasm.base.allocator, existing_loc, sym_loc); + continue; // to-be-exported symbol is weak, so we keep the existing symbol + } + + // new symbol is not weak while existing is, replace existing symbol + if (existing_sym.isWeak()) { + break :blk; + } + // When both the to-be-exported symbol and the already existing symbol + // are strong symbols, we have a linker error. + // In the other case we replace one with the other. + try mod.failed_exports.put(gpa, exp, try Module.ErrorMsg.create( + gpa, + decl.srcLoc(mod), + \\LinkError: symbol '{}' defined multiple times + \\ first definition in '{s}' + \\ next definition in '{s}' + , + .{ exp.opts.name.fmt(&mod.intern_pool), wasm.name, wasm.name }, + )); + continue; + } + + // in this case the existing symbol must be replaced either because it's weak or undefined. + try wasm.discarded.put(wasm.base.allocator, existing_loc, sym_loc); + _ = wasm.imports.remove(existing_loc); + _ = wasm.undefs.swapRemove(existing_sym.name); + } + // Ensure the symbol will be exported using the given name if (!mod.intern_pool.stringEqlSlice(exp.opts.name, sym_loc.getName(wasm))) { try wasm.export_names.put(wasm.base.allocator, sym_loc, export_name); } - symbol.setGlobal(true); - symbol.setUndefined(false); try wasm.globals.put( wasm.base.allocator, export_name, sym_loc, ); - - // if the symbol was previously undefined, remove it as an import - _ = wasm.imports.remove(sym_loc); - _ = wasm.undefs.swapRemove(export_name); } } @@ -1900,6 +1909,17 @@ pub fn addOrUpdateImport( global_gop.value_ptr.* = loc; try wasm.resolved_symbols.put(wasm.base.allocator, loc, {}); try wasm.undefs.putNoClobber(wasm.base.allocator, decl_name_index, loc); + } else if (global_gop.value_ptr.*.index != symbol_index) { + // We are not updating a symbol, but found an existing global + // symbol with the same name. This means we always favor the + // existing symbol, regardless whether it's defined or not. + // We can also skip storing the import as we will not output + // this symbol. + return wasm.discarded.put( + wasm.base.allocator, + .{ .file = null, .index = symbol_index }, + global_gop.value_ptr.*, + ); } if (type_index) |ty_index| { @@ -1915,8 +1935,8 @@ pub fn addOrUpdateImport( }; } } else { + // non-functions will not be imported from the runtime, but only resolved during link-time symbol.tag = .data; - return; // non-functions will not be imported from the runtime, but only resolved during link-time } } |
