| ... | ... | @@ -260,30 +260,15 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node) |
| 260 | 260 | var f: Flush = .{}; |
| 261 | 261 | defer f.deinit(gpa); |
| 262 | 262 | |
| 263 | | // Covers zig.h and err_typedef_item. |
| 263 | // Covers zig.h and typedef. |
| 264 | 264 | try f.all_buffers.ensureUnusedCapacity(gpa, 2); |
| 265 | 265 | |
| 266 | | if (zig_h.len != 0) { |
| 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 | | } |
| 266 | f.appendBufAssumeCapacity(zig_h); |
| 273 | 267 | |
| 274 | | const err_typedef_writer = f.err_typedef_buf.writer(gpa); |
| 275 | | const err_typedef_index = f.all_buffers.items.len; |
| 268 | const typedef_index = f.all_buffers.items.len; |
| 276 | 269 | f.all_buffers.items.len += 1; |
| 277 | 270 | |
| 278 | | if (module.global_error_set.size > 0) { |
| 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 | | } |
| 271 | try self.flushErrDecls(&f); |
| 287 | 272 | |
| 288 | 273 | // Typedefs, forward decls, and non-functions first. |
| 289 | 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 | 286 | |
| 302 | 287 | while (f.remaining_decls.popOrNull()) |kv| { |
| 303 | 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) { |
| 308 | | f.all_buffers.items[err_typedef_index] = .{ |
| 309 | | .iov_base = "", |
| 310 | | .iov_len = 0, |
| 311 | | }; |
| 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 | | } |
| 292 | f.all_buffers.items[typedef_index] = .{ |
| 293 | .iov_base = if (f.typedef_buf.items.len > 0) f.typedef_buf.items.ptr else "", |
| 294 | .iov_len = f.typedef_buf.items.len, |
| 295 | }; |
| 296 | f.file_size += f.typedef_buf.items.len; |
| 319 | 297 | |
| 320 | 298 | // Now the function bodies. |
| 321 | 299 | try f.all_buffers.ensureUnusedCapacity(gpa, f.fn_count); |
| 322 | | for (decl_keys) |decl_index, i| { |
| 323 | | const decl = module.declPtr(decl_index); |
| 324 | | if (decl.getFunction() != null) { |
| 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 | | } |
| 300 | for (decl_keys) |decl_index, i| |
| 301 | if (module.declPtr(decl_index).getFunction() != null) |
| 302 | f.appendBufAssumeCapacity(decl_values[i].code.items); |
| 336 | 303 | |
| 337 | 304 | const file = self.base.file.?; |
| 338 | 305 | try file.setEndPos(f.file_size); |
| ... | ... | @@ -342,7 +309,8 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node) |
| 342 | 309 | const Flush = struct { |
| 343 | 310 | remaining_decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, void) = .{}, |
| 344 | 311 | typedefs: Typedefs = .{}, |
| 345 | | err_typedef_buf: std.ArrayListUnmanaged(u8) = .{}, |
| 312 | typedef_buf: std.ArrayListUnmanaged(u8) = .{}, |
| 313 | err_buf: std.ArrayListUnmanaged(u8) = .{}, |
| 346 | 314 | /// We collect a list of buffers to write, and write them all at once with pwritev 😎 |
| 347 | 315 | all_buffers: std.ArrayListUnmanaged(std.os.iovec_const) = .{}, |
| 348 | 316 | /// Keeps track of the total bytes of `all_buffers`. |
| ... | ... | @@ -356,9 +324,16 @@ const Flush = struct { |
| 356 | 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 | 333 | fn deinit(f: *Flush, gpa: Allocator) void { |
| 360 | 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 | 337 | f.typedefs.deinit(gpa); |
| 363 | 338 | f.remaining_decls.deinit(gpa); |
| 364 | 339 | } |
| ... | ... | @@ -368,6 +343,57 @@ const FlushDeclError = error{ |
| 368 | 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 | 397 | /// Assumes `decl` was in the `remaining_decls` set, and has already been removed. |
| 372 | 398 | fn flushDecl(self: *C, f: *Flush, decl_index: Module.Decl.Index) FlushDeclError!void { |
| 373 | 399 | const module = self.base.options.module.?; |
| ... | ... | @@ -384,43 +410,13 @@ fn flushDecl(self: *C, f: *Flush, decl_index: Module.Decl.Index) FlushDeclError! |
| 384 | 410 | const decl_block = self.decl_table.getPtr(decl_index).?; |
| 385 | 411 | const gpa = self.base.allocator; |
| 386 | 412 | |
| 387 | | if (decl_block.typedefs.count() != 0) { |
| 388 | | try f.typedefs.ensureUnusedCapacityContext(gpa, @intCast(u32, decl_block.typedefs.count()), .{ |
| 389 | | .mod = module, |
| 390 | | }); |
| 391 | | var it = decl_block.typedefs.iterator(); |
| 392 | | while (it.next()) |new| { |
| 393 | | const gop = f.typedefs.getOrPutAssumeCapacityContext(new.key_ptr.*, .{ |
| 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 | | } |
| 413 | try self.flushTypedefs(f, decl_block.typedefs); |
| 414 | try f.all_buffers.ensureUnusedCapacity(gpa, 2); |
| 415 | f.appendBufAssumeCapacity(decl_block.fwd_decl.items); |
| 416 | if (decl.getFunction()) |_| |
| 417 | f.fn_count += 1 |
| 418 | else |
| 419 | f.appendBufAssumeCapacity(decl_block.code.items); |
| 424 | 420 | } |
| 425 | 421 | |
| 426 | 422 | pub fn flushEmitH(module: *Module) !void { |