authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-12-30 15:40:11-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-01-15 15:11:36-08:00
log5b18af85cb77d8dd7b2300bd01c00990d03abde2
tree1de9ca1604f82d222a15fba0b0f58bbc466f047c
parenta4895f3c42e8bd7d3eba5624e4a11aae5312a085

type checking for synthetic functions


3 files changed, 68 insertions(+), 31 deletions(-)

src/link.zig+16-3
......@@ -214,22 +214,35 @@ pub const Diags = struct {
214214 return error.LinkFailure;
215215 }
216216
217 pub fn failSourceLocation(diags: *Diags, sl: SourceLocation, comptime format: []const u8, args: anytype) error{LinkFailure} {
218 @branchHint(.cold);
219 addErrorSourceLocation(diags, sl, format, args);
220 return error.LinkFailure;
221 }
222
217223 pub fn addError(diags: *Diags, comptime format: []const u8, args: anytype) void {
224 return addErrorSourceLocation(diags, .none, format, args);
225 }
226
227 pub fn addErrorSourceLocation(diags: *Diags, sl: SourceLocation, comptime format: []const u8, args: anytype) void {
218228 @branchHint(.cold);
219229 const gpa = diags.gpa;
220230 const eu_main_msg = std.fmt.allocPrint(gpa, format, args);
221231 diags.mutex.lock();
222232 defer diags.mutex.unlock();
223 addErrorLockedFallible(diags, eu_main_msg) catch |err| switch (err) {
233 addErrorLockedFallible(diags, sl, eu_main_msg) catch |err| switch (err) {
224234 error.OutOfMemory => diags.setAllocFailureLocked(),
225235 };
226236 }
227237
228 fn addErrorLockedFallible(diags: *Diags, eu_main_msg: Allocator.Error![]u8) Allocator.Error!void {
238 fn addErrorLockedFallible(diags: *Diags, sl: SourceLocation, eu_main_msg: Allocator.Error![]u8) Allocator.Error!void {
229239 const gpa = diags.gpa;
230240 const main_msg = try eu_main_msg;
231241 errdefer gpa.free(main_msg);
232 try diags.msgs.append(gpa, .{ .msg = main_msg });
242 try diags.msgs.append(gpa, .{
243 .msg = main_msg,
244 .source_location = sl,
245 });
233246 }
234247
235248 pub fn addErrorWithNotes(diags: *Diags, note_count: usize) error{OutOfMemory}!ErrorWithNotes {
src/link/Wasm.zig+52-27
......@@ -474,6 +474,10 @@ pub const SourceLocation = enum(u32) {
474474 err_msg.notes[err.note_slot - 1].source_location = .{ .wasm = sl };
475475 }
476476
477 pub fn fail(sl: SourceLocation, diags: *link.Diags, comptime format: []const u8, args: anytype) error{LinkFailure} {
478 return diags.failSourceLocation(.{ .wasm = sl }, format, args);
479 }
480
477481 pub fn string(
478482 sl: SourceLocation,
479483 msg: []const u8,
......@@ -881,12 +885,11 @@ pub const FunctionImport = extern struct {
881885 __wasm_call_ctors,
882886 __wasm_init_memory,
883887 __wasm_init_tls,
884 __zig_error_names,
885888 // Next, index into `object_functions`.
886889 // Next, index into `zcu_funcs`.
887890 _,
888891
889 const first_object_function = @intFromEnum(Resolution.__zig_error_names) + 1;
892 const first_object_function = @intFromEnum(Resolution.__wasm_init_tls) + 1;
890893
891894 pub const Unpacked = union(enum) {
892895 unresolved,
......@@ -894,7 +897,6 @@ pub const FunctionImport = extern struct {
894897 __wasm_call_ctors,
895898 __wasm_init_memory,
896899 __wasm_init_tls,
897 __zig_error_names,
898900 object_function: ObjectFunctionIndex,
899901 zcu_func: ZcuFunc.Index,
900902 };
......@@ -906,7 +908,6 @@ pub const FunctionImport = extern struct {
906908 .__wasm_call_ctors => .__wasm_call_ctors,
907909 .__wasm_init_memory => .__wasm_init_memory,
908910 .__wasm_init_tls => .__wasm_init_tls,
909 .__zig_error_names => .__zig_error_names,
910911 _ => {
911912 const object_function_index = @intFromEnum(r) - first_object_function;
912913
......@@ -927,7 +928,6 @@ pub const FunctionImport = extern struct {
927928 .__wasm_call_ctors => .__wasm_call_ctors,
928929 .__wasm_init_memory => .__wasm_init_memory,
929930 .__wasm_init_tls => .__wasm_init_tls,
930 .__zig_error_names => .__zig_error_names,
931931 .object_function => |i| @enumFromInt(first_object_function + @intFromEnum(i)),
932932 .zcu_func => |i| @enumFromInt(first_object_function + wasm.object_functions.items.len + @intFromEnum(i)),
933933 };
......@@ -957,11 +957,11 @@ pub const FunctionImport = extern struct {
957957 pub fn typeIndex(r: Resolution, wasm: *Wasm) FunctionType.Index {
958958 return switch (unpack(r, wasm)) {
959959 .unresolved => unreachable,
960 .__wasm_apply_global_tls_relocs => @panic("TODO"),
961 .__wasm_call_ctors => @panic("TODO"),
962 .__wasm_init_memory => @panic("TODO"),
963 .__wasm_init_tls => @panic("TODO"),
964 .__zig_error_names => @panic("TODO"),
960 .__wasm_apply_global_tls_relocs,
961 .__wasm_call_ctors,
962 .__wasm_init_memory,
963 => getExistingFuncType2(wasm, &.{}, &.{}),
964 .__wasm_init_tls => getExistingFuncType2(wasm, &.{.i32}, &.{}),
965965 .object_function => |i| i.ptr(wasm).type_index,
966966 .zcu_func => |i| i.typeIndex(wasm).?,
967967 };
......@@ -974,7 +974,6 @@ pub const FunctionImport = extern struct {
974974 .__wasm_call_ctors => @tagName(Unpacked.__wasm_call_ctors),
975975 .__wasm_init_memory => @tagName(Unpacked.__wasm_init_memory),
976976 .__wasm_init_tls => @tagName(Unpacked.__wasm_init_tls),
977 .__zig_error_names => @tagName(Unpacked.__zig_error_names),
978977 .object_function => |i| i.ptr(wasm).name.slice(wasm),
979978 .zcu_func => |i| i.name(wasm),
980979 };
......@@ -2991,7 +2990,7 @@ fn markFunctionImport(
29912990 name: String,
29922991 import: *FunctionImport,
29932992 func_index: FunctionImport.Index,
2994) Allocator.Error!void {
2993) link.File.FlushError!void {
29952994 if (import.flags.alive) return;
29962995 import.flags.alive = true;
29972996
......@@ -3002,17 +3001,13 @@ fn markFunctionImport(
30023001
30033002 if (import.resolution == .unresolved) {
30043003 if (name == wasm.preloaded_strings.__wasm_init_memory) {
3005 import.resolution = .__wasm_init_memory;
3006 wasm.functions.putAssumeCapacity(.__wasm_init_memory, {});
3004 try wasm.resolveFunctionSynthetic(import, .__wasm_init_memory, &.{}, &.{});
30073005 } else if (name == wasm.preloaded_strings.__wasm_apply_global_tls_relocs) {
3008 import.resolution = .__wasm_apply_global_tls_relocs;
3009 wasm.functions.putAssumeCapacity(.__wasm_apply_global_tls_relocs, {});
3006 try wasm.resolveFunctionSynthetic(import, .__wasm_apply_global_tls_relocs, &.{}, &.{});
30103007 } else if (name == wasm.preloaded_strings.__wasm_call_ctors) {
3011 import.resolution = .__wasm_call_ctors;
3012 wasm.functions.putAssumeCapacity(.__wasm_call_ctors, {});
3008 try wasm.resolveFunctionSynthetic(import, .__wasm_call_ctors, &.{}, &.{});
30133009 } else if (name == wasm.preloaded_strings.__wasm_init_tls) {
3014 import.resolution = .__wasm_init_tls;
3015 wasm.functions.putAssumeCapacity(.__wasm_init_tls, {});
3010 try wasm.resolveFunctionSynthetic(import, .__wasm_init_tls, &.{.i32}, &.{});
30163011 } else {
30173012 try wasm.function_imports.put(gpa, name, .fromObject(func_index, wasm));
30183013 }
......@@ -3022,7 +3017,7 @@ fn markFunctionImport(
30223017}
30233018
30243019/// Recursively mark alive everything referenced by the function.
3025fn markFunction(wasm: *Wasm, i: ObjectFunctionIndex) Allocator.Error!void {
3020fn markFunction(wasm: *Wasm, i: ObjectFunctionIndex) link.File.FlushError!void {
30263021 const comp = wasm.base.comp;
30273022 const gpa = comp.gpa;
30283023 const gop = try wasm.functions.getOrPut(gpa, .fromObjectFunction(wasm, i));
......@@ -3046,7 +3041,7 @@ fn markGlobalImport(
30463041 name: String,
30473042 import: *GlobalImport,
30483043 global_index: GlobalImport.Index,
3049) !void {
3044) link.File.FlushError!void {
30503045 if (import.flags.alive) return;
30513046 import.flags.alive = true;
30523047
......@@ -3082,7 +3077,7 @@ fn markGlobalImport(
30823077 }
30833078}
30843079
3085fn markGlobal(wasm: *Wasm, i: ObjectGlobalIndex) Allocator.Error!void {
3080fn markGlobal(wasm: *Wasm, i: ObjectGlobalIndex) link.File.FlushError!void {
30863081 const comp = wasm.base.comp;
30873082 const gpa = comp.gpa;
30883083 const gop = try wasm.globals.getOrPut(gpa, .fromObjectGlobal(wasm, i));
......@@ -3105,7 +3100,7 @@ fn markTableImport(
31053100 name: String,
31063101 import: *TableImport,
31073102 table_index: TableImport.Index,
3108) !void {
3103) link.File.FlushError!void {
31093104 if (import.flags.alive) return;
31103105 import.flags.alive = true;
31113106
......@@ -3127,7 +3122,7 @@ fn markTableImport(
31273122 }
31283123}
31293124
3130fn markDataSegment(wasm: *Wasm, segment_index: ObjectDataSegment.Index) Allocator.Error!void {
3125fn markDataSegment(wasm: *Wasm, segment_index: ObjectDataSegment.Index) link.File.FlushError!void {
31313126 const segment = segment_index.ptr(wasm);
31323127 if (segment.flags.alive) return;
31333128 segment.flags.alive = true;
......@@ -3135,7 +3130,7 @@ fn markDataSegment(wasm: *Wasm, segment_index: ObjectDataSegment.Index) Allocato
31353130 try wasm.markRelocations(segment.relocations(wasm));
31363131}
31373132
3138fn markRelocations(wasm: *Wasm, relocs: ObjectRelocation.IterableSlice) Allocator.Error!void {
3133fn markRelocations(wasm: *Wasm, relocs: ObjectRelocation.IterableSlice) link.File.FlushError!void {
31393134 for (relocs.slice.tags(wasm), relocs.slice.pointees(wasm), relocs.slice.offsets(wasm)) |tag, *pointee, offset| {
31403135 if (offset >= relocs.end) break;
31413136 switch (tag) {
......@@ -3751,7 +3746,7 @@ pub fn internValtypeList(wasm: *Wasm, valtype_list: []const std.wasm.Valtype) Al
37513746 return .fromString(try internString(wasm, @ptrCast(valtype_list)));
37523747}
37533748
3754pub fn getExistingValtypeList(wasm: *Wasm, valtype_list: []const std.wasm.Valtype) ?ValtypeList {
3749pub fn getExistingValtypeList(wasm: *const Wasm, valtype_list: []const std.wasm.Valtype) ?ValtypeList {
37553750 return .fromString(getExistingString(wasm, @ptrCast(valtype_list)) orelse return null);
37563751}
37573752
......@@ -3766,6 +3761,13 @@ pub fn getExistingFuncType(wasm: *const Wasm, ft: FunctionType) ?FunctionType.In
37663761 return @enumFromInt(index);
37673762}
37683763
3764pub fn getExistingFuncType2(wasm: *const Wasm, params: []const std.wasm.Valtype, returns: []const std.wasm.Valtype) FunctionType.Index {
3765 return getExistingFuncType(wasm, .{
3766 .params = getExistingValtypeList(wasm, params).?,
3767 .returns = getExistingValtypeList(wasm, returns).?,
3768 }).?;
3769}
3770
37693771pub fn internFunctionType(
37703772 wasm: *Wasm,
37713773 cc: std.builtin.CallingConvention,
......@@ -4080,3 +4082,26 @@ fn addZcuImportReserved(wasm: *Wasm, nav_index: InternPool.Nav.Index) ZcuImportI
40804082 gop.value_ptr.* = {};
40814083 return @enumFromInt(gop.index);
40824084}
4085
4086fn resolveFunctionSynthetic(
4087 wasm: *Wasm,
4088 import: *FunctionImport,
4089 res: FunctionImport.Resolution,
4090 params: []const std.wasm.Valtype,
4091 returns: []const std.wasm.Valtype,
4092) link.File.FlushError!void {
4093 import.resolution = res;
4094 wasm.functions.putAssumeCapacity(res, {});
4095 // This is not only used for type-checking but also ensures the function
4096 // type index is interned so that it is guaranteed to exist during `flush`.
4097 const correct_func_type = try addFuncType(wasm, .{
4098 .params = try internValtypeList(wasm, params),
4099 .returns = try internValtypeList(wasm, returns),
4100 });
4101 if (import.type != correct_func_type) {
4102 const diags = &wasm.base.comp.link_diags;
4103 return import.source_location.fail(diags, "synthetic function {s} {} imported with incorrect signature {}", .{
4104 @tagName(res), correct_func_type.fmt(wasm), import.type.fmt(wasm),
4105 });
4106 }
4107}
src/link/Wasm/Flush.zig-1
......@@ -682,7 +682,6 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
682682 .__wasm_call_ctors => @panic("TODO lower __wasm_call_ctors"),
683683 .__wasm_init_memory => @panic("TODO lower __wasm_init_memory "),
684684 .__wasm_init_tls => @panic("TODO lower __wasm_init_tls "),
685 .__zig_error_names => @panic("TODO lower __zig_error_names "),
686685 .object_function => |i| {
687686 _ = i;
688687 @panic("TODO lower object function code and apply relocations");