| author | |
| committer | |
| log | 619159cf48e953ca65933391313a72c392007710 |
| tree | 315cb12cff807374cd8fbbad3c06107241633565 |
| parent | a32d3a85d21d614e5960b9eadcd85374954b910f |
* add TypedValue.Managed which represents a Type, a Value, and some
kind of memory management strategy.
* introduce an analysis queue
* flesh out how incremental compilation works with respect to exports
* ir.text.Module is only capable of one error message during parsing
* link.zig no longer has a decl table map and instead has structs that
exist directly on ir.Module.Decl and ir.Module.Export
* implement primitive .text block allocation
* implement linker code for updating Decls and Exports
* implement null Type
Some supporting std lib changes:
* add std.ArrayList.appendSliceAssumeCapacity
* add std.fs.File.copyRange and copyRangeAll
* fix std.HashMap having modification safety on in ReleaseSmall builds
* add std.HashMap.putAssumeCapacityNoClobber9 files changed, 651 insertions(+), 276 deletions(-)
lib/std/array_list.zig+14-3| ... | @@ -149,10 +149,15 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -149,10 +149,15 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 149 | /// Append the slice of items to the list. Allocates more | 149 | /// Append the slice of items to the list. Allocates more |
| 150 | /// memory as necessary. | 150 | /// memory as necessary. |
| 151 | pub fn appendSlice(self: *Self, items: SliceConst) !void { | 151 | pub fn appendSlice(self: *Self, items: SliceConst) !void { |
| 152 | try self.ensureCapacity(self.items.len + items.len); | ||
| 153 | self.appendSliceAssumeCapacity(items); | ||
| 154 | } | ||
| 155 | |||
| 156 | /// Append the slice of items to the list, asserting the capacity is already | ||
| 157 | /// enough to store the new items. | ||
| 158 | pub fn appendSliceAssumeCapacity(self: *Self, items: SliceConst) void { | ||
| 152 | const oldlen = self.items.len; | 159 | const oldlen = self.items.len; |
| 153 | const newlen = self.items.len + items.len; | 160 | const newlen = self.items.len + items.len; |
| 154 | |||
| 155 | try self.ensureCapacity(newlen); | ||
| 156 | self.items.len = newlen; | 161 | self.items.len = newlen; |
| 157 | mem.copy(T, self.items[oldlen..], items); | 162 | mem.copy(T, self.items[oldlen..], items); |
| 158 | } | 163 | } |
| ... | @@ -378,10 +383,16 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -378,10 +383,16 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 378 | /// Append the slice of items to the list. Allocates more | 383 | /// Append the slice of items to the list. Allocates more |
| 379 | /// memory as necessary. | 384 | /// memory as necessary. |
| 380 | pub fn appendSlice(self: *Self, allocator: *Allocator, items: SliceConst) !void { | 385 | pub fn appendSlice(self: *Self, allocator: *Allocator, items: SliceConst) !void { |
| 386 | try self.ensureCapacity(allocator, self.items.len + items.len); | ||
| 387 | self.appendSliceAssumeCapacity(items); | ||
| 388 | } | ||
| 389 | |||
| 390 | /// Append the slice of items to the list, asserting the capacity is enough | ||
| 391 | /// to store the new items. | ||
| 392 | pub fn appendSliceAssumeCapacity(self: *Self, items: SliceConst) void { | ||
| 381 | const oldlen = self.items.len; | 393 | const oldlen = self.items.len; |
| 382 | const newlen = self.items.len + items.len; | 394 | const newlen = self.items.len + items.len; |
| 383 | 395 | ||
| 384 | try self.ensureCapacity(allocator, newlen); | ||
| 385 | self.items.len = newlen; | 396 | self.items.len = newlen; |
| 386 | mem.copy(T, self.items[oldlen..], items); | 397 | mem.copy(T, self.items[oldlen..], items); |
| 387 | } | 398 | } |
lib/std/fs/file.zig+24| ... | @@ -527,6 +527,30 @@ pub const File = struct { | ... | @@ -527,6 +527,30 @@ pub const File = struct { |
| 527 | } | 527 | } |
| 528 | } | 528 | } |
| 529 | 529 | ||
| 530 | pub fn copyRange(in: File, in_offset: u64, out: File, out_offset: u64, len: usize) PWriteError!usize { | ||
| 531 | // TODO take advantage of copy_file_range OS APIs | ||
| 532 | var buf: [8 * 4096]u8 = undefined; | ||
| 533 | const adjusted_count = math.min(buf.len, len); | ||
| 534 | const amt_read = try in.pread(buf[0..adjusted_count], in_offset); | ||
| 535 | if (amt_read == 0) return 0; | ||
| 536 | return out.pwrite(buf[0..amt_read], out_offset); | ||
| 537 | } | ||
| 538 | |||
| 539 | /// Returns the number of bytes copied. If the number read is smaller than `buffer.len`, it | ||
| 540 | /// means the in file reached the end. Reaching the end of a file is not an error condition. | ||
| 541 | pub fn copyRangeAll(in: File, in_offset: u64, out: File, out_offset: u64, len: usize) PWriteError!usize { | ||
| 542 | var total_bytes_copied = 0; | ||
| 543 | var in_off = in_offset; | ||
| 544 | var out_off = out_offset; | ||
| 545 | while (total_bytes_copied < len) { | ||
| 546 | const amt_copied = try copyRange(in, in_off, out, out_off, len - total_bytes_copied); | ||
| 547 | if (amt_copied == 0) return total_bytes_copied; | ||
| 548 | total_bytes_copied += amt_copied; | ||
| 549 | in_off += amt_copied; | ||
| 550 | out_off += amt_copied; | ||
| 551 | } | ||
| 552 | } | ||
| 553 | |||
| 530 | pub const WriteFileOptions = struct { | 554 | pub const WriteFileOptions = struct { |
| 531 | in_offset: u64 = 0, | 555 | in_offset: u64 = 0, |
| 532 | 556 |
lib/std/hash_map.zig+5-1| ... | @@ -10,7 +10,7 @@ const Wyhash = std.hash.Wyhash; | ... | @@ -10,7 +10,7 @@ const Wyhash = std.hash.Wyhash; |
| 10 | const Allocator = mem.Allocator; | 10 | const Allocator = mem.Allocator; |
| 11 | const builtin = @import("builtin"); | 11 | const builtin = @import("builtin"); |
| 12 | 12 | ||
| 13 | const want_modification_safety = builtin.mode != .ReleaseFast; | 13 | const want_modification_safety = std.debug.runtime_safety; |
| 14 | const debug_u32 = if (want_modification_safety) u32 else void; | 14 | const debug_u32 = if (want_modification_safety) u32 else void; |
| 15 | 15 | ||
| 16 | pub fn AutoHashMap(comptime K: type, comptime V: type) type { | 16 | pub fn AutoHashMap(comptime K: type, comptime V: type) type { |
| ... | @@ -219,6 +219,10 @@ pub fn HashMap(comptime K: type, comptime V: type, comptime hash: fn (key: K) u3 | ... | @@ -219,6 +219,10 @@ pub fn HashMap(comptime K: type, comptime V: type, comptime hash: fn (key: K) u3 |
| 219 | return put_result.old_kv; | 219 | return put_result.old_kv; |
| 220 | } | 220 | } |
| 221 | 221 | ||
| 222 | pub fn putAssumeCapacityNoClobber(self: *Self, key: K, value: V) void { | ||
| 223 | assert(self.putAssumeCapacity(key, value) == null); | ||
| 224 | } | ||
| 225 | |||
| 222 | pub fn get(hm: *const Self, key: K) ?*KV { | 226 | pub fn get(hm: *const Self, key: K) ?*KV { |
| 223 | if (hm.entries.len == 0) { | 227 | if (hm.entries.len == 0) { |
| 224 | return null; | 228 | return null; |
src-self-hosted/TypedValue.zig created+23| ... | @@ -0,0 +1,23 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const Type = @import("type.zig").Type; | ||
| 3 | const Value = @import("value.zig").Value; | ||
| 4 | const Allocator = std.mem.Allocator; | ||
| 5 | const TypedValue = @This(); | ||
| 6 | |||
| 7 | ty: Type, | ||
| 8 | val: Value, | ||
| 9 | |||
| 10 | /// Memory management for TypedValue. The main purpose of this type | ||
| 11 | /// is to be small and have a deinit() function to free associated resources. | ||
| 12 | pub const Managed = struct { | ||
| 13 | /// If the tag value is less than Tag.no_payload_count, then no pointer | ||
| 14 | /// dereference is needed. | ||
| 15 | typed_value: TypedValue, | ||
| 16 | /// If this is `null` then there is no memory management needed. | ||
| 17 | arena: ?*std.heap.ArenaAllocator.State = null, | ||
| 18 | |||
| 19 | pub fn deinit(self: *ManagedTypedValue, allocator: *Allocator) void { | ||
| 20 | if (self.arena) |a| a.promote(allocator).deinit(); | ||
| 21 | self.* = undefined; | ||
| 22 | } | ||
| 23 | }; | ||
src-self-hosted/ir.zig+320-132| ... | @@ -5,6 +5,7 @@ const ArrayListUnmanaged = std.ArrayListUnmanaged; | ... | @@ -5,6 +5,7 @@ const ArrayListUnmanaged = std.ArrayListUnmanaged; |
| 5 | const LinkedList = std.TailQueue; | 5 | const LinkedList = std.TailQueue; |
| 6 | const Value = @import("value.zig").Value; | 6 | const Value = @import("value.zig").Value; |
| 7 | const Type = @import("type.zig").Type; | 7 | const Type = @import("type.zig").Type; |
| 8 | const TypedValue = @import("TypedValue.zig"); | ||
| 8 | const assert = std.debug.assert; | 9 | const assert = std.debug.assert; |
| 9 | const BigIntConst = std.math.big.int.Const; | 10 | const BigIntConst = std.math.big.int.Const; |
| 10 | const BigIntMutable = std.math.big.int.Mutable; | 11 | const BigIntMutable = std.math.big.int.Mutable; |
| ... | @@ -167,11 +168,6 @@ pub const Inst = struct { | ... | @@ -167,11 +168,6 @@ pub const Inst = struct { |
| 167 | }; | 168 | }; |
| 168 | }; | 169 | }; |
| 169 | 170 | ||
| 170 | pub const TypedValue = struct { | ||
| 171 | ty: Type, | ||
| 172 | val: Value, | ||
| 173 | }; | ||
| 174 | |||
| 175 | fn swapRemoveElem(allocator: *Allocator, comptime T: type, item: T, list: *ArrayListUnmanaged(T)) void { | 171 | fn swapRemoveElem(allocator: *Allocator, comptime T: type, item: T, list: *ArrayListUnmanaged(T)) void { |
| 176 | var i: usize = 0; | 172 | var i: usize = 0; |
| 177 | while (i < list.items.len) { | 173 | while (i < list.items.len) { |
| ... | @@ -192,46 +188,125 @@ pub const Module = struct { | ... | @@ -192,46 +188,125 @@ pub const Module = struct { |
| 192 | root_scope: *Scope.ZIRModule, | 188 | root_scope: *Scope.ZIRModule, |
| 193 | /// Pointer to externally managed resource. | 189 | /// Pointer to externally managed resource. |
| 194 | bin_file: *link.ElfFile, | 190 | bin_file: *link.ElfFile, |
| 195 | failed_decls: ArrayListUnmanaged(*Decl) = .{}, | 191 | /// It's rare for a decl to be exported, so we save memory by having a sparse map of |
| 196 | failed_fns: ArrayListUnmanaged(*Fn) = .{}, | 192 | /// Decl pointers to details about them being exported. |
| 197 | failed_files: ArrayListUnmanaged(*Scope.ZIRModule) = .{}, | 193 | /// The Export memory is owned by the `export_owners` table; the slice itself is owned by this table. |
| 194 | decl_exports: std.AutoHashMap(*Decl, []*Export), | ||
| 195 | /// This models the Decls that perform exports, so that `decl_exports` can be updated when a Decl | ||
| 196 | /// is modified. Note that the key of this table is not the Decl being exported, but the Decl that | ||
| 197 | /// is performing the export of another Decl. | ||
| 198 | /// This table owns the Export memory. | ||
| 199 | export_owners: std.AutoHashMap(*Decl, []*Export), | ||
| 200 | /// Maps fully qualified namespaced names to the Decl struct for them. | ||
| 198 | decl_table: std.AutoHashMap(Decl.Hash, *Decl), | 201 | decl_table: std.AutoHashMap(Decl.Hash, *Decl), |
| 202 | |||
| 199 | optimize_mode: std.builtin.Mode, | 203 | optimize_mode: std.builtin.Mode, |
| 200 | link_error_flags: link.ElfFile.ErrorFlags = .{}, | 204 | link_error_flags: link.ElfFile.ErrorFlags = .{}, |
| 201 | 205 | ||
| 206 | /// We optimize memory usage for a compilation with no compile errors by storing the | ||
| 207 | /// error messages and mapping outside of `Decl`. | ||
| 208 | /// The ErrorMsg memory is owned by the decl, using Module's allocator. | ||
| 209 | failed_decls: std.AutoHashMap(*Decl, *ErrorMsg), | ||
| 210 | /// We optimize memory usage for a compilation with no compile errors by storing the | ||
| 211 | /// error messages and mapping outside of `Fn`. | ||
| 212 | /// The ErrorMsg memory is owned by the `Fn`, using Module's allocator. | ||
| 213 | failed_fns: std.AutoHashMap(*Fn, *ErrorMsg), | ||
| 214 | /// Using a map here for consistency with the other fields here. | ||
| 215 | /// The ErrorMsg memory is owned by the `Scope.ZIRModule`, using Module's allocator. | ||
| 216 | failed_files: std.AutoHashMap(*Scope.ZIRModule, *ErrorMsg), | ||
| 217 | /// Using a map here for consistency with the other fields here. | ||
| 218 | /// The ErrorMsg memory is owned by the `Export`, using Module's allocator. | ||
| 219 | failed_exports: std.AutoHashMap(*Export, *ErrorMsg), | ||
| 220 | |||
| 221 | pub const Export = struct { | ||
| 222 | options: std.builtin.ExportOptions, | ||
| 223 | /// Byte offset into the file that contains the export directive. | ||
| 224 | src: usize, | ||
| 225 | /// Represents the position of the export, if any, in the output file. | ||
| 226 | link: link.ElfFile.Export, | ||
| 227 | /// The Decl that performs the export. Note that this is *not* the Decl being exported. | ||
| 228 | owner_decl: *Decl, | ||
| 229 | status: enum { in_progress, failed, complete }, | ||
| 230 | }; | ||
| 231 | |||
| 202 | pub const Decl = struct { | 232 | pub const Decl = struct { |
| 203 | /// Contains the memory for `typed_value` and this `Decl` itself. | ||
| 204 | /// If the Decl is a function, also contains that memory. | ||
| 205 | /// If the decl has any export nodes, also contains that memory. | ||
| 206 | /// TODO look into using a more memory efficient arena that will cost less bytes per decl. | ||
| 207 | /// This one has a minimum allocation of 4096 bytes. | ||
| 208 | arena: std.heap.ArenaAllocator.State, | ||
| 209 | /// This name is relative to the containing namespace of the decl. It uses a null-termination | 233 | /// This name is relative to the containing namespace of the decl. It uses a null-termination |
| 210 | /// to save bytes, since there can be a lot of decls in a compilation. The null byte is not allowed | 234 | /// to save bytes, since there can be a lot of decls in a compilation. The null byte is not allowed |
| 211 | /// in symbol names, because executable file formats use null-terminated strings for symbol names. | 235 | /// in symbol names, because executable file formats use null-terminated strings for symbol names. |
| 236 | /// All Decls have names, even values that are not bound to a zig namespace. This is necessary for | ||
| 237 | /// mapping them to an address in the output file. | ||
| 238 | /// Memory owned by this decl, using Module's allocator. | ||
| 212 | name: [*:0]const u8, | 239 | name: [*:0]const u8, |
| 213 | /// It's rare for a decl to be exported, and it's even rarer for a decl to be mapped to more | 240 | /// The direct parent container of the Decl. This field will need to get more fleshed out when |
| 214 | /// than one export, so we use a linked list to save memory. | 241 | /// self-hosted supports proper struct types and Zig AST => ZIR. |
| 215 | export_node: ?*LinkedList(std.builtin.ExportOptions).Node = null, | 242 | /// Reference to externally owned memory. |
| 243 | scope: *Scope.ZIRModule, | ||
| 216 | /// Byte offset into the source file that contains this declaration. | 244 | /// Byte offset into the source file that contains this declaration. |
| 217 | /// This is the base offset that src offsets within this Decl are relative to. | 245 | /// This is the base offset that src offsets within this Decl are relative to. |
| 218 | src: usize, | 246 | src: usize, |
| 247 | /// The most recent value of the Decl after a successful semantic analysis. | ||
| 248 | /// The tag for this union is determined by the tag value of the analysis field. | ||
| 249 | typed_value: union { | ||
| 250 | never_succeeded, | ||
| 251 | most_recent: TypedValue.Managed, | ||
| 252 | }, | ||
| 219 | /// Represents the "shallow" analysis status. For example, for decls that are functions, | 253 | /// Represents the "shallow" analysis status. For example, for decls that are functions, |
| 220 | /// the function type is analyzed with this set to `in_progress`, however, the semantic | 254 | /// the function type is analyzed with this set to `in_progress`, however, the semantic |
| 221 | /// analysis of the function body is performed with this value set to `success`. Functions | 255 | /// analysis of the function body is performed with this value set to `success`. Functions |
| 222 | /// have their own analysis status field. | 256 | /// have their own analysis status field. |
| 223 | analysis: union(enum) { | 257 | analysis: enum { |
| 224 | in_progress, | 258 | initial_in_progress, |
| 225 | failure: ErrorMsg, | 259 | /// This Decl might be OK but it depends on another one which did not successfully complete |
| 226 | success: TypedValue, | 260 | /// semantic analysis. This Decl never had a value computed. |
| 261 | initial_dependency_failure, | ||
| 262 | /// Semantic analysis failure. This Decl never had a value computed. | ||
| 263 | /// There will be a corresponding ErrorMsg in Module.failed_decls. | ||
| 264 | initial_sema_failure, | ||
| 265 | /// In this case the `typed_value.most_recent` can still be accessed. | ||
| 266 | /// There will be a corresponding ErrorMsg in Module.failed_decls. | ||
| 267 | codegen_failure, | ||
| 268 | /// This Decl might be OK but it depends on another one which did not successfully complete | ||
| 269 | /// semantic analysis. There is a most recent value available. | ||
| 270 | repeat_dependency_failure, | ||
| 271 | /// Semantic anlaysis failure, but the `typed_value.most_recent` can be accessed. | ||
| 272 | /// There will be a corresponding ErrorMsg in Module.failed_decls. | ||
| 273 | repeat_sema_failure, | ||
| 274 | /// Completed successfully before; the `typed_value.most_recent` can be accessed, and | ||
| 275 | /// new semantic analysis is in progress. | ||
| 276 | repeat_in_progress, | ||
| 277 | /// Everything is done and updated. | ||
| 278 | complete, | ||
| 227 | }, | 279 | }, |
| 228 | /// The direct container of the Decl. This field will need to get more fleshed out when | 280 | |
| 229 | /// self-hosted supports proper struct types and Zig AST => ZIR. | 281 | /// Represents the position of the code, if any, in the output file. |
| 230 | scope: *Scope.ZIRModule, | 282 | /// This is populated regardless of semantic analysis and code generation. |
| 283 | /// This value is `undefined` if the type has no runtime bits. | ||
| 284 | link: link.ElfFile.Decl, | ||
| 285 | |||
| 286 | /// The set of other decls whose typed_value could possibly change if this Decl's | ||
| 287 | /// typed_value is modified. | ||
| 288 | /// TODO look into using a lightweight map/set data structure rather than a linear array. | ||
| 289 | dependants: ArrayListUnmanaged(*Decl) = .{}, | ||
| 290 | |||
| 291 | pub fn typedValue(self: Decl) ?TypedValue { | ||
| 292 | switch (self.analysis) { | ||
| 293 | .initial_in_progress, | ||
| 294 | .initial_dependency_failure, | ||
| 295 | .initial_sema_failure, | ||
| 296 | => return null, | ||
| 297 | .codegen_failure, | ||
| 298 | .repeat_dependency_failure, | ||
| 299 | .repeat_sema_failure, | ||
| 300 | .repeat_in_progress, | ||
| 301 | .complete, | ||
| 302 | => return self.typed_value.most_recent, | ||
| 303 | } | ||
| 304 | } | ||
| 231 | 305 | ||
| 232 | pub fn destroy(self: *Decl, allocator: *Allocator) void { | 306 | pub fn destroy(self: *Decl, allocator: *Allocator) void { |
| 233 | var arena = self.arena.promote(allocator); | 307 | allocator.free(mem.spanZ(u8, self.name)); |
| 234 | arena.deinit(); | 308 | if (self.typedValue()) |tv| tv.deinit(allocator); |
| 309 | allocator.destroy(self); | ||
| 235 | } | 310 | } |
| 236 | 311 | ||
| 237 | pub const Hash = [16]u8; | 312 | pub const Hash = [16]u8; |
| ... | @@ -252,8 +327,10 @@ pub const Module = struct { | ... | @@ -252,8 +327,10 @@ pub const Module = struct { |
| 252 | pub const Fn = struct { | 327 | pub const Fn = struct { |
| 253 | fn_type: Type, | 328 | fn_type: Type, |
| 254 | analysis: union(enum) { | 329 | analysis: union(enum) { |
| 330 | queued, | ||
| 255 | in_progress: *Analysis, | 331 | in_progress: *Analysis, |
| 256 | failure: ErrorMsg, | 332 | /// There will be a corresponding ErrorMsg in Module.failed_fns |
| 333 | failure, | ||
| 257 | success: Body, | 334 | success: Body, |
| 258 | }, | 335 | }, |
| 259 | /// The direct container of the Fn. This field will need to get more fleshed out when | 336 | /// The direct container of the Fn. This field will need to get more fleshed out when |
| ... | @@ -290,68 +367,36 @@ pub const Module = struct { | ... | @@ -290,68 +367,36 @@ pub const Module = struct { |
| 290 | /// Relative to the owning package's root_src_dir. | 367 | /// Relative to the owning package's root_src_dir. |
| 291 | /// Reference to external memory, not owned by ZIRModule. | 368 | /// Reference to external memory, not owned by ZIRModule. |
| 292 | sub_file_path: []const u8, | 369 | sub_file_path: []const u8, |
| 293 | contents: union(enum) { | 370 | source: union { |
| 294 | unloaded, | 371 | unloaded, |
| 295 | parse_failure: ParseFailure, | 372 | bytes: [:0]const u8, |
| 296 | success: Contents, | ||
| 297 | }, | 373 | }, |
| 298 | pub const ParseFailure = struct { | 374 | contents: union { |
| 299 | source: [:0]const u8, | 375 | not_available, |
| 300 | errors: []ErrorMsg, | ||
| 301 | |||
| 302 | pub fn deinit(self: *ParseFailure, allocator: *Allocator) void { | ||
| 303 | allocator.free(self.errors); | ||
| 304 | allocator.free(source); | ||
| 305 | } | ||
| 306 | }; | ||
| 307 | pub const Contents = struct { | ||
| 308 | source: [:0]const u8, | ||
| 309 | module: *text.Module, | 376 | module: *text.Module, |
| 310 | }; | 377 | }, |
| 378 | status: enum { | ||
| 379 | unloaded, | ||
| 380 | unloaded_parse_failure, | ||
| 381 | loaded_parse_failure, | ||
| 382 | loaded_success, | ||
| 383 | }, | ||
| 311 | 384 | ||
| 312 | pub fn deinit(self: *ZIRModule, allocator: *Allocator) void { | 385 | pub fn deinit(self: *ZIRModule, allocator: *Allocator) void { |
| 313 | switch (self.contents) { | 386 | switch (self.status) { |
| 314 | .unloaded => {}, | 387 | .unloaded, |
| 315 | .parse_failure => |pf| pd.deinit(allocator), | 388 | .unloaded_parse_failure, |
| 316 | .success => |contents| { | 389 | => {}, |
| 390 | .loaded_success => { | ||
| 391 | allocator.free(contents.source); | ||
| 392 | self.contents.module.deinit(allocator); | ||
| 393 | }, | ||
| 394 | .loaded_parse_failure => { | ||
| 317 | allocator.free(contents.source); | 395 | allocator.free(contents.source); |
| 318 | contents.src_zir_module.deinit(allocator); | ||
| 319 | }, | 396 | }, |
| 320 | } | 397 | } |
| 321 | self.* = undefined; | 398 | self.* = undefined; |
| 322 | } | 399 | } |
| 323 | |||
| 324 | pub fn loadContents(self: *ZIRModule, allocator: *Allocator) !*Contents { | ||
| 325 | if (self.contents) |contents| return contents; | ||
| 326 | |||
| 327 | const max_size = std.math.maxInt(u32); | ||
| 328 | const source = try self.root_pkg_dir.readFileAllocOptions(allocator, self.root_src_path, max_size, 1, 0); | ||
| 329 | errdefer allocator.free(source); | ||
| 330 | |||
| 331 | var errors = std.ArrayList(ErrorMsg).init(allocator); | ||
| 332 | defer errors.deinit(); | ||
| 333 | |||
| 334 | var src_zir_module = try text.parse(allocator, source, &errors); | ||
| 335 | errdefer src_zir_module.deinit(allocator); | ||
| 336 | |||
| 337 | switch (self.contents) { | ||
| 338 | .parse_failure => |pf| pf.deinit(allocator), | ||
| 339 | .unloaded => {}, | ||
| 340 | .success => unreachable, | ||
| 341 | } | ||
| 342 | |||
| 343 | if (errors.items.len != 0) { | ||
| 344 | self.contents = .{ .parse_failure = errors.toOwnedSlice() }; | ||
| 345 | return error.ParseFailure; | ||
| 346 | } | ||
| 347 | self.contents = .{ | ||
| 348 | .success = .{ | ||
| 349 | .source = source, | ||
| 350 | .module = src_zir_module, | ||
| 351 | }, | ||
| 352 | }; | ||
| 353 | return &self.contents.success; | ||
| 354 | } | ||
| 355 | }; | 400 | }; |
| 356 | 401 | ||
| 357 | /// This is a temporary structure, references to it are valid only | 402 | /// This is a temporary structure, references to it are valid only |
| ... | @@ -436,7 +481,7 @@ pub const Module = struct { | ... | @@ -436,7 +481,7 @@ pub const Module = struct { |
| 436 | // Analyze the root source file now. | 481 | // Analyze the root source file now. |
| 437 | self.analyzeRoot(self.root_scope) catch |err| switch (err) { | 482 | self.analyzeRoot(self.root_scope) catch |err| switch (err) { |
| 438 | error.AnalysisFail => { | 483 | error.AnalysisFail => { |
| 439 | assert(self.totalErrorCount() != 0); | 484 | assert(self.failed_files.size != 0); |
| 440 | }, | 485 | }, |
| 441 | else => |e| return e, | 486 | else => |e| return e, |
| 442 | }; | 487 | }; |
| ... | @@ -446,9 +491,10 @@ pub const Module = struct { | ... | @@ -446,9 +491,10 @@ pub const Module = struct { |
| 446 | } | 491 | } |
| 447 | 492 | ||
| 448 | pub fn totalErrorCount(self: *Module) usize { | 493 | pub fn totalErrorCount(self: *Module) usize { |
| 449 | return self.failed_decls.items.len + | 494 | return self.failed_decls.size + |
| 450 | self.failed_fns.items.len + | 495 | self.failed_fns.size + |
| 451 | self.failed_decls.items.len + | 496 | self.failed_decls.size + |
| 497 | self.failed_exports.size + | ||
| 452 | @boolToInt(self.link_error_flags.no_entry_point_found); | 498 | @boolToInt(self.link_error_flags.no_entry_point_found); |
| 453 | } | 499 | } |
| 454 | 500 | ||
| ... | @@ -459,26 +505,42 @@ pub const Module = struct { | ... | @@ -459,26 +505,42 @@ pub const Module = struct { |
| 459 | var errors = std.ArrayList(AllErrors.Message).init(self.allocator); | 505 | var errors = std.ArrayList(AllErrors.Message).init(self.allocator); |
| 460 | defer errors.deinit(); | 506 | defer errors.deinit(); |
| 461 | 507 | ||
| 462 | for (self.failed_files.items) |scope| { | 508 | { |
| 463 | const source = scope.parse_failure.source; | 509 | var it = self.failed_files.iterator(); |
| 464 | for (scope.parse_failure.errors) |parse_error| { | 510 | while (it.next()) |kv| { |
| 465 | AllErrors.add(&arena, &errors, scope.sub_file_path, source, parse_error); | 511 | const scope = kv.key; |
| 512 | const err_msg = kv.value; | ||
| 513 | const source = scope.parse_failure.source; | ||
| 514 | AllErrors.add(&arena, &errors, scope.sub_file_path, source, err_msg); | ||
| 466 | } | 515 | } |
| 467 | } | 516 | } |
| 468 | 517 | { | |
| 469 | for (self.failed_fns.items) |func| { | 518 | var it = self.failed_fns.iterator(); |
| 470 | const source = func.scope.success.source; | 519 | while (it.next()) |kv| { |
| 471 | for (func.analysis.failure) |err_msg| { | 520 | const func = kv.key; |
| 521 | const err_msg = kv.value; | ||
| 522 | const source = func.scope.success.source; | ||
| 472 | AllErrors.add(&arena, &errors, func.scope.sub_file_path, source, err_msg); | 523 | AllErrors.add(&arena, &errors, func.scope.sub_file_path, source, err_msg); |
| 473 | } | 524 | } |
| 474 | } | 525 | } |
| 475 | 526 | { | |
| 476 | for (self.failed_decls.items) |decl| { | 527 | var it = self.failed_decls.iterator(); |
| 477 | const source = decl.scope.success.source; | 528 | while (it.next()) |kv| { |
| 478 | for (decl.analysis.failure) |err_msg| { | 529 | const decl = kv.key; |
| 530 | const err_msg = kv.value; | ||
| 531 | const source = decl.scope.success.source; | ||
| 479 | AllErrors.add(&arena, &errors, decl.scope.sub_file_path, source, err_msg); | 532 | AllErrors.add(&arena, &errors, decl.scope.sub_file_path, source, err_msg); |
| 480 | } | 533 | } |
| 481 | } | 534 | } |
| 535 | { | ||
| 536 | var it = self.failed_exports.iterator(); | ||
| 537 | while (it.next()) |kv| { | ||
| 538 | const decl = kv.key.owner_decl; | ||
| 539 | const err_msg = kv.value; | ||
| 540 | const source = decl.scope.success.source; | ||
| 541 | try AllErrors.add(&arena, &errors, decl.scope.sub_file_path, source, err_msg); | ||
| 542 | } | ||
| 543 | } | ||
| 482 | 544 | ||
| 483 | if (self.link_error_flags.no_entry_point_found) { | 545 | if (self.link_error_flags.no_entry_point_found) { |
| 484 | try errors.append(.{ | 546 | try errors.append(.{ |
| ... | @@ -508,23 +570,81 @@ pub const Module = struct { | ... | @@ -508,23 +570,81 @@ pub const Module = struct { |
| 508 | // Here we simulate adding a source file which was previously not part of the compilation, | 570 | // Here we simulate adding a source file which was previously not part of the compilation, |
| 509 | // which means scanning the decls looking for exports. | 571 | // which means scanning the decls looking for exports. |
| 510 | // TODO also identify decls that need to be deleted. | 572 | // TODO also identify decls that need to be deleted. |
| 511 | const contents = blk: { | 573 | const src_module = switch (root_scope.status) { |
| 512 | // Clear parse errors. | 574 | .unloaded => blk: { |
| 513 | swapRemoveElem(self.allocator, *Scope.ZIRModule, root_scope, self.failed_files); | 575 | try self.failed_files.ensureCapacity(self.failed_files.size + 1); |
| 514 | try self.failed_files.ensureCapacity(self.allocator, self.failed_files.items.len + 1); | 576 | |
| 515 | break :blk root_scope.loadContents(self.allocator) catch |err| switch (err) { | 577 | var keep_source = false; |
| 516 | error.ParseFailure => { | 578 | const source = try self.root_pkg_dir.readFileAllocOptions( |
| 517 | self.failed_files.appendAssumeCapacity(root_scope); | 579 | self.allocator, |
| 580 | self.root_src_path, | ||
| 581 | std.math.maxInt(u32), | ||
| 582 | 1, | ||
| 583 | 0, | ||
| 584 | ); | ||
| 585 | defer if (!keep_source) self.allocator.free(source); | ||
| 586 | |||
| 587 | var keep_zir_module = false; | ||
| 588 | const zir_module = try self.allocator.create(text.Module); | ||
| 589 | defer if (!keep_zir_module) self.allocator.destroy(zir_module); | ||
| 590 | |||
| 591 | zir_module.* = try text.parse(self.allocator, source); | ||
| 592 | defer if (!keep_zir_module) zir_module.deinit(self.allocator); | ||
| 593 | |||
| 594 | if (zir_module.error_msg) |src_err_msg| { | ||
| 595 | self.failed_files.putAssumeCapacityNoClobber( | ||
| 596 | root_scope, | ||
| 597 | try ErrorMsg.create(self.allocator, src_err_msg.byte_offset, "{}", .{src_err_msg.msg}), | ||
| 598 | ); | ||
| 599 | root_scope.status = .loaded_parse_failure; | ||
| 600 | root_scope.source = .{ .bytes = source }; | ||
| 601 | keep_source = true; | ||
| 518 | return error.AnalysisFail; | 602 | return error.AnalysisFail; |
| 519 | }, | 603 | } |
| 520 | else => |e| return e, | 604 | |
| 521 | }; | 605 | root_scope.status = .loaded_success; |
| 606 | root_scope.source = .{ .bytes = source }; | ||
| 607 | keep_source = true; | ||
| 608 | root_scope.contents = .{ .module = zir_module }; | ||
| 609 | keep_zir_module = true; | ||
| 610 | |||
| 611 | break :blk zir_module; | ||
| 612 | }, | ||
| 613 | |||
| 614 | .unloaded_parse_failure, .loaded_parse_failure => return error.AnalysisFail, | ||
| 615 | .loaded_success => root_scope.contents.module, | ||
| 522 | }; | 616 | }; |
| 617 | |||
| 618 | // Here we ensure enough queue capacity to store all the decls, so that later we can use | ||
| 619 | // appendAssumeCapacity. | ||
| 620 | try self.analysis_queue.ensureCapacity(self.analysis_queue.items.len + contents.module.decls.len); | ||
| 621 | |||
| 523 | for (contents.module.decls) |decl| { | 622 | for (contents.module.decls) |decl| { |
| 524 | if (decl.cast(text.Inst.Export)) |export_inst| { | 623 | if (decl.cast(text.Inst.Export)) |export_inst| { |
| 525 | try analyzeExport(self, &root_scope.base, export_inst); | 624 | try analyzeExport(self, &root_scope.base, export_inst); |
| 526 | } | 625 | } |
| 527 | } | 626 | } |
| 627 | |||
| 628 | while (self.analysis_queue.popOrNull()) |work_item| { | ||
| 629 | switch (work_item) { | ||
| 630 | .decl => |decl| switch (decl.analysis) { | ||
| 631 | .success => |typed_value| { | ||
| 632 | var arena = decl.arena.promote(self.allocator); | ||
| 633 | const update_result = self.bin_file.updateDecl( | ||
| 634 | self.*, | ||
| 635 | typed_value, | ||
| 636 | decl.export_node, | ||
| 637 | decl.fullyQualifiedNameHash(), | ||
| 638 | &arena.allocator, | ||
| 639 | ); | ||
| 640 | decl.arena = arena.state; | ||
| 641 | if (try update_result) |err_msg| { | ||
| 642 | decl.analysis = .{ .codegen_failure = err_msg }; | ||
| 643 | } | ||
| 644 | }, | ||
| 645 | }, | ||
| 646 | } | ||
| 647 | } | ||
| 528 | } | 648 | } |
| 529 | 649 | ||
| 530 | fn resolveDecl(self: *Module, scope: *Scope, old_inst: *text.Inst) InnerError!*Decl { | 650 | fn resolveDecl(self: *Module, scope: *Scope, old_inst: *text.Inst) InnerError!*Decl { |
| ... | @@ -548,21 +668,41 @@ pub const Module = struct { | ... | @@ -548,21 +668,41 @@ pub const Module = struct { |
| 548 | break :blk new_decl; | 668 | break :blk new_decl; |
| 549 | }; | 669 | }; |
| 550 | 670 | ||
| 551 | var decl_scope: Scope.DeclAnalysis = .{ .decl = new_decl }; | 671 | swapRemoveElem(self.allocator, *Scope.ZIRModule, root_scope, self.failed_decls); |
| 672 | var decl_scope: Scope.DeclAnalysis = .{ | ||
| 673 | .base = .{ .parent = scope }, | ||
| 674 | .decl = new_decl, | ||
| 675 | }; | ||
| 552 | const typed_value = self.analyzeInstConst(&decl_scope.base, old_inst) catch |err| switch (err) { | 676 | const typed_value = self.analyzeInstConst(&decl_scope.base, old_inst) catch |err| switch (err) { |
| 553 | error.AnalysisFail => return error.AnalysisFail, | 677 | error.AnalysisFail => { |
| 678 | assert(new_decl.analysis == .failure); | ||
| 679 | return error.AnalysisFail; | ||
| 680 | }, | ||
| 554 | else => |e| return e, | 681 | else => |e| return e, |
| 555 | }; | 682 | }; |
| 556 | new_decl.analysis = .{ .success = typed_value }; | 683 | new_decl.analysis = .{ .success = typed_value }; |
| 557 | if (try self.bin_file.updateDecl(self.*, typed_value, new_decl.export_node, hash)) |err_msg| { | 684 | // We ensureCapacity when scanning for decls. |
| 558 | new_decl.analysis = .{ .success = typed_value }; | 685 | self.analysis_queue.appendAssumeCapacity(.{ .decl = new_decl }); |
| 559 | } else |err| { | ||
| 560 | return err; | ||
| 561 | } | ||
| 562 | return new_decl; | 686 | return new_decl; |
| 563 | } | 687 | } |
| 564 | } | 688 | } |
| 565 | 689 | ||
| 690 | fn resolveCompleteDecl(self: *Module, scope: *Scope, old_inst: *text.Inst) InnerError!*Decl { | ||
| 691 | const decl = try self.resolveDecl(scope, old_inst); | ||
| 692 | switch (decl.analysis) { | ||
| 693 | .initial_in_progress => unreachable, | ||
| 694 | .repeat_in_progress => unreachable, | ||
| 695 | .initial_dependency_failure, | ||
| 696 | .repeat_dependency_failure, | ||
| 697 | .initial_sema_failure, | ||
| 698 | .repeat_sema_failure, | ||
| 699 | .codegen_failure, | ||
| 700 | => return error.AnalysisFail, | ||
| 701 | |||
| 702 | .complete => return decl, | ||
| 703 | } | ||
| 704 | } | ||
| 705 | |||
| 566 | fn resolveInst(self: *Module, scope: *Scope, old_inst: *text.Inst) InnerError!*Inst { | 706 | fn resolveInst(self: *Module, scope: *Scope, old_inst: *text.Inst) InnerError!*Inst { |
| 567 | if (scope.cast(Scope.Block)) |block| { | 707 | if (scope.cast(Scope.Block)) |block| { |
| 568 | if (block.func.inst_table.get(old_inst)) |kv| { | 708 | if (block.func.inst_table.get(old_inst)) |kv| { |
| ... | @@ -570,7 +710,7 @@ pub const Module = struct { | ... | @@ -570,7 +710,7 @@ pub const Module = struct { |
| 570 | } | 710 | } |
| 571 | } | 711 | } |
| 572 | 712 | ||
| 573 | const decl = try self.resolveDecl(scope, old_inst); | 713 | const decl = try self.resolveCompleteDecl(scope, old_inst); |
| 574 | const decl_ref = try self.analyzeDeclRef(scope, old_inst.src, decl); | 714 | const decl_ref = try self.analyzeDeclRef(scope, old_inst.src, decl); |
| 575 | return self.analyzeDeref(scope, old_inst.src, decl_ref); | 715 | return self.analyzeDeref(scope, old_inst.src, decl_ref); |
| 576 | } | 716 | } |
| ... | @@ -621,29 +761,52 @@ pub const Module = struct { | ... | @@ -621,29 +761,52 @@ pub const Module = struct { |
| 621 | } | 761 | } |
| 622 | 762 | ||
| 623 | fn analyzeExport(self: *Module, scope: *Scope, export_inst: *text.Inst.Export) !void { | 763 | fn analyzeExport(self: *Module, scope: *Scope, export_inst: *text.Inst.Export) !void { |
| 764 | try self.decl_exports.ensureCapacity(self.decl_exports.size + 1); | ||
| 765 | try self.export_owners.ensureCapacity(self.export_owners.size + 1); | ||
| 624 | const symbol_name = try self.resolveConstString(scope, export_inst.positionals.symbol_name); | 766 | const symbol_name = try self.resolveConstString(scope, export_inst.positionals.symbol_name); |
| 625 | const decl = try self.resolveDecl(scope, export_inst.positionals.value); | 767 | const exported_decl = try self.resolveCompleteDecl(scope, export_inst.positionals.value); |
| 768 | const typed_value = exported_decl.typed_value.most_recent.typed_value; | ||
| 769 | switch (typed_value.ty.zigTypeTag()) { | ||
| 770 | .Fn => {}, | ||
| 771 | else => return self.fail( | ||
| 772 | scope, | ||
| 773 | export_inst.positionals.value.src, | ||
| 774 | "unable to export type '{}'", | ||
| 775 | .{typed_value.ty}, | ||
| 776 | ), | ||
| 777 | } | ||
| 778 | const new_export = try self.allocator.create(Export); | ||
| 779 | errdefer self.allocator.destroy(new_export); | ||
| 626 | 780 | ||
| 627 | switch (decl.analysis) { | 781 | const owner_decl = scope.getDecl(); |
| 628 | .in_progress => unreachable, | 782 | |
| 629 | .failure => return error.AnalysisFail, | 783 | new_export.* = .{ |
| 630 | .success => |typed_value| switch (typed_value.ty.zigTypeTag()) { | 784 | .options = .{ .data = .{ .name = symbol_name } }, |
| 631 | .Fn => {}, | 785 | .src = export_inst.base.src, |
| 632 | else => return self.fail( | 786 | .link = .{}, |
| 633 | scope, | 787 | .owner_decl = owner_decl, |
| 634 | export_inst.positionals.value.src, | 788 | .status = .in_progress, |
| 635 | "unable to export type '{}'", | 789 | }; |
| 636 | .{typed_value.ty}, | 790 | |
| 637 | ), | 791 | // Add to export_owners table. |
| 638 | }, | 792 | const eo_gop = self.export_owners.getOrPut(owner_decl) catch unreachable; |
| 793 | if (!eo_gop.found_existing) { | ||
| 794 | eo_gop.kv.value = &[0]*Export{}; | ||
| 795 | } | ||
| 796 | eo_gop.kv.value = try self.allocator.realloc(eo_gop.kv.value, eo_gop.kv.value.len + 1); | ||
| 797 | eo_gop.kv.value[eo_gop.kv.value.len - 1] = new_export; | ||
| 798 | errdefer eo_gop.kv.value = self.allocator.shrink(eo_gop.kv.value, eo_gop.kv.value.len - 1); | ||
| 799 | |||
| 800 | // Add to exported_decl table. | ||
| 801 | const de_gop = self.decl_exports.getOrPut(exported_decl) catch unreachable; | ||
| 802 | if (!de_gop.found_existing) { | ||
| 803 | de_gop.kv.value = &[0]*Export{}; | ||
| 639 | } | 804 | } |
| 640 | const Node = LinkedList(std.builtin.ExportOptions).Node; | 805 | de_gop.kv.value = try self.allocator.realloc(de_gop.kv.value, de_gop.kv.value.len + 1); |
| 641 | export_node = try decl.arena.promote(self.allocator).allocator.create(Node); | 806 | de_gop.kv.value[de_gop.kv.value.len - 1] = new_export; |
| 642 | export_node.* = .{ .data = .{ .name = symbol_name } }; | 807 | errdefer de_gop.kv.value = self.allocator.shrink(de_gop.kv.value, de_gop.kv.value.len - 1); |
| 643 | decl.export_node = export_node; | ||
| 644 | 808 | ||
| 645 | // TODO Avoid double update in the case of exporting a decl that we just created. | 809 | try self.bin_file.updateDeclExports(self, decl, de_gop.kv.value); |
| 646 | self.bin_file.updateDeclExports(); | ||
| 647 | } | 810 | } |
| 648 | 811 | ||
| 649 | /// TODO should not need the cast on the last parameter at the callsites | 812 | /// TODO should not need the cast on the last parameter at the callsites |
| ... | @@ -1636,6 +1799,31 @@ pub const Module = struct { | ... | @@ -1636,6 +1799,31 @@ pub const Module = struct { |
| 1636 | pub const ErrorMsg = struct { | 1799 | pub const ErrorMsg = struct { |
| 1637 | byte_offset: usize, | 1800 | byte_offset: usize, |
| 1638 | msg: []const u8, | 1801 | msg: []const u8, |
| 1802 | |||
| 1803 | pub fn create(allocator: *Allocator, byte_offset: usize, comptime format: []const u8, args: var) !*ErrorMsg { | ||
| 1804 | const self = try allocator.create(ErrorMsg); | ||
| 1805 | errdefer allocator.destroy(ErrorMsg); | ||
| 1806 | self.* = init(allocator, byte_offset, format, args); | ||
| 1807 | return self; | ||
| 1808 | } | ||
| 1809 | |||
| 1810 | /// Assumes the ErrorMsg struct and msg were both allocated with allocator. | ||
| 1811 | pub fn destroy(self: *ErrorMsg, allocator: *Allocator) void { | ||
| 1812 | self.deinit(allocator); | ||
| 1813 | allocator.destroy(self); | ||
| 1814 | } | ||
| 1815 | |||
| 1816 | pub fn init(allocator: *Allocator, byte_offset: usize, comptime format: []const u8, args: var) !ErrorMsg { | ||
| 1817 | return ErrorMsg{ | ||
| 1818 | .byte_offset = byte_offset, | ||
| 1819 | .msg = try std.fmt.allocPrint(allocator, format, args), | ||
| 1820 | }; | ||
| 1821 | } | ||
| 1822 | |||
| 1823 | pub fn deinit(self: *ErrorMsg, allocator: *Allocator) void { | ||
| 1824 | allocator.free(err_msg.msg); | ||
| 1825 | self.* = undefined; | ||
| 1826 | } | ||
| 1639 | }; | 1827 | }; |
| 1640 | 1828 | ||
| 1641 | pub fn main() anyerror!void { | 1829 | pub fn main() anyerror!void { |
src-self-hosted/ir/text.zig+6-10| ... | @@ -406,8 +406,8 @@ pub const ErrorMsg = struct { | ... | @@ -406,8 +406,8 @@ pub const ErrorMsg = struct { |
| 406 | 406 | ||
| 407 | pub const Module = struct { | 407 | pub const Module = struct { |
| 408 | decls: []*Inst, | 408 | decls: []*Inst, |
| 409 | errors: []ErrorMsg, | ||
| 410 | arena: std.heap.ArenaAllocator.State, | 409 | arena: std.heap.ArenaAllocator.State, |
| 410 | error_msg: ?ErrorMsg = null, | ||
| 411 | 411 | ||
| 412 | pub const Body = struct { | 412 | pub const Body = struct { |
| 413 | instructions: []*Inst, | 413 | instructions: []*Inst, |
| ... | @@ -415,7 +415,6 @@ pub const Module = struct { | ... | @@ -415,7 +415,6 @@ pub const Module = struct { |
| 415 | 415 | ||
| 416 | pub fn deinit(self: *Module, allocator: *Allocator) void { | 416 | pub fn deinit(self: *Module, allocator: *Allocator) void { |
| 417 | allocator.free(self.decls); | 417 | allocator.free(self.decls); |
| 418 | allocator.free(self.errors); | ||
| 419 | self.arena.promote(allocator).deinit(); | 418 | self.arena.promote(allocator).deinit(); |
| 420 | self.* = undefined; | 419 | self.* = undefined; |
| 421 | } | 420 | } |
| ... | @@ -576,22 +575,21 @@ pub fn parse(allocator: *Allocator, source: [:0]const u8) Allocator.Error!Module | ... | @@ -576,22 +575,21 @@ pub fn parse(allocator: *Allocator, source: [:0]const u8) Allocator.Error!Module |
| 576 | .i = 0, | 575 | .i = 0, |
| 577 | .source = source, | 576 | .source = source, |
| 578 | .global_name_map = &global_name_map, | 577 | .global_name_map = &global_name_map, |
| 579 | .errors = .{}, | ||
| 580 | .decls = .{}, | 578 | .decls = .{}, |
| 581 | }; | 579 | }; |
| 582 | errdefer parser.arena.deinit(); | 580 | errdefer parser.arena.deinit(); |
| 583 | 581 | ||
| 584 | parser.parseRoot() catch |err| switch (err) { | 582 | parser.parseRoot() catch |err| switch (err) { |
| 585 | error.ParseFailure => { | 583 | error.ParseFailure => { |
| 586 | assert(parser.errors.items.len != 0); | 584 | assert(parser.error_msg != null); |
| 587 | }, | 585 | }, |
| 588 | else => |e| return e, | 586 | else => |e| return e, |
| 589 | }; | 587 | }; |
| 590 | 588 | ||
| 591 | return Module{ | 589 | return Module{ |
| 592 | .decls = parser.decls.toOwnedSlice(allocator), | 590 | .decls = parser.decls.toOwnedSlice(allocator), |
| 593 | .errors = parser.errors.toOwnedSlice(allocator), | ||
| 594 | .arena = parser.arena.state, | 591 | .arena = parser.arena.state, |
| 592 | .error_msg = parser.error_msg, | ||
| 595 | }; | 593 | }; |
| 596 | } | 594 | } |
| 597 | 595 | ||
| ... | @@ -600,9 +598,9 @@ const Parser = struct { | ... | @@ -600,9 +598,9 @@ const Parser = struct { |
| 600 | arena: std.heap.ArenaAllocator, | 598 | arena: std.heap.ArenaAllocator, |
| 601 | i: usize, | 599 | i: usize, |
| 602 | source: [:0]const u8, | 600 | source: [:0]const u8, |
| 603 | errors: std.ArrayListUnmanaged(ErrorMsg), | ||
| 604 | decls: std.ArrayListUnmanaged(*Inst), | 601 | decls: std.ArrayListUnmanaged(*Inst), |
| 605 | global_name_map: *std.StringHashMap(usize), | 602 | global_name_map: *std.StringHashMap(usize), |
| 603 | error_msg: ?ErrorMsg = null, | ||
| 606 | 604 | ||
| 607 | const Body = struct { | 605 | const Body = struct { |
| 608 | instructions: std.ArrayList(*Inst), | 606 | instructions: std.ArrayList(*Inst), |
| ... | @@ -776,10 +774,9 @@ const Parser = struct { | ... | @@ -776,10 +774,9 @@ const Parser = struct { |
| 776 | 774 | ||
| 777 | fn fail(self: *Parser, comptime format: []const u8, args: var) InnerError { | 775 | fn fail(self: *Parser, comptime format: []const u8, args: var) InnerError { |
| 778 | @setCold(true); | 776 | @setCold(true); |
| 779 | const msg = try std.fmt.allocPrint(&self.arena.allocator, format, args); | 777 | self.error_msg = ErrorMsg{ |
| 780 | (try self.errors.addOne()).* = .{ | ||
| 781 | .byte_offset = self.i, | 778 | .byte_offset = self.i, |
| 782 | .msg = msg, | 779 | .msg = try std.fmt.allocPrint(&self.arena.allocator, format, args), |
| 783 | }; | 780 | }; |
| 784 | return error.ParseFailure; | 781 | return error.ParseFailure; |
| 785 | } | 782 | } |
| ... | @@ -971,7 +968,6 @@ pub fn emit_zir(allocator: *Allocator, old_module: ir.Module) !Module { | ... | @@ -971,7 +968,6 @@ pub fn emit_zir(allocator: *Allocator, old_module: ir.Module) !Module { |
| 971 | return Module{ | 968 | return Module{ |
| 972 | .decls = ctx.decls.toOwnedSlice(), | 969 | .decls = ctx.decls.toOwnedSlice(), |
| 973 | .arena = ctx.arena, | 970 | .arena = ctx.arena, |
| 974 | .errors = &[0]ErrorMsg{}, | ||
| 975 | }; | 971 | }; |
| 976 | } | 972 | } |
| 977 | 973 |
src-self-hosted/link.zig+225-127| ... | @@ -130,6 +130,20 @@ pub const ElfFile = struct { | ... | @@ -130,6 +130,20 @@ pub const ElfFile = struct { |
| 130 | no_entry_point_found: bool = false, | 130 | no_entry_point_found: bool = false, |
| 131 | }; | 131 | }; |
| 132 | 132 | ||
| 133 | /// TODO it's too bad this optional takes up double the memory it should | ||
| 134 | pub const Decl = struct { | ||
| 135 | /// Each decl always gets a local symbol with the fully qualified name. | ||
| 136 | /// The vaddr and size are found here directly. | ||
| 137 | /// The file offset is found by computing the vaddr offset from the section vaddr | ||
| 138 | /// the symbol references, and adding that to the file offset of the section. | ||
| 139 | local_sym_index: ?usize = null, | ||
| 140 | }; | ||
| 141 | |||
| 142 | /// TODO it's too bad this optional takes up double the memory it should | ||
| 143 | pub const Export = struct { | ||
| 144 | sym_index: ?usize = null, | ||
| 145 | }; | ||
| 146 | |||
| 133 | pub fn deinit(self: *ElfFile) void { | 147 | pub fn deinit(self: *ElfFile) void { |
| 134 | self.sections.deinit(self.allocator); | 148 | self.sections.deinit(self.allocator); |
| 135 | self.program_headers.deinit(self.allocator); | 149 | self.program_headers.deinit(self.allocator); |
| ... | @@ -138,7 +152,7 @@ pub const ElfFile = struct { | ... | @@ -138,7 +152,7 @@ pub const ElfFile = struct { |
| 138 | self.offset_table.deinit(self.allocator); | 152 | self.offset_table.deinit(self.allocator); |
| 139 | } | 153 | } |
| 140 | 154 | ||
| 141 | // `expand_num / expand_den` is the factor of padding when allocation | 155 | // `alloc_num / alloc_den` is the factor of padding when allocation |
| 142 | const alloc_num = 4; | 156 | const alloc_num = 4; |
| 143 | const alloc_den = 3; | 157 | const alloc_den = 3; |
| 144 | 158 | ||
| ... | @@ -216,12 +230,21 @@ pub const ElfFile = struct { | ... | @@ -216,12 +230,21 @@ pub const ElfFile = struct { |
| 216 | } | 230 | } |
| 217 | 231 | ||
| 218 | fn makeString(self: *ElfFile, bytes: []const u8) !u32 { | 232 | fn makeString(self: *ElfFile, bytes: []const u8) !u32 { |
| 233 | try self.shstrtab.ensureCapacity(self.allocator, self.shstrtab.items.len + bytes.len + 1); | ||
| 219 | const result = self.shstrtab.items.len; | 234 | const result = self.shstrtab.items.len; |
| 220 | try self.shstrtab.appendSlice(bytes); | 235 | self.shstrtab.appendSliceAssumeCapacity(bytes); |
| 221 | try self.shstrtab.append(0); | 236 | self.shstrtab.appendAssumeCapacity(0); |
| 222 | return @intCast(u32, result); | 237 | return @intCast(u32, result); |
| 223 | } | 238 | } |
| 224 | 239 | ||
| 240 | fn updateString(self: *ElfFile, old_str_off: u32, new_name: []const u8) !u32 { | ||
| 241 | const existing_name = self.getString(old_str_off); | ||
| 242 | if (mem.eql(u8, existing_name, new_name)) { | ||
| 243 | return old_str_off; | ||
| 244 | } | ||
| 245 | return self.makeString(new_name); | ||
| 246 | } | ||
| 247 | |||
| 225 | pub fn populateMissingMetadata(self: *ElfFile) !void { | 248 | pub fn populateMissingMetadata(self: *ElfFile) !void { |
| 226 | const small_ptr = switch (self.ptr_width) { | 249 | const small_ptr = switch (self.ptr_width) { |
| 227 | .p32 => true, | 250 | .p32 => true, |
| ... | @@ -575,166 +598,200 @@ pub const ElfFile = struct { | ... | @@ -575,166 +598,200 @@ pub const ElfFile = struct { |
| 575 | try self.file.pwriteAll(hdr_buf[0..index], 0); | 598 | try self.file.pwriteAll(hdr_buf[0..index], 0); |
| 576 | } | 599 | } |
| 577 | 600 | ||
| 578 | /// TODO Look into making this smaller to save memory. | ||
| 579 | /// Lots of redundant info here with the data stored in symbol structs. | ||
| 580 | const DeclSymbol = struct { | ||
| 581 | symbol_indexes: []usize, | ||
| 582 | vaddr: u64, | ||
| 583 | file_offset: u64, | ||
| 584 | size: u64, | ||
| 585 | }; | ||
| 586 | |||
| 587 | const AllocatedBlock = struct { | 601 | const AllocatedBlock = struct { |
| 588 | vaddr: u64, | 602 | vaddr: u64, |
| 589 | file_offset: u64, | 603 | file_offset: u64, |
| 590 | size_capacity: u64, | 604 | size_capacity: u64, |
| 591 | }; | 605 | }; |
| 592 | 606 | ||
| 593 | fn allocateDeclSymbol(self: *ElfFile, size: u64) AllocatedBlock { | 607 | fn allocateTextBlock(self: *ElfFile, new_block_size: u64) !AllocatedBlock { |
| 594 | const phdr = &self.program_headers.items[self.phdr_load_re_index.?]; | 608 | const phdr = &self.program_headers.items[self.phdr_load_re_index.?]; |
| 595 | todo(); | 609 | const shdr = &self.sections.items[self.text_section_index.?]; |
| 596 | //{ | 610 | |
| 597 | // // Now that we know the code size, we need to update the program header for executable code | 611 | const text_capacity = self.allocatedSize(shdr.sh_offset); |
| 598 | // phdr.p_memsz = vaddr - phdr.p_vaddr; | 612 | // TODO instead of looping here, maintain a free list and a pointer to the end. |
| 599 | // phdr.p_filesz = phdr.p_memsz; | 613 | const end_vaddr = blk: { |
| 600 | 614 | var start: u64 = 0; | |
| 601 | // const shdr = &self.sections.items[self.text_section_index.?]; | 615 | var size: u64 = 0; |
| 602 | // shdr.sh_size = phdr.p_filesz; | 616 | for (self.symbols.items) |sym| { |
| 617 | if (sym.st_value > start) { | ||
| 618 | start = sm.st_value; | ||
| 619 | size = sym.st_size; | ||
| 620 | } | ||
| 621 | } | ||
| 622 | break :blk start + (size * alloc_num / alloc_den); | ||
| 623 | }; | ||
| 603 | 624 | ||
| 604 | // self.phdr_table_dirty = true; // TODO look into making only the one program header dirty | 625 | const text_size = end_vaddr - phdr.p_vaddr; |
| 605 | // self.shdr_table_dirty = true; // TODO look into making only the one section dirty | 626 | const needed_size = text_size + new_block_size; |
| 606 | //} | 627 | if (needed_size > text_capacity) { |
| 628 | // Must move the entire text section. | ||
| 629 | const new_offset = self.findFreeSpace(needed_size, 0x1000); | ||
| 630 | const amt = try self.file.copyRangeAll(shdr.sh_offset, self.file, new_offset, text_size); | ||
| 631 | if (amt != text_size) return error.InputOutput; | ||
| 632 | shdr.sh_offset = new_offset; | ||
| 633 | } | ||
| 634 | // Now that we know the code size, we need to update the program header for executable code | ||
| 635 | shdr.sh_size = needed_size; | ||
| 636 | phdr.p_memsz = needed_size; | ||
| 637 | phdr.p_filesz = needed_size; | ||
| 607 | 638 | ||
| 608 | //return self.writeSymbols(); | 639 | self.phdr_table_dirty = true; // TODO look into making only the one program header dirty |
| 640 | self.shdr_table_dirty = true; // TODO look into making only the one section dirty | ||
| 609 | } | 641 | } |
| 610 | 642 | ||
| 611 | fn findAllocatedBlock(self: *ElfFile, vaddr: u64) AllocatedBlock { | 643 | fn findAllocatedTextBlock(self: *ElfFile, sym: elf.Elf64_Sym) AllocatedBlock { |
| 612 | todo(); | 644 | const phdr = &self.program_headers.items[self.phdr_load_re_index.?]; |
| 645 | const shdr = &self.sections.items[self.text_section_index.?]; | ||
| 646 | |||
| 647 | // Find the next sym after this one. | ||
| 648 | // TODO look into using a hash map to speed up perf. | ||
| 649 | const text_capacity = self.allocatedSize(shdr.sh_offset); | ||
| 650 | var next_vaddr_start = phdr.p_vaddr + text_capacity; | ||
| 651 | for (self.symbols.items) |elem| { | ||
| 652 | if (elem.st_value < sym.st_value) continue; | ||
| 653 | if (elem.st_value < next_vaddr_start) next_vaddr_start = elem.st_value; | ||
| 654 | } | ||
| 655 | return .{ | ||
| 656 | .vaddr = sym.st_value, | ||
| 657 | .file_offset = shdr.sh_offset + (sym.st_value - phdr.p_vaddr), | ||
| 658 | .size_capacity = next_vaddr_start - sym.st_value, | ||
| 659 | }; | ||
| 613 | } | 660 | } |
| 614 | 661 | ||
| 615 | pub fn updateDecl( | 662 | pub fn updateDecl(self: *ElfFile, module: *ir.Module, decl: *ir.Module.Decl) !void { |
| 616 | self: *ElfFile, | ||
| 617 | module: ir.Module, | ||
| 618 | typed_value: ir.TypedValue, | ||
| 619 | decl_export_node: ?*std.LinkedList(std.builtin.ExportOptions).Node, | ||
| 620 | hash: ir.Module.Decl.Hash, | ||
| 621 | err_msg_allocator: *Allocator, | ||
| 622 | ) !?ir.ErrorMsg { | ||
| 623 | var code = std.ArrayList(u8).init(self.allocator); | 663 | var code = std.ArrayList(u8).init(self.allocator); |
| 624 | defer code.deinit(); | 664 | defer code.deinit(); |
| 625 | 665 | ||
| 626 | const err_msg = try codegen.generateSymbol(typed_value, module, &code, err_msg_allocator); | 666 | const typed_value = decl.typed_value.most_recent.typed_value; |
| 627 | if (err_msg != null) |em| return em; | 667 | const err_msg = try codegen.generateSymbol(typed_value, module, &code, module.allocator); |
| 668 | if (err_msg != null) |em| { | ||
| 669 | decl.analysis = .codegen_failure; | ||
| 670 | _ = try module.failed_decls.put(decl, em); | ||
| 671 | return; | ||
| 672 | } | ||
| 628 | 673 | ||
| 629 | const export_count = blk: { | 674 | const file_offset = blk: { |
| 630 | var export_node = decl_export_node; | 675 | const code_size = code.items.len; |
| 631 | var i: usize = 0; | 676 | const stt_bits: u8 = switch (typed_value.ty.zigTypeTag()) { |
| 632 | while (export_node) |node| : (export_node = node.next) i += 1; | 677 | .Fn => elf.STT_FUNC, |
| 633 | break :blk i; | 678 | else => elf.STT_OBJECT, |
| 634 | }; | 679 | }; |
| 635 | 680 | ||
| 636 | // Find or create a symbol from the decl | 681 | if (decl.link.local_sym_index) |local_sym_index| { |
| 637 | var valid_sym_index_len: usize = 0; | 682 | const local_sym = &self.symbols.items[local_sym_index]; |
| 638 | const decl_symbol = blk: { | 683 | const existing_block = self.findAllocatedTextBlock(local_sym); |
| 639 | if (self.decl_table.getValue(hash)) |decl_symbol| { | 684 | const file_offset = if (code_size > existing_block.size_capacity) fo: { |
| 640 | valid_sym_index_len = decl_symbol.symbol_indexes.len; | 685 | const new_block = self.allocateTextBlock(code_size); |
| 641 | decl_symbol.symbol_indexes = try self.allocator.realloc(usize, export_count); | 686 | local_sym.st_value = new_block.vaddr; |
| 642 | 687 | local_sym.st_size = code_size; | |
| 643 | const existing_block = self.findAllocatedBlock(decl_symbol.vaddr); | 688 | break :fo new_block.file_offset; |
| 644 | if (code.items.len > existing_block.size_capacity) { | 689 | } else existing_block.file_offset; |
| 645 | const new_block = self.allocateDeclSymbol(code.items.len); | 690 | local_sym.st_name = try self.updateString(local_sym.st_name, mem.spanZ(u8, decl.name)); |
| 646 | decl_symbol.vaddr = new_block.vaddr; | 691 | local_sym.st_info = (elf.STB_LOCAL << 4) | stt_bits; |
| 647 | decl_symbol.file_offset = new_block.file_offset; | 692 | // TODO this write could be avoided if no fields of the symbol were changed. |
| 648 | decl_symbol.size = code.items.len; | 693 | try self.writeSymbol(local_sym_index); |
| 649 | } | 694 | break :blk file_offset; |
| 650 | break :blk decl_symbol; | ||
| 651 | } else { | 695 | } else { |
| 652 | const new_block = self.allocateDeclSymbol(code.items.len); | 696 | try self.symbols.ensureCapacity(self.symbols.items.len + 1); |
| 653 | 697 | const decl_name = mem.spanZ(u8, decl.name); | |
| 654 | const decl_symbol = try self.allocator.create(DeclSymbol); | 698 | const name_str_index = try self.makeString(decl_name); |
| 655 | errdefer self.allocator.destroy(decl_symbol); | 699 | const new_block = self.allocateTextBlock(code_size); |
| 656 | 700 | const local_sym_index = self.symbols.items.len; | |
| 657 | decl_symbol.* = .{ | 701 | |
| 658 | .symbol_indexes = try self.allocator.alloc(usize, export_count), | 702 | self.symbols.appendAssumeCapacity(self.allocator, .{ |
| 659 | .vaddr = new_block.vaddr, | 703 | .st_name = name_str_index, |
| 660 | .file_offset = new_block.file_offset, | 704 | .st_info = (elf.STB_LOCAL << 4) | stt_bits, |
| 661 | .size = code.items.len, | 705 | .st_other = 0, |
| 662 | }; | 706 | .st_shndx = self.text_section_index.?, |
| 663 | errdefer self.allocator.free(decl_symbol.symbol_indexes); | 707 | .st_value = new_block.vaddr, |
| 664 | 708 | .st_size = code_size, | |
| 665 | try self.decl_table.put(hash, decl_symbol); | 709 | }); |
| 666 | break :blk decl_symbol; | 710 | errdefer self.symbols.shrink(self.symbols.items.len - 1); |
| 711 | try self.writeSymbol(local_sym_index); | ||
| 712 | |||
| 713 | self.symbol_count_dirty = true; | ||
| 714 | decl.link.local_sym_index = local_sym_index; | ||
| 715 | |||
| 716 | break :blk new_block.file_offset; | ||
| 667 | } | 717 | } |
| 668 | }; | 718 | }; |
| 669 | 719 | ||
| 670 | // Allocate new symbols. | 720 | try self.file.pwriteAll(code.items, file_offset); |
| 671 | { | ||
| 672 | var i: usize = valid_sym_index_len; | ||
| 673 | const old_len = self.symbols.items.len; | ||
| 674 | try self.symbols.resize(old_len + (decl_symbol.symbol_indexes.len - i)); | ||
| 675 | while (i < decl_symbol.symbol_indexes) : (i += 1) { | ||
| 676 | decl_symbol.symbol_indexes[i] = old_len + i; | ||
| 677 | } | ||
| 678 | } | ||
| 679 | 721 | ||
| 680 | var export_node = decl_export_node; | 722 | // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated. |
| 681 | var export_index: usize = 0; | 723 | const decl_exports = module.decl_exports.get(decl) orelse &[0]*ir.Module.Export{}; |
| 682 | while (export_node) |node| : ({ | 724 | return self.updateDeclExports(module, decl, decl_exports); |
| 683 | export_node = node.next; | 725 | } |
| 684 | export_index += 1; | 726 | |
| 685 | }) { | 727 | /// Must be called only after a successful call to `updateDecl`. |
| 686 | if (node.data.section) |section_name| { | 728 | pub fn updateDeclExports( |
| 729 | self: *ElfFile, | ||
| 730 | module: *ir.Module, | ||
| 731 | decl: *const ir.Module.Decl, | ||
| 732 | exports: []const *const Export, | ||
| 733 | ) !void { | ||
| 734 | try self.symbols.ensureCapacity(self.symbols.items.len + exports.len); | ||
| 735 | const typed_value = decl.typed_value.most_recent.typed_value; | ||
| 736 | const decl_sym = self.symbols.items[decl.link.local_sym_index.?]; | ||
| 737 | |||
| 738 | for (exports) |exp| { | ||
| 739 | if (exp.options.section) |section_name| { | ||
| 687 | if (!mem.eql(u8, section_name, ".text")) { | 740 | if (!mem.eql(u8, section_name, ".text")) { |
| 688 | try errors.ensureCapacity(errors.items.len + 1); | 741 | try module.failed_exports.ensureCapacity(module.failed_exports.size + 1); |
| 689 | errors.appendAssumeCapacity(.{ | 742 | module.failed_exports.putAssumeCapacityNoClobber( |
| 690 | .byte_offset = 0, | 743 | exp, |
| 691 | .msg = try std.fmt.allocPrint(errors.allocator, "Unimplemented: ExportOptions.section", .{}), | 744 | try ir.ErrorMsg.create(0, "Unimplemented: ExportOptions.section", .{}), |
| 692 | }); | 745 | ); |
| 693 | } | 746 | } |
| 694 | } | 747 | } |
| 695 | const stb_bits = switch (node.data.linkage) { | 748 | const stb_bits = switch (exp.options.linkage) { |
| 696 | .Internal => elf.STB_LOCAL, | 749 | .Internal => elf.STB_LOCAL, |
| 697 | .Strong => blk: { | 750 | .Strong => blk: { |
| 698 | if (mem.eql(u8, node.data.name, "_start")) { | 751 | if (mem.eql(u8, exp.options.name, "_start")) { |
| 699 | self.entry_addr = decl_symbol.vaddr; | 752 | self.entry_addr = decl_symbol.vaddr; |
| 700 | } | 753 | } |
| 701 | break :blk elf.STB_GLOBAL; | 754 | break :blk elf.STB_GLOBAL; |
| 702 | }, | 755 | }, |
| 703 | .Weak => elf.STB_WEAK, | 756 | .Weak => elf.STB_WEAK, |
| 704 | .LinkOnce => { | 757 | .LinkOnce => { |
| 705 | try errors.ensureCapacity(errors.items.len + 1); | 758 | try module.failed_exports.ensureCapacity(module.failed_exports.size + 1); |
| 706 | errors.appendAssumeCapacity(.{ | 759 | module.failed_exports.putAssumeCapacityNoClobber( |
| 707 | .byte_offset = 0, | 760 | exp, |
| 708 | .msg = try std.fmt.allocPrint(errors.allocator, "Unimplemented: GlobalLinkage.LinkOnce", .{}), | 761 | try ir.ErrorMsg.create(0, "Unimplemented: GlobalLinkage.LinkOnce", .{}), |
| 709 | }); | 762 | ); |
| 710 | }, | 763 | }, |
| 711 | }; | 764 | }; |
| 712 | const stt_bits = switch (typed_value.ty.zigTypeTag()) { | 765 | const stt_bits: u8 = @truncate(u4, decl_sym.st_info); |
| 713 | .Fn => elf.STT_FUNC, | 766 | if (exp.link.sym_index) |i| { |
| 714 | else => elf.STT_OBJECT, | 767 | const sym = &self.symbols.items[i]; |
| 715 | }; | 768 | sym.* = .{ |
| 716 | const sym_index = decl_symbol.symbol_indexes[export_index]; | 769 | .st_name = try self.updateString(sym.st_name, exp.options.name), |
| 717 | const name = blk: { | 770 | .st_info = (stb_bits << 4) | stt_bits, |
| 718 | if (i < valid_sym_index_len) { | 771 | .st_other = 0, |
| 719 | const name_stroff = self.symbols.items[sym_index].st_name; | 772 | .st_shndx = self.text_section_index.?, |
| 720 | const existing_name = self.getString(name_stroff); | 773 | .st_value = decl_sym.st_value, |
| 721 | if (mem.eql(u8, existing_name, node.data.name)) { | 774 | .st_size = decl_sym.st_size, |
| 722 | break :blk name_stroff; | 775 | }; |
| 723 | } | 776 | try self.writeSymbol(i); |
| 724 | } | 777 | } else { |
| 725 | break :blk try self.makeString(node.data.name); | 778 | const name = try self.makeString(exp.options.name); |
| 726 | }; | 779 | const i = self.symbols.items.len; |
| 727 | self.symbols.items[sym_index] = .{ | 780 | self.symbols.appendAssumeCapacity(self.allocator, .{ |
| 728 | .st_name = name, | 781 | .st_name = sn.name, |
| 729 | .st_info = (stb_bits << 4) | stt_bits, | 782 | .st_info = (stb_bits << 4) | stt_bits, |
| 730 | .st_other = 0, | 783 | .st_other = 0, |
| 731 | .st_shndx = self.text_section_index.?, | 784 | .st_shndx = self.text_section_index.?, |
| 732 | .st_value = decl_symbol.vaddr, | 785 | .st_value = decl_sym.st_value, |
| 733 | .st_size = code.items.len, | 786 | .st_size = decl_sym.st_size, |
| 734 | }; | 787 | }); |
| 788 | errdefer self.symbols.shrink(self.symbols.items.len - 1); | ||
| 789 | try self.writeSymbol(i); | ||
| 790 | |||
| 791 | self.symbol_count_dirty = true; | ||
| 792 | exp.link.sym_index = i; | ||
| 793 | } | ||
| 735 | } | 794 | } |
| 736 | |||
| 737 | try self.file.pwriteAll(code.items, decl_symbol.file_offset); | ||
| 738 | } | 795 | } |
| 739 | 796 | ||
| 740 | fn writeProgHeader(self: *ElfFile, index: usize) !void { | 797 | fn writeProgHeader(self: *ElfFile, index: usize) !void { |
| ... | @@ -782,7 +839,48 @@ pub const ElfFile = struct { | ... | @@ -782,7 +839,48 @@ pub const ElfFile = struct { |
| 782 | } | 839 | } |
| 783 | } | 840 | } |
| 784 | 841 | ||
| 785 | fn writeSymbols(self: *ElfFile) !void { | 842 | fn writeSymbol(self: *ElfFile, index: usize) !void { |
| 843 | const syms_sect = &self.sections.items[self.symtab_section_index.?]; | ||
| 844 | // Make sure we are not pointlessly writing symbol data that will have to get relocated | ||
| 845 | // due to running out of space. | ||
| 846 | if (self.symbol_count_dirty) { | ||
| 847 | const allocated_size = self.allocatedSize(syms_sect.sh_offset); | ||
| 848 | const needed_size = self.symbols.items.len * sym_size; | ||
| 849 | if (needed_size > allocated_size) { | ||
| 850 | return self.writeAllSymbols(); | ||
| 851 | } | ||
| 852 | } | ||
| 853 | const foreign_endian = self.options.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian(); | ||
| 854 | switch (self.ptr_width) { | ||
| 855 | .p32 => { | ||
| 856 | var sym = [1]elf.Elf32_Sym{ | ||
| 857 | .{ | ||
| 858 | .st_name = self.symbols.items[index].st_name, | ||
| 859 | .st_value = @intCast(u32, self.symbols.items[index].st_value), | ||
| 860 | .st_size = @intCast(u32, self.symbols.items[index].st_size), | ||
| 861 | .st_info = self.symbols.items[index].st_info, | ||
| 862 | .st_other = self.symbols.items[index].st_other, | ||
| 863 | .st_shndx = self.symbols.items[index].st_shndx, | ||
| 864 | }, | ||
| 865 | }; | ||
| 866 | if (foreign_endian) { | ||
| 867 | bswapAllFields(elf.Elf32_Sym, &sym[0]); | ||
| 868 | } | ||
| 869 | const off = syms_sect.sh_offset + @sizeOf(elf.Elf32_Sym) * index; | ||
| 870 | try self.file.pwriteAll(mem.sliceAsBytes(sym[0..1]), off); | ||
| 871 | }, | ||
| 872 | .p64 => { | ||
| 873 | var sym = [1]elf.Elf64_Sym{self.symbols.items[index]}; | ||
| 874 | if (foreign_endian) { | ||
| 875 | bswapAllFields(elf.Elf64_Sym, &sym[0]); | ||
| 876 | } | ||
| 877 | const off = syms_sect.sh_offset + @sizeOf(elf.Elf64_Sym) * index; | ||
| 878 | try self.file.pwriteAll(mem.sliceAsBytes(sym[0..1]), off); | ||
| 879 | }, | ||
| 880 | } | ||
| 881 | } | ||
| 882 | |||
| 883 | fn writeAllSymbols(self: *ElfFile) !void { | ||
| 786 | const small_ptr = self.ptr_width == .p32; | 884 | const small_ptr = self.ptr_width == .p32; |
| 787 | const syms_sect = &self.sections.items[self.symtab_section_index.?]; | 885 | const syms_sect = &self.sections.items[self.symtab_section_index.?]; |
| 788 | const sym_align: u16 = if (small_ptr) @alignOf(elf.Elf32_Sym) else @alignOf(elf.Elf64_Sym); | 886 | const sym_align: u16 = if (small_ptr) @alignOf(elf.Elf32_Sym) else @alignOf(elf.Elf64_Sym); |
src-self-hosted/type.zig+21-2| ... | @@ -5,8 +5,7 @@ const Allocator = std.mem.Allocator; | ... | @@ -5,8 +5,7 @@ const Allocator = std.mem.Allocator; |
| 5 | const Target = std.Target; | 5 | const Target = std.Target; |
| 6 | 6 | ||
| 7 | /// This is the raw data, with no bookkeeping, no memory awareness, no de-duplication. | 7 | /// This is the raw data, with no bookkeeping, no memory awareness, no de-duplication. |
| 8 | /// It's important for this struct to be small. | 8 | /// It's important for this type to be small. |
| 9 | /// It is not copyable since it may contain references to its inner data. | ||
| 10 | /// Types are not de-duplicated, which helps with multi-threading since it obviates the requirement | 9 | /// Types are not de-duplicated, which helps with multi-threading since it obviates the requirement |
| 11 | /// of obtaining a lock on a global type table, as well as making the | 10 | /// of obtaining a lock on a global type table, as well as making the |
| 12 | /// garbage collection bookkeeping simpler. | 11 | /// garbage collection bookkeeping simpler. |
| ... | @@ -51,6 +50,7 @@ pub const Type = extern union { | ... | @@ -51,6 +50,7 @@ pub const Type = extern union { |
| 51 | .comptime_int => return .ComptimeInt, | 50 | .comptime_int => return .ComptimeInt, |
| 52 | .comptime_float => return .ComptimeFloat, | 51 | .comptime_float => return .ComptimeFloat, |
| 53 | .noreturn => return .NoReturn, | 52 | .noreturn => return .NoReturn, |
| 53 | .@"null" => return .Null, | ||
| 54 | 54 | ||
| 55 | .fn_noreturn_no_args => return .Fn, | 55 | .fn_noreturn_no_args => return .Fn, |
| 56 | .fn_naked_noreturn_no_args => return .Fn, | 56 | .fn_naked_noreturn_no_args => return .Fn, |
| ... | @@ -184,6 +184,8 @@ pub const Type = extern union { | ... | @@ -184,6 +184,8 @@ pub const Type = extern union { |
| 184 | .noreturn, | 184 | .noreturn, |
| 185 | => return out_stream.writeAll(@tagName(t)), | 185 | => return out_stream.writeAll(@tagName(t)), |
| 186 | 186 | ||
| 187 | .@"null" => return out_stream.writeAll("@TypeOf(null)"), | ||
| 188 | |||
| 187 | .const_slice_u8 => return out_stream.writeAll("[]const u8"), | 189 | .const_slice_u8 => return out_stream.writeAll("[]const u8"), |
| 188 | .fn_noreturn_no_args => return out_stream.writeAll("fn() noreturn"), | 190 | .fn_noreturn_no_args => return out_stream.writeAll("fn() noreturn"), |
| 189 | .fn_naked_noreturn_no_args => return out_stream.writeAll("fn() callconv(.Naked) noreturn"), | 191 | .fn_naked_noreturn_no_args => return out_stream.writeAll("fn() callconv(.Naked) noreturn"), |
| ... | @@ -246,6 +248,7 @@ pub const Type = extern union { | ... | @@ -246,6 +248,7 @@ pub const Type = extern union { |
| 246 | .comptime_int => return Value.initTag(.comptime_int_type), | 248 | .comptime_int => return Value.initTag(.comptime_int_type), |
| 247 | .comptime_float => return Value.initTag(.comptime_float_type), | 249 | .comptime_float => return Value.initTag(.comptime_float_type), |
| 248 | .noreturn => return Value.initTag(.noreturn_type), | 250 | .noreturn => return Value.initTag(.noreturn_type), |
| 251 | .@"null" => return Value.initTag(.null_type), | ||
| 249 | .fn_noreturn_no_args => return Value.initTag(.fn_noreturn_no_args_type), | 252 | .fn_noreturn_no_args => return Value.initTag(.fn_noreturn_no_args_type), |
| 250 | .fn_naked_noreturn_no_args => return Value.initTag(.fn_naked_noreturn_no_args_type), | 253 | .fn_naked_noreturn_no_args => return Value.initTag(.fn_naked_noreturn_no_args_type), |
| 251 | .fn_ccc_void_no_args => return Value.initTag(.fn_ccc_void_no_args_type), | 254 | .fn_ccc_void_no_args => return Value.initTag(.fn_ccc_void_no_args_type), |
| ... | @@ -286,6 +289,7 @@ pub const Type = extern union { | ... | @@ -286,6 +289,7 @@ pub const Type = extern union { |
| 286 | .comptime_int, | 289 | .comptime_int, |
| 287 | .comptime_float, | 290 | .comptime_float, |
| 288 | .noreturn, | 291 | .noreturn, |
| 292 | .@"null", | ||
| 289 | .array, | 293 | .array, |
| 290 | .array_u8_sentinel_0, | 294 | .array_u8_sentinel_0, |
| 291 | .const_slice_u8, | 295 | .const_slice_u8, |
| ... | @@ -329,6 +333,7 @@ pub const Type = extern union { | ... | @@ -329,6 +333,7 @@ pub const Type = extern union { |
| 329 | .comptime_int, | 333 | .comptime_int, |
| 330 | .comptime_float, | 334 | .comptime_float, |
| 331 | .noreturn, | 335 | .noreturn, |
| 336 | .@"null", | ||
| 332 | .array, | 337 | .array, |
| 333 | .array_u8_sentinel_0, | 338 | .array_u8_sentinel_0, |
| 334 | .single_const_pointer, | 339 | .single_const_pointer, |
| ... | @@ -372,6 +377,7 @@ pub const Type = extern union { | ... | @@ -372,6 +377,7 @@ pub const Type = extern union { |
| 372 | .comptime_int, | 377 | .comptime_int, |
| 373 | .comptime_float, | 378 | .comptime_float, |
| 374 | .noreturn, | 379 | .noreturn, |
| 380 | .@"null", | ||
| 375 | .array, | 381 | .array, |
| 376 | .array_u8_sentinel_0, | 382 | .array_u8_sentinel_0, |
| 377 | .fn_noreturn_no_args, | 383 | .fn_noreturn_no_args, |
| ... | @@ -416,6 +422,7 @@ pub const Type = extern union { | ... | @@ -416,6 +422,7 @@ pub const Type = extern union { |
| 416 | .comptime_int, | 422 | .comptime_int, |
| 417 | .comptime_float, | 423 | .comptime_float, |
| 418 | .noreturn, | 424 | .noreturn, |
| 425 | .@"null", | ||
| 419 | .fn_noreturn_no_args, | 426 | .fn_noreturn_no_args, |
| 420 | .fn_naked_noreturn_no_args, | 427 | .fn_naked_noreturn_no_args, |
| 421 | .fn_ccc_void_no_args, | 428 | .fn_ccc_void_no_args, |
| ... | @@ -458,6 +465,7 @@ pub const Type = extern union { | ... | @@ -458,6 +465,7 @@ pub const Type = extern union { |
| 458 | .comptime_int, | 465 | .comptime_int, |
| 459 | .comptime_float, | 466 | .comptime_float, |
| 460 | .noreturn, | 467 | .noreturn, |
| 468 | .@"null", | ||
| 461 | .fn_noreturn_no_args, | 469 | .fn_noreturn_no_args, |
| 462 | .fn_naked_noreturn_no_args, | 470 | .fn_naked_noreturn_no_args, |
| 463 | .fn_ccc_void_no_args, | 471 | .fn_ccc_void_no_args, |
| ... | @@ -489,6 +497,7 @@ pub const Type = extern union { | ... | @@ -489,6 +497,7 @@ pub const Type = extern union { |
| 489 | .comptime_int, | 497 | .comptime_int, |
| 490 | .comptime_float, | 498 | .comptime_float, |
| 491 | .noreturn, | 499 | .noreturn, |
| 500 | .@"null", | ||
| 492 | .fn_noreturn_no_args, | 501 | .fn_noreturn_no_args, |
| 493 | .fn_naked_noreturn_no_args, | 502 | .fn_naked_noreturn_no_args, |
| 494 | .fn_ccc_void_no_args, | 503 | .fn_ccc_void_no_args, |
| ... | @@ -533,6 +542,7 @@ pub const Type = extern union { | ... | @@ -533,6 +542,7 @@ pub const Type = extern union { |
| 533 | .comptime_int, | 542 | .comptime_int, |
| 534 | .comptime_float, | 543 | .comptime_float, |
| 535 | .noreturn, | 544 | .noreturn, |
| 545 | .@"null", | ||
| 536 | .fn_noreturn_no_args, | 546 | .fn_noreturn_no_args, |
| 537 | .fn_naked_noreturn_no_args, | 547 | .fn_naked_noreturn_no_args, |
| 538 | .fn_ccc_void_no_args, | 548 | .fn_ccc_void_no_args, |
| ... | @@ -606,6 +616,7 @@ pub const Type = extern union { | ... | @@ -606,6 +616,7 @@ pub const Type = extern union { |
| 606 | .comptime_int, | 616 | .comptime_int, |
| 607 | .comptime_float, | 617 | .comptime_float, |
| 608 | .noreturn, | 618 | .noreturn, |
| 619 | .@"null", | ||
| 609 | .array, | 620 | .array, |
| 610 | .single_const_pointer, | 621 | .single_const_pointer, |
| 611 | .single_const_pointer_to_comptime_int, | 622 | .single_const_pointer_to_comptime_int, |
| ... | @@ -650,6 +661,7 @@ pub const Type = extern union { | ... | @@ -650,6 +661,7 @@ pub const Type = extern union { |
| 650 | .comptime_int, | 661 | .comptime_int, |
| 651 | .comptime_float, | 662 | .comptime_float, |
| 652 | .noreturn, | 663 | .noreturn, |
| 664 | .@"null", | ||
| 653 | .array, | 665 | .array, |
| 654 | .single_const_pointer, | 666 | .single_const_pointer, |
| 655 | .single_const_pointer_to_comptime_int, | 667 | .single_const_pointer_to_comptime_int, |
| ... | @@ -693,6 +705,7 @@ pub const Type = extern union { | ... | @@ -693,6 +705,7 @@ pub const Type = extern union { |
| 693 | .comptime_int, | 705 | .comptime_int, |
| 694 | .comptime_float, | 706 | .comptime_float, |
| 695 | .noreturn, | 707 | .noreturn, |
| 708 | .@"null", | ||
| 696 | .array, | 709 | .array, |
| 697 | .single_const_pointer, | 710 | .single_const_pointer, |
| 698 | .single_const_pointer_to_comptime_int, | 711 | .single_const_pointer_to_comptime_int, |
| ... | @@ -736,6 +749,7 @@ pub const Type = extern union { | ... | @@ -736,6 +749,7 @@ pub const Type = extern union { |
| 736 | .comptime_int, | 749 | .comptime_int, |
| 737 | .comptime_float, | 750 | .comptime_float, |
| 738 | .noreturn, | 751 | .noreturn, |
| 752 | .@"null", | ||
| 739 | .array, | 753 | .array, |
| 740 | .single_const_pointer, | 754 | .single_const_pointer, |
| 741 | .single_const_pointer_to_comptime_int, | 755 | .single_const_pointer_to_comptime_int, |
| ... | @@ -779,6 +793,7 @@ pub const Type = extern union { | ... | @@ -779,6 +793,7 @@ pub const Type = extern union { |
| 779 | .comptime_int, | 793 | .comptime_int, |
| 780 | .comptime_float, | 794 | .comptime_float, |
| 781 | .noreturn, | 795 | .noreturn, |
| 796 | .@"null", | ||
| 782 | .array, | 797 | .array, |
| 783 | .single_const_pointer, | 798 | .single_const_pointer, |
| 784 | .single_const_pointer_to_comptime_int, | 799 | .single_const_pointer_to_comptime_int, |
| ... | @@ -833,6 +848,7 @@ pub const Type = extern union { | ... | @@ -833,6 +848,7 @@ pub const Type = extern union { |
| 833 | .type, | 848 | .type, |
| 834 | .anyerror, | 849 | .anyerror, |
| 835 | .noreturn, | 850 | .noreturn, |
| 851 | .@"null", | ||
| 836 | .fn_noreturn_no_args, | 852 | .fn_noreturn_no_args, |
| 837 | .fn_naked_noreturn_no_args, | 853 | .fn_naked_noreturn_no_args, |
| 838 | .fn_ccc_void_no_args, | 854 | .fn_ccc_void_no_args, |
| ... | @@ -881,6 +897,7 @@ pub const Type = extern union { | ... | @@ -881,6 +897,7 @@ pub const Type = extern union { |
| 881 | .c_void, | 897 | .c_void, |
| 882 | .void, | 898 | .void, |
| 883 | .noreturn, | 899 | .noreturn, |
| 900 | .@"null", | ||
| 884 | => return true, | 901 | => return true, |
| 885 | 902 | ||
| 886 | .int_unsigned => return ty.cast(Payload.IntUnsigned).?.bits == 0, | 903 | .int_unsigned => return ty.cast(Payload.IntUnsigned).?.bits == 0, |
| ... | @@ -933,6 +950,7 @@ pub const Type = extern union { | ... | @@ -933,6 +950,7 @@ pub const Type = extern union { |
| 933 | .c_void, | 950 | .c_void, |
| 934 | .void, | 951 | .void, |
| 935 | .noreturn, | 952 | .noreturn, |
| 953 | .@"null", | ||
| 936 | .int_unsigned, | 954 | .int_unsigned, |
| 937 | .int_signed, | 955 | .int_signed, |
| 938 | .array, | 956 | .array, |
| ... | @@ -974,6 +992,7 @@ pub const Type = extern union { | ... | @@ -974,6 +992,7 @@ pub const Type = extern union { |
| 974 | comptime_int, | 992 | comptime_int, |
| 975 | comptime_float, | 993 | comptime_float, |
| 976 | noreturn, | 994 | noreturn, |
| 995 | @"null", | ||
| 977 | fn_noreturn_no_args, | 996 | fn_noreturn_no_args, |
| 978 | fn_naked_noreturn_no_args, | 997 | fn_naked_noreturn_no_args, |
| 979 | fn_ccc_void_no_args, | 998 | fn_ccc_void_no_args, |
src-self-hosted/value.zig+13-1| ... | @@ -10,7 +10,7 @@ const ir = @import("ir.zig"); | ... | @@ -10,7 +10,7 @@ const ir = @import("ir.zig"); |
| 10 | 10 | ||
| 11 | /// This is the raw data, with no bookkeeping, no memory awareness, | 11 | /// This is the raw data, with no bookkeeping, no memory awareness, |
| 12 | /// no de-duplication, and no type system awareness. | 12 | /// no de-duplication, and no type system awareness. |
| 13 | /// It's important for this struct to be small. | 13 | /// It's important for this type to be small. |
| 14 | /// This union takes advantage of the fact that the first page of memory | 14 | /// This union takes advantage of the fact that the first page of memory |
| 15 | /// is unmapped, giving us 4096 possible enum tags that have no payload. | 15 | /// is unmapped, giving us 4096 possible enum tags that have no payload. |
| 16 | pub const Value = extern union { | 16 | pub const Value = extern union { |
| ... | @@ -46,6 +46,7 @@ pub const Value = extern union { | ... | @@ -46,6 +46,7 @@ pub const Value = extern union { |
| 46 | comptime_int_type, | 46 | comptime_int_type, |
| 47 | comptime_float_type, | 47 | comptime_float_type, |
| 48 | noreturn_type, | 48 | noreturn_type, |
| 49 | null_type, | ||
| 49 | fn_noreturn_no_args_type, | 50 | fn_noreturn_no_args_type, |
| 50 | fn_naked_noreturn_no_args_type, | 51 | fn_naked_noreturn_no_args_type, |
| 51 | fn_ccc_void_no_args_type, | 52 | fn_ccc_void_no_args_type, |
| ... | @@ -138,6 +139,7 @@ pub const Value = extern union { | ... | @@ -138,6 +139,7 @@ pub const Value = extern union { |
| 138 | .comptime_int_type => return out_stream.writeAll("comptime_int"), | 139 | .comptime_int_type => return out_stream.writeAll("comptime_int"), |
| 139 | .comptime_float_type => return out_stream.writeAll("comptime_float"), | 140 | .comptime_float_type => return out_stream.writeAll("comptime_float"), |
| 140 | .noreturn_type => return out_stream.writeAll("noreturn"), | 141 | .noreturn_type => return out_stream.writeAll("noreturn"), |
| 142 | .null_type => return out_stream.writeAll("@TypeOf(null)"), | ||
| 141 | .fn_noreturn_no_args_type => return out_stream.writeAll("fn() noreturn"), | 143 | .fn_noreturn_no_args_type => return out_stream.writeAll("fn() noreturn"), |
| 142 | .fn_naked_noreturn_no_args_type => return out_stream.writeAll("fn() callconv(.Naked) noreturn"), | 144 | .fn_naked_noreturn_no_args_type => return out_stream.writeAll("fn() callconv(.Naked) noreturn"), |
| 143 | .fn_ccc_void_no_args_type => return out_stream.writeAll("fn() callconv(.C) void"), | 145 | .fn_ccc_void_no_args_type => return out_stream.writeAll("fn() callconv(.C) void"), |
| ... | @@ -209,6 +211,7 @@ pub const Value = extern union { | ... | @@ -209,6 +211,7 @@ pub const Value = extern union { |
| 209 | .comptime_int_type => Type.initTag(.comptime_int), | 211 | .comptime_int_type => Type.initTag(.comptime_int), |
| 210 | .comptime_float_type => Type.initTag(.comptime_float), | 212 | .comptime_float_type => Type.initTag(.comptime_float), |
| 211 | .noreturn_type => Type.initTag(.noreturn), | 213 | .noreturn_type => Type.initTag(.noreturn), |
| 214 | .null_type => Type.initTag(.@"null"), | ||
| 212 | .fn_noreturn_no_args_type => Type.initTag(.fn_noreturn_no_args), | 215 | .fn_noreturn_no_args_type => Type.initTag(.fn_noreturn_no_args), |
| 213 | .fn_naked_noreturn_no_args_type => Type.initTag(.fn_naked_noreturn_no_args), | 216 | .fn_naked_noreturn_no_args_type => Type.initTag(.fn_naked_noreturn_no_args), |
| 214 | .fn_ccc_void_no_args_type => Type.initTag(.fn_ccc_void_no_args), | 217 | .fn_ccc_void_no_args_type => Type.initTag(.fn_ccc_void_no_args), |
| ... | @@ -263,6 +266,7 @@ pub const Value = extern union { | ... | @@ -263,6 +266,7 @@ pub const Value = extern union { |
| 263 | .comptime_int_type, | 266 | .comptime_int_type, |
| 264 | .comptime_float_type, | 267 | .comptime_float_type, |
| 265 | .noreturn_type, | 268 | .noreturn_type, |
| 269 | .null_type, | ||
| 266 | .fn_noreturn_no_args_type, | 270 | .fn_noreturn_no_args_type, |
| 267 | .fn_naked_noreturn_no_args_type, | 271 | .fn_naked_noreturn_no_args_type, |
| 268 | .fn_ccc_void_no_args_type, | 272 | .fn_ccc_void_no_args_type, |
| ... | @@ -319,6 +323,7 @@ pub const Value = extern union { | ... | @@ -319,6 +323,7 @@ pub const Value = extern union { |
| 319 | .comptime_int_type, | 323 | .comptime_int_type, |
| 320 | .comptime_float_type, | 324 | .comptime_float_type, |
| 321 | .noreturn_type, | 325 | .noreturn_type, |
| 326 | .null_type, | ||
| 322 | .fn_noreturn_no_args_type, | 327 | .fn_noreturn_no_args_type, |
| 323 | .fn_naked_noreturn_no_args_type, | 328 | .fn_naked_noreturn_no_args_type, |
| 324 | .fn_ccc_void_no_args_type, | 329 | .fn_ccc_void_no_args_type, |
| ... | @@ -376,6 +381,7 @@ pub const Value = extern union { | ... | @@ -376,6 +381,7 @@ pub const Value = extern union { |
| 376 | .comptime_int_type, | 381 | .comptime_int_type, |
| 377 | .comptime_float_type, | 382 | .comptime_float_type, |
| 378 | .noreturn_type, | 383 | .noreturn_type, |
| 384 | .null_type, | ||
| 379 | .fn_noreturn_no_args_type, | 385 | .fn_noreturn_no_args_type, |
| 380 | .fn_naked_noreturn_no_args_type, | 386 | .fn_naked_noreturn_no_args_type, |
| 381 | .fn_ccc_void_no_args_type, | 387 | .fn_ccc_void_no_args_type, |
| ... | @@ -438,6 +444,7 @@ pub const Value = extern union { | ... | @@ -438,6 +444,7 @@ pub const Value = extern union { |
| 438 | .comptime_int_type, | 444 | .comptime_int_type, |
| 439 | .comptime_float_type, | 445 | .comptime_float_type, |
| 440 | .noreturn_type, | 446 | .noreturn_type, |
| 447 | .null_type, | ||
| 441 | .fn_noreturn_no_args_type, | 448 | .fn_noreturn_no_args_type, |
| 442 | .fn_naked_noreturn_no_args_type, | 449 | .fn_naked_noreturn_no_args_type, |
| 443 | .fn_ccc_void_no_args_type, | 450 | .fn_ccc_void_no_args_type, |
| ... | @@ -529,6 +536,7 @@ pub const Value = extern union { | ... | @@ -529,6 +536,7 @@ pub const Value = extern union { |
| 529 | .comptime_int_type, | 536 | .comptime_int_type, |
| 530 | .comptime_float_type, | 537 | .comptime_float_type, |
| 531 | .noreturn_type, | 538 | .noreturn_type, |
| 539 | .null_type, | ||
| 532 | .fn_noreturn_no_args_type, | 540 | .fn_noreturn_no_args_type, |
| 533 | .fn_naked_noreturn_no_args_type, | 541 | .fn_naked_noreturn_no_args_type, |
| 534 | .fn_ccc_void_no_args_type, | 542 | .fn_ccc_void_no_args_type, |
| ... | @@ -582,6 +590,7 @@ pub const Value = extern union { | ... | @@ -582,6 +590,7 @@ pub const Value = extern union { |
| 582 | .comptime_int_type, | 590 | .comptime_int_type, |
| 583 | .comptime_float_type, | 591 | .comptime_float_type, |
| 584 | .noreturn_type, | 592 | .noreturn_type, |
| 593 | .null_type, | ||
| 585 | .fn_noreturn_no_args_type, | 594 | .fn_noreturn_no_args_type, |
| 586 | .fn_naked_noreturn_no_args_type, | 595 | .fn_naked_noreturn_no_args_type, |
| 587 | .fn_ccc_void_no_args_type, | 596 | .fn_ccc_void_no_args_type, |
| ... | @@ -674,6 +683,7 @@ pub const Value = extern union { | ... | @@ -674,6 +683,7 @@ pub const Value = extern union { |
| 674 | .comptime_int_type, | 683 | .comptime_int_type, |
| 675 | .comptime_float_type, | 684 | .comptime_float_type, |
| 676 | .noreturn_type, | 685 | .noreturn_type, |
| 686 | .null_type, | ||
| 677 | .fn_noreturn_no_args_type, | 687 | .fn_noreturn_no_args_type, |
| 678 | .fn_naked_noreturn_no_args_type, | 688 | .fn_naked_noreturn_no_args_type, |
| 679 | .fn_ccc_void_no_args_type, | 689 | .fn_ccc_void_no_args_type, |
| ... | @@ -736,6 +746,7 @@ pub const Value = extern union { | ... | @@ -736,6 +746,7 @@ pub const Value = extern union { |
| 736 | .comptime_int_type, | 746 | .comptime_int_type, |
| 737 | .comptime_float_type, | 747 | .comptime_float_type, |
| 738 | .noreturn_type, | 748 | .noreturn_type, |
| 749 | .null_type, | ||
| 739 | .fn_noreturn_no_args_type, | 750 | .fn_noreturn_no_args_type, |
| 740 | .fn_naked_noreturn_no_args_type, | 751 | .fn_naked_noreturn_no_args_type, |
| 741 | .fn_ccc_void_no_args_type, | 752 | .fn_ccc_void_no_args_type, |
| ... | @@ -812,6 +823,7 @@ pub const Value = extern union { | ... | @@ -812,6 +823,7 @@ pub const Value = extern union { |
| 812 | .comptime_int_type, | 823 | .comptime_int_type, |
| 813 | .comptime_float_type, | 824 | .comptime_float_type, |
| 814 | .noreturn_type, | 825 | .noreturn_type, |
| 826 | .null_type, | ||
| 815 | .fn_noreturn_no_args_type, | 827 | .fn_noreturn_no_args_type, |
| 816 | .fn_naked_noreturn_no_args_type, | 828 | .fn_naked_noreturn_no_args_type, |
| 817 | .fn_ccc_void_no_args_type, | 829 | .fn_ccc_void_no_args_type, |