| ... | @@ -260,30 +260,15 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node) | ... | @@ -260,30 +260,15 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node) |
| 260 | var f: Flush = .{}; | 260 | var f: Flush = .{}; |
| 261 | defer f.deinit(gpa); | 261 | defer f.deinit(gpa); |
| 262 | | 262 | |
| 263 | // Covers zig.h and err_typedef_item. | 263 | // Covers zig.h and typedef. |
| 264 | try f.all_buffers.ensureUnusedCapacity(gpa, 2); | 264 | try f.all_buffers.ensureUnusedCapacity(gpa, 2); |
| 265 | | 265 | |
| 266 | if (zig_h.len != 0) { | 266 | f.appendBufAssumeCapacity(zig_h); |
| 267 | f.all_buffers.appendAssumeCapacity(.{ | | |
| 268 | .iov_base = zig_h, | | |
| 269 | .iov_len = zig_h.len, | | |
| 270 | }); | | |
| 271 | f.file_size += zig_h.len; | | |
| 272 | } | | |
| 273 | | 267 | |
| 274 | const err_typedef_writer = f.err_typedef_buf.writer(gpa); | 268 | const typedef_index = f.all_buffers.items.len; |
| 275 | const err_typedef_index = f.all_buffers.items.len; | | |
| 276 | f.all_buffers.items.len += 1; | 269 | f.all_buffers.items.len += 1; |
| 277 | | 270 | |
| 278 | if (module.global_error_set.size > 0) { | 271 | try self.flushErrDecls(&f); |
| 279 | try err_typedef_writer.writeAll("enum {\n"); | | |
| 280 | var it = module.global_error_set.iterator(); | | |
| 281 | while (it.next()) |entry| try err_typedef_writer.print(" zig_error_{s} = {d},\n", .{ | | |
| 282 | codegen.fmtIdent(entry.key_ptr.*), | | |
| 283 | entry.value_ptr.*, | | |
| 284 | }); | | |
| 285 | try err_typedef_writer.writeAll("};\n"); | | |
| 286 | } | | |
| 287 | | 272 | |
| 288 | // Typedefs, forward decls, and non-functions first. | 273 | // Typedefs, forward decls, and non-functions first. |
| 289 | // Unlike other backends, the .c code we are emitting is order-dependent. Therefore | 274 | // Unlike other backends, the .c code we are emitting is order-dependent. Therefore |
| ... | @@ -301,38 +286,20 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node) | ... | @@ -301,38 +286,20 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node) |
| 301 | | 286 | |
| 302 | while (f.remaining_decls.popOrNull()) |kv| { | 287 | while (f.remaining_decls.popOrNull()) |kv| { |
| 303 | const decl_index = kv.key; | 288 | const decl_index = kv.key; |
| 304 | try flushDecl(self, &f, decl_index); | 289 | try self.flushDecl(&f, decl_index); |
| 305 | } | 290 | } |
| 306 | | 291 | |
| 307 | if (f.err_typedef_buf.items.len == 0) { | 292 | f.all_buffers.items[typedef_index] = .{ |
| 308 | f.all_buffers.items[err_typedef_index] = .{ | 293 | .iov_base = if (f.typedef_buf.items.len > 0) f.typedef_buf.items.ptr else "", |
| 309 | .iov_base = "", | 294 | .iov_len = f.typedef_buf.items.len, |
| 310 | .iov_len = 0, | 295 | }; |
| 311 | }; | 296 | f.file_size += f.typedef_buf.items.len; |
| 312 | } else { | | |
| 313 | f.all_buffers.items[err_typedef_index] = .{ | | |
| 314 | .iov_base = f.err_typedef_buf.items.ptr, | | |
| 315 | .iov_len = f.err_typedef_buf.items.len, | | |
| 316 | }; | | |
| 317 | f.file_size += f.err_typedef_buf.items.len; | | |
| 318 | } | | |
| 319 | | 297 | |
| 320 | // Now the function bodies. | 298 | // Now the function bodies. |
| 321 | try f.all_buffers.ensureUnusedCapacity(gpa, f.fn_count); | 299 | try f.all_buffers.ensureUnusedCapacity(gpa, f.fn_count); |
| 322 | for (decl_keys) |decl_index, i| { | 300 | for (decl_keys) |decl_index, i| |
| 323 | const decl = module.declPtr(decl_index); | 301 | if (module.declPtr(decl_index).getFunction() != null) |
| 324 | if (decl.getFunction() != null) { | 302 | f.appendBufAssumeCapacity(decl_values[i].code.items); |
| 325 | const decl_block = &decl_values[i]; | | |
| 326 | const buf = decl_block.code.items; | | |
| 327 | if (buf.len != 0) { | | |
| 328 | f.all_buffers.appendAssumeCapacity(.{ | | |
| 329 | .iov_base = buf.ptr, | | |
| 330 | .iov_len = buf.len, | | |
| 331 | }); | | |
| 332 | f.file_size += buf.len; | | |
| 333 | } | | |
| 334 | } | | |
| 335 | } | | |
| 336 | | 303 | |
| 337 | const file = self.base.file.?; | 304 | const file = self.base.file.?; |
| 338 | try file.setEndPos(f.file_size); | 305 | try file.setEndPos(f.file_size); |
| ... | @@ -342,7 +309,8 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node) | ... | @@ -342,7 +309,8 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node) |
| 342 | const Flush = struct { | 309 | const Flush = struct { |
| 343 | remaining_decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, void) = .{}, | 310 | remaining_decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, void) = .{}, |
| 344 | typedefs: Typedefs = .{}, | 311 | typedefs: Typedefs = .{}, |
| 345 | err_typedef_buf: std.ArrayListUnmanaged(u8) = .{}, | 312 | typedef_buf: std.ArrayListUnmanaged(u8) = .{}, |
| | 313 | err_buf: std.ArrayListUnmanaged(u8) = .{}, |
| 346 | /// We collect a list of buffers to write, and write them all at once with pwritev 😎 | 314 | /// We collect a list of buffers to write, and write them all at once with pwritev 😎 |
| 347 | all_buffers: std.ArrayListUnmanaged(std.os.iovec_const) = .{}, | 315 | all_buffers: std.ArrayListUnmanaged(std.os.iovec_const) = .{}, |
| 348 | /// Keeps track of the total bytes of `all_buffers`. | 316 | /// Keeps track of the total bytes of `all_buffers`. |
| ... | @@ -356,9 +324,16 @@ const Flush = struct { | ... | @@ -356,9 +324,16 @@ const Flush = struct { |
| 356 | std.hash_map.default_max_load_percentage, | 324 | std.hash_map.default_max_load_percentage, |
| 357 | ); | 325 | ); |
| 358 | | 326 | |
| | 327 | fn appendBufAssumeCapacity(f: *Flush, buf: []const u8) void { |
| | 328 | if (buf.len == 0) return; |
| | 329 | f.all_buffers.appendAssumeCapacity(.{ .iov_base = buf.ptr, .iov_len = buf.len }); |
| | 330 | f.file_size += buf.len; |
| | 331 | } |
| | 332 | |
| 359 | fn deinit(f: *Flush, gpa: Allocator) void { | 333 | fn deinit(f: *Flush, gpa: Allocator) void { |
| 360 | f.all_buffers.deinit(gpa); | 334 | f.all_buffers.deinit(gpa); |
| 361 | f.err_typedef_buf.deinit(gpa); | 335 | f.err_buf.deinit(gpa); |
| | 336 | f.typedef_buf.deinit(gpa); |
| 362 | f.typedefs.deinit(gpa); | 337 | f.typedefs.deinit(gpa); |
| 363 | f.remaining_decls.deinit(gpa); | 338 | f.remaining_decls.deinit(gpa); |
| 364 | } | 339 | } |
| ... | @@ -368,6 +343,57 @@ const FlushDeclError = error{ | ... | @@ -368,6 +343,57 @@ const FlushDeclError = error{ |
| 368 | OutOfMemory, | 343 | OutOfMemory, |
| 369 | }; | 344 | }; |
| 370 | | 345 | |
| | 346 | fn flushTypedefs(self: *C, f: *Flush, typedefs: codegen.TypedefMap.Unmanaged) FlushDeclError!void { |
| | 347 | if (typedefs.count() == 0) return; |
| | 348 | const gpa = self.base.allocator; |
| | 349 | const module = self.base.options.module.?; |
| | 350 | |
| | 351 | try f.typedefs.ensureUnusedCapacityContext(gpa, @intCast(u32, typedefs.count()), .{ |
| | 352 | .mod = module, |
| | 353 | }); |
| | 354 | var it = typedefs.iterator(); |
| | 355 | while (it.next()) |new| { |
| | 356 | const gop = f.typedefs.getOrPutAssumeCapacityContext(new.key_ptr.*, .{ |
| | 357 | .mod = module, |
| | 358 | }); |
| | 359 | if (!gop.found_existing) { |
| | 360 | try f.typedef_buf.appendSlice(gpa, new.value_ptr.rendered); |
| | 361 | } |
| | 362 | } |
| | 363 | } |
| | 364 | |
| | 365 | fn flushErrDecls(self: *C, f: *Flush) FlushDeclError!void { |
| | 366 | const gpa = self.base.allocator; |
| | 367 | const module = self.base.options.module.?; |
| | 368 | |
| | 369 | var object = codegen.Object{ |
| | 370 | .dg = .{ |
| | 371 | .gpa = gpa, |
| | 372 | .module = module, |
| | 373 | .error_msg = null, |
| | 374 | .decl_index = undefined, |
| | 375 | .decl = undefined, |
| | 376 | .fwd_decl = undefined, |
| | 377 | .typedefs = codegen.TypedefMap.initContext(gpa, .{ .mod = module }), |
| | 378 | .typedefs_arena = gpa, |
| | 379 | }, |
| | 380 | .code = f.err_buf.toManaged(gpa), |
| | 381 | .indent_writer = undefined, // set later so we can get a pointer to object.code |
| | 382 | }; |
| | 383 | object.indent_writer = .{ .underlying_writer = object.code.writer() }; |
| | 384 | defer object.dg.typedefs.deinit(); |
| | 385 | defer f.err_buf = object.code.moveToUnmanaged(); |
| | 386 | |
| | 387 | codegen.genErrDecls(&object) catch |err| switch (err) { |
| | 388 | error.AnalysisFail => unreachable, |
| | 389 | else => |e| return e, |
| | 390 | }; |
| | 391 | |
| | 392 | try self.flushTypedefs(f, object.dg.typedefs.unmanaged); |
| | 393 | try f.all_buffers.ensureUnusedCapacity(gpa, 1); |
| | 394 | f.appendBufAssumeCapacity(object.code.items); |
| | 395 | } |
| | 396 | |
| 371 | /// Assumes `decl` was in the `remaining_decls` set, and has already been removed. | 397 | /// Assumes `decl` was in the `remaining_decls` set, and has already been removed. |
| 372 | fn flushDecl(self: *C, f: *Flush, decl_index: Module.Decl.Index) FlushDeclError!void { | 398 | fn flushDecl(self: *C, f: *Flush, decl_index: Module.Decl.Index) FlushDeclError!void { |
| 373 | const module = self.base.options.module.?; | 399 | const module = self.base.options.module.?; |
| ... | @@ -384,43 +410,13 @@ fn flushDecl(self: *C, f: *Flush, decl_index: Module.Decl.Index) FlushDeclError! | ... | @@ -384,43 +410,13 @@ fn flushDecl(self: *C, f: *Flush, decl_index: Module.Decl.Index) FlushDeclError! |
| 384 | const decl_block = self.decl_table.getPtr(decl_index).?; | 410 | const decl_block = self.decl_table.getPtr(decl_index).?; |
| 385 | const gpa = self.base.allocator; | 411 | const gpa = self.base.allocator; |
| 386 | | 412 | |
| 387 | if (decl_block.typedefs.count() != 0) { | 413 | try self.flushTypedefs(f, decl_block.typedefs); |
| 388 | try f.typedefs.ensureUnusedCapacityContext(gpa, @intCast(u32, decl_block.typedefs.count()), .{ | 414 | try f.all_buffers.ensureUnusedCapacity(gpa, 2); |
| 389 | .mod = module, | 415 | f.appendBufAssumeCapacity(decl_block.fwd_decl.items); |
| 390 | }); | 416 | if (decl.getFunction()) |_| |
| 391 | var it = decl_block.typedefs.iterator(); | 417 | f.fn_count += 1 |
| 392 | while (it.next()) |new| { | 418 | else |
| 393 | const gop = f.typedefs.getOrPutAssumeCapacityContext(new.key_ptr.*, .{ | 419 | f.appendBufAssumeCapacity(decl_block.code.items); |
| 394 | .mod = module, | | |
| 395 | }); | | |
| 396 | if (!gop.found_existing) { | | |
| 397 | try f.err_typedef_buf.appendSlice(gpa, new.value_ptr.rendered); | | |
| 398 | } | | |
| 399 | } | | |
| 400 | } | | |
| 401 | | | |
| 402 | if (decl_block.fwd_decl.items.len != 0) { | | |
| 403 | const buf = decl_block.fwd_decl.items; | | |
| 404 | if (buf.len != 0) { | | |
| 405 | try f.all_buffers.append(gpa, .{ | | |
| 406 | .iov_base = buf.ptr, | | |
| 407 | .iov_len = buf.len, | | |
| 408 | }); | | |
| 409 | f.file_size += buf.len; | | |
| 410 | } | | |
| 411 | } | | |
| 412 | if (decl.getFunction() != null) { | | |
| 413 | f.fn_count += 1; | | |
| 414 | } else if (decl_block.code.items.len != 0) { | | |
| 415 | const buf = decl_block.code.items; | | |
| 416 | if (buf.len != 0) { | | |
| 417 | try f.all_buffers.append(gpa, .{ | | |
| 418 | .iov_base = buf.ptr, | | |
| 419 | .iov_len = buf.len, | | |
| 420 | }); | | |
| 421 | f.file_size += buf.len; | | |
| 422 | } | | |
| 423 | } | | |
| 424 | } | 420 | } |
| 425 | | 421 | |
| 426 | pub fn flushEmitH(module: *Module) !void { | 422 | pub fn flushEmitH(module: *Module) !void { |