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 {...@@ -214,22 +214,35 @@ pub const Diags = struct {
214 return error.LinkFailure;214 return error.LinkFailure;
215 }215 }
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
217 pub fn addError(diags: *Diags, comptime format: []const u8, args: anytype) void {223 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 {
218 @branchHint(.cold);228 @branchHint(.cold);
219 const gpa = diags.gpa;229 const gpa = diags.gpa;
220 const eu_main_msg = std.fmt.allocPrint(gpa, format, args);230 const eu_main_msg = std.fmt.allocPrint(gpa, format, args);
221 diags.mutex.lock();231 diags.mutex.lock();
222 defer diags.mutex.unlock();232 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) {
224 error.OutOfMemory => diags.setAllocFailureLocked(),234 error.OutOfMemory => diags.setAllocFailureLocked(),
225 };235 };
226 }236 }
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 {
229 const gpa = diags.gpa;239 const gpa = diags.gpa;
230 const main_msg = try eu_main_msg;240 const main_msg = try eu_main_msg;
231 errdefer gpa.free(main_msg);241 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 });
233 }246 }
234247
235 pub fn addErrorWithNotes(diags: *Diags, note_count: usize) error{OutOfMemory}!ErrorWithNotes {248 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) {...@@ -474,6 +474,10 @@ pub const SourceLocation = enum(u32) {
474 err_msg.notes[err.note_slot - 1].source_location = .{ .wasm = sl };474 err_msg.notes[err.note_slot - 1].source_location = .{ .wasm = sl };
475 }475 }
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
477 pub fn string(481 pub fn string(
478 sl: SourceLocation,482 sl: SourceLocation,
479 msg: []const u8,483 msg: []const u8,
...@@ -881,12 +885,11 @@ pub const FunctionImport = extern struct {...@@ -881,12 +885,11 @@ pub const FunctionImport = extern struct {
881 __wasm_call_ctors,885 __wasm_call_ctors,
882 __wasm_init_memory,886 __wasm_init_memory,
883 __wasm_init_tls,887 __wasm_init_tls,
884 __zig_error_names,
885 // Next, index into `object_functions`.888 // Next, index into `object_functions`.
886 // Next, index into `zcu_funcs`.889 // Next, index into `zcu_funcs`.
887 _,890 _,
888891
889 const first_object_function = @intFromEnum(Resolution.__zig_error_names) + 1;892 const first_object_function = @intFromEnum(Resolution.__wasm_init_tls) + 1;
890893
891 pub const Unpacked = union(enum) {894 pub const Unpacked = union(enum) {
892 unresolved,895 unresolved,
...@@ -894,7 +897,6 @@ pub const FunctionImport = extern struct {...@@ -894,7 +897,6 @@ pub const FunctionImport = extern struct {
894 __wasm_call_ctors,897 __wasm_call_ctors,
895 __wasm_init_memory,898 __wasm_init_memory,
896 __wasm_init_tls,899 __wasm_init_tls,
897 __zig_error_names,
898 object_function: ObjectFunctionIndex,900 object_function: ObjectFunctionIndex,
899 zcu_func: ZcuFunc.Index,901 zcu_func: ZcuFunc.Index,
900 };902 };
...@@ -906,7 +908,6 @@ pub const FunctionImport = extern struct {...@@ -906,7 +908,6 @@ pub const FunctionImport = extern struct {
906 .__wasm_call_ctors => .__wasm_call_ctors,908 .__wasm_call_ctors => .__wasm_call_ctors,
907 .__wasm_init_memory => .__wasm_init_memory,909 .__wasm_init_memory => .__wasm_init_memory,
908 .__wasm_init_tls => .__wasm_init_tls,910 .__wasm_init_tls => .__wasm_init_tls,
909 .__zig_error_names => .__zig_error_names,
910 _ => {911 _ => {
911 const object_function_index = @intFromEnum(r) - first_object_function;912 const object_function_index = @intFromEnum(r) - first_object_function;
912913
...@@ -927,7 +928,6 @@ pub const FunctionImport = extern struct {...@@ -927,7 +928,6 @@ pub const FunctionImport = extern struct {
927 .__wasm_call_ctors => .__wasm_call_ctors,928 .__wasm_call_ctors => .__wasm_call_ctors,
928 .__wasm_init_memory => .__wasm_init_memory,929 .__wasm_init_memory => .__wasm_init_memory,
929 .__wasm_init_tls => .__wasm_init_tls,930 .__wasm_init_tls => .__wasm_init_tls,
930 .__zig_error_names => .__zig_error_names,
931 .object_function => |i| @enumFromInt(first_object_function + @intFromEnum(i)),931 .object_function => |i| @enumFromInt(first_object_function + @intFromEnum(i)),
932 .zcu_func => |i| @enumFromInt(first_object_function + wasm.object_functions.items.len + @intFromEnum(i)),932 .zcu_func => |i| @enumFromInt(first_object_function + wasm.object_functions.items.len + @intFromEnum(i)),
933 };933 };
...@@ -957,11 +957,11 @@ pub const FunctionImport = extern struct {...@@ -957,11 +957,11 @@ pub const FunctionImport = extern struct {
957 pub fn typeIndex(r: Resolution, wasm: *Wasm) FunctionType.Index {957 pub fn typeIndex(r: Resolution, wasm: *Wasm) FunctionType.Index {
958 return switch (unpack(r, wasm)) {958 return switch (unpack(r, wasm)) {
959 .unresolved => unreachable,959 .unresolved => unreachable,
960 .__wasm_apply_global_tls_relocs => @panic("TODO"),960 .__wasm_apply_global_tls_relocs,
961 .__wasm_call_ctors => @panic("TODO"),961 .__wasm_call_ctors,
962 .__wasm_init_memory => @panic("TODO"),962 .__wasm_init_memory,
963 .__wasm_init_tls => @panic("TODO"),963 => getExistingFuncType2(wasm, &.{}, &.{}),
964 .__zig_error_names => @panic("TODO"),964 .__wasm_init_tls => getExistingFuncType2(wasm, &.{.i32}, &.{}),
965 .object_function => |i| i.ptr(wasm).type_index,965 .object_function => |i| i.ptr(wasm).type_index,
966 .zcu_func => |i| i.typeIndex(wasm).?,966 .zcu_func => |i| i.typeIndex(wasm).?,
967 };967 };
...@@ -974,7 +974,6 @@ pub const FunctionImport = extern struct {...@@ -974,7 +974,6 @@ pub const FunctionImport = extern struct {
974 .__wasm_call_ctors => @tagName(Unpacked.__wasm_call_ctors),974 .__wasm_call_ctors => @tagName(Unpacked.__wasm_call_ctors),
975 .__wasm_init_memory => @tagName(Unpacked.__wasm_init_memory),975 .__wasm_init_memory => @tagName(Unpacked.__wasm_init_memory),
976 .__wasm_init_tls => @tagName(Unpacked.__wasm_init_tls),976 .__wasm_init_tls => @tagName(Unpacked.__wasm_init_tls),
977 .__zig_error_names => @tagName(Unpacked.__zig_error_names),
978 .object_function => |i| i.ptr(wasm).name.slice(wasm),977 .object_function => |i| i.ptr(wasm).name.slice(wasm),
979 .zcu_func => |i| i.name(wasm),978 .zcu_func => |i| i.name(wasm),
980 };979 };
...@@ -2991,7 +2990,7 @@ fn markFunctionImport(...@@ -2991,7 +2990,7 @@ fn markFunctionImport(
2991 name: String,2990 name: String,
2992 import: *FunctionImport,2991 import: *FunctionImport,
2993 func_index: FunctionImport.Index,2992 func_index: FunctionImport.Index,
2994) Allocator.Error!void {2993) link.File.FlushError!void {
2995 if (import.flags.alive) return;2994 if (import.flags.alive) return;
2996 import.flags.alive = true;2995 import.flags.alive = true;
29972996
...@@ -3002,17 +3001,13 @@ fn markFunctionImport(...@@ -3002,17 +3001,13 @@ fn markFunctionImport(
30023001
3003 if (import.resolution == .unresolved) {3002 if (import.resolution == .unresolved) {
3004 if (name == wasm.preloaded_strings.__wasm_init_memory) {3003 if (name == wasm.preloaded_strings.__wasm_init_memory) {
3005 import.resolution = .__wasm_init_memory;3004 try wasm.resolveFunctionSynthetic(import, .__wasm_init_memory, &.{}, &.{});
3006 wasm.functions.putAssumeCapacity(.__wasm_init_memory, {});
3007 } else if (name == wasm.preloaded_strings.__wasm_apply_global_tls_relocs) {3005 } else if (name == wasm.preloaded_strings.__wasm_apply_global_tls_relocs) {
3008 import.resolution = .__wasm_apply_global_tls_relocs;3006 try wasm.resolveFunctionSynthetic(import, .__wasm_apply_global_tls_relocs, &.{}, &.{});
3009 wasm.functions.putAssumeCapacity(.__wasm_apply_global_tls_relocs, {});
3010 } else if (name == wasm.preloaded_strings.__wasm_call_ctors) {3007 } else if (name == wasm.preloaded_strings.__wasm_call_ctors) {
3011 import.resolution = .__wasm_call_ctors;3008 try wasm.resolveFunctionSynthetic(import, .__wasm_call_ctors, &.{}, &.{});
3012 wasm.functions.putAssumeCapacity(.__wasm_call_ctors, {});
3013 } else if (name == wasm.preloaded_strings.__wasm_init_tls) {3009 } else if (name == wasm.preloaded_strings.__wasm_init_tls) {
3014 import.resolution = .__wasm_init_tls;3010 try wasm.resolveFunctionSynthetic(import, .__wasm_init_tls, &.{.i32}, &.{});
3015 wasm.functions.putAssumeCapacity(.__wasm_init_tls, {});
3016 } else {3011 } else {
3017 try wasm.function_imports.put(gpa, name, .fromObject(func_index, wasm));3012 try wasm.function_imports.put(gpa, name, .fromObject(func_index, wasm));
3018 }3013 }
...@@ -3022,7 +3017,7 @@ fn markFunctionImport(...@@ -3022,7 +3017,7 @@ fn markFunctionImport(
3022}3017}
30233018
3024/// Recursively mark alive everything referenced by the function.3019/// 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 {
3026 const comp = wasm.base.comp;3021 const comp = wasm.base.comp;
3027 const gpa = comp.gpa;3022 const gpa = comp.gpa;
3028 const gop = try wasm.functions.getOrPut(gpa, .fromObjectFunction(wasm, i));3023 const gop = try wasm.functions.getOrPut(gpa, .fromObjectFunction(wasm, i));
...@@ -3046,7 +3041,7 @@ fn markGlobalImport(...@@ -3046,7 +3041,7 @@ fn markGlobalImport(
3046 name: String,3041 name: String,
3047 import: *GlobalImport,3042 import: *GlobalImport,
3048 global_index: GlobalImport.Index,3043 global_index: GlobalImport.Index,
3049) !void {3044) link.File.FlushError!void {
3050 if (import.flags.alive) return;3045 if (import.flags.alive) return;
3051 import.flags.alive = true;3046 import.flags.alive = true;
30523047
...@@ -3082,7 +3077,7 @@ fn markGlobalImport(...@@ -3082,7 +3077,7 @@ fn markGlobalImport(
3082 }3077 }
3083}3078}
30843079
3085fn markGlobal(wasm: *Wasm, i: ObjectGlobalIndex) Allocator.Error!void {3080fn markGlobal(wasm: *Wasm, i: ObjectGlobalIndex) link.File.FlushError!void {
3086 const comp = wasm.base.comp;3081 const comp = wasm.base.comp;
3087 const gpa = comp.gpa;3082 const gpa = comp.gpa;
3088 const gop = try wasm.globals.getOrPut(gpa, .fromObjectGlobal(wasm, i));3083 const gop = try wasm.globals.getOrPut(gpa, .fromObjectGlobal(wasm, i));
...@@ -3105,7 +3100,7 @@ fn markTableImport(...@@ -3105,7 +3100,7 @@ fn markTableImport(
3105 name: String,3100 name: String,
3106 import: *TableImport,3101 import: *TableImport,
3107 table_index: TableImport.Index,3102 table_index: TableImport.Index,
3108) !void {3103) link.File.FlushError!void {
3109 if (import.flags.alive) return;3104 if (import.flags.alive) return;
3110 import.flags.alive = true;3105 import.flags.alive = true;
31113106
...@@ -3127,7 +3122,7 @@ fn markTableImport(...@@ -3127,7 +3122,7 @@ fn markTableImport(
3127 }3122 }
3128}3123}
31293124
3130fn markDataSegment(wasm: *Wasm, segment_index: ObjectDataSegment.Index) Allocator.Error!void {3125fn markDataSegment(wasm: *Wasm, segment_index: ObjectDataSegment.Index) link.File.FlushError!void {
3131 const segment = segment_index.ptr(wasm);3126 const segment = segment_index.ptr(wasm);
3132 if (segment.flags.alive) return;3127 if (segment.flags.alive) return;
3133 segment.flags.alive = true;3128 segment.flags.alive = true;
...@@ -3135,7 +3130,7 @@ fn markDataSegment(wasm: *Wasm, segment_index: ObjectDataSegment.Index) Allocato...@@ -3135,7 +3130,7 @@ fn markDataSegment(wasm: *Wasm, segment_index: ObjectDataSegment.Index) Allocato
3135 try wasm.markRelocations(segment.relocations(wasm));3130 try wasm.markRelocations(segment.relocations(wasm));
3136}3131}
31373132
3138fn markRelocations(wasm: *Wasm, relocs: ObjectRelocation.IterableSlice) Allocator.Error!void {3133fn markRelocations(wasm: *Wasm, relocs: ObjectRelocation.IterableSlice) link.File.FlushError!void {
3139 for (relocs.slice.tags(wasm), relocs.slice.pointees(wasm), relocs.slice.offsets(wasm)) |tag, *pointee, offset| {3134 for (relocs.slice.tags(wasm), relocs.slice.pointees(wasm), relocs.slice.offsets(wasm)) |tag, *pointee, offset| {
3140 if (offset >= relocs.end) break;3135 if (offset >= relocs.end) break;
3141 switch (tag) {3136 switch (tag) {
...@@ -3751,7 +3746,7 @@ pub fn internValtypeList(wasm: *Wasm, valtype_list: []const std.wasm.Valtype) Al...@@ -3751,7 +3746,7 @@ pub fn internValtypeList(wasm: *Wasm, valtype_list: []const std.wasm.Valtype) Al
3751 return .fromString(try internString(wasm, @ptrCast(valtype_list)));3746 return .fromString(try internString(wasm, @ptrCast(valtype_list)));
3752}3747}
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 {
3755 return .fromString(getExistingString(wasm, @ptrCast(valtype_list)) orelse return null);3750 return .fromString(getExistingString(wasm, @ptrCast(valtype_list)) orelse return null);
3756}3751}
37573752
...@@ -3766,6 +3761,13 @@ pub fn getExistingFuncType(wasm: *const Wasm, ft: FunctionType) ?FunctionType.In...@@ -3766,6 +3761,13 @@ pub fn getExistingFuncType(wasm: *const Wasm, ft: FunctionType) ?FunctionType.In
3766 return @enumFromInt(index);3761 return @enumFromInt(index);
3767}3762}
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
3769pub fn internFunctionType(3771pub fn internFunctionType(
3770 wasm: *Wasm,3772 wasm: *Wasm,
3771 cc: std.builtin.CallingConvention,3773 cc: std.builtin.CallingConvention,
...@@ -4080,3 +4082,26 @@ fn addZcuImportReserved(wasm: *Wasm, nav_index: InternPool.Nav.Index) ZcuImportI...@@ -4080,3 +4082,26 @@ fn addZcuImportReserved(wasm: *Wasm, nav_index: InternPool.Nav.Index) ZcuImportI
4080 gop.value_ptr.* = {};4082 gop.value_ptr.* = {};
4081 return @enumFromInt(gop.index);4083 return @enumFromInt(gop.index);
4082}4084}
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 {...@@ -682,7 +682,6 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
682 .__wasm_call_ctors => @panic("TODO lower __wasm_call_ctors"),682 .__wasm_call_ctors => @panic("TODO lower __wasm_call_ctors"),
683 .__wasm_init_memory => @panic("TODO lower __wasm_init_memory "),683 .__wasm_init_memory => @panic("TODO lower __wasm_init_memory "),
684 .__wasm_init_tls => @panic("TODO lower __wasm_init_tls "),684 .__wasm_init_tls => @panic("TODO lower __wasm_init_tls "),
685 .__zig_error_names => @panic("TODO lower __zig_error_names "),
686 .object_function => |i| {685 .object_function => |i| {
687 _ = i;686 _ = i;
688 @panic("TODO lower object function code and apply relocations");687 @panic("TODO lower object function code and apply relocations");