aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/arch/wasm/CodeGen.zig69
-rw-r--r--src/codegen.zig4
-rw-r--r--src/link/Wasm.zig94
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
}
}