commit b732a5d4604781dd27b372bb604ad6210062b2d3
parent 9437e8f1750cb6133f73a22b6efe18bdf3717181
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Thu, 14 May 2026 17:45:54 -0700
Avoid duplicate segment copies in JIT
Diffstat:
2 files changed, 53 insertions(+), 5 deletions(-)
diff --git a/src/link/link_jit.c b/src/link/link_jit.c
@@ -147,6 +147,39 @@ static uintptr_t vaddr_to_write(const LinkImage* img,
return 0;
}
+static void jit_copy_input_section_bytes(LinkImage* img,
+ const CfreeExecMemRegion* segs) {
+ Compiler* c = img->c;
+ Linker* l = img->linker;
+ u32 i;
+ for (i = 0; i < img->nsections; ++i) {
+ const LinkSection* ls = &img->sections[i];
+ const LinkSegment* seg;
+ ObjBuilder* ob;
+ const Section* s;
+ u32 input_idx;
+ u8* dst;
+ if (ls->input_id == LINK_INPUT_NONE) continue;
+ input_idx = ls->input_id - 1u;
+ if (ls->segment_id == LINK_SEG_NONE || ls->segment_id > img->nsegments)
+ compiler_panic(c, no_loc(),
+ "cfree_jit_from_image: section has invalid segment");
+ seg = &img->segments[ls->segment_id - 1u];
+ ob = (input_idx < img->dbg_objs_n) ? img->dbg_objs[input_idx] : NULL;
+ if (!ob && l && input_idx < LinkInputs_count(&l->inputs))
+ ob = LinkInputs_at(&l->inputs, input_idx)->obj;
+ if (!ob)
+ compiler_panic(c, no_loc(),
+ "cfree_jit_from_image: input section bytes unavailable");
+ s = obj_section_get(ob, ls->obj_section_id);
+ if (!s || s->sem == SSEM_NOBITS) continue;
+ if (s->bytes.total == 0) continue;
+ dst = (u8*)segs[seg->id - 1u].write + (size_t)(ls->vaddr - seg->vaddr);
+ metrics_count(c, "jit.input_section_bytes", s->bytes.total);
+ buf_flatten(&s->bytes, dst);
+ }
+}
+
/* Walk every TLV descriptor and overwrite its three slots with
* (thunk_addr, ctx, per-thread offset). See src/jit/tlv_thunk.h for
* the descriptor contract. Iteration is reloc-driven: every descriptor
@@ -268,6 +301,7 @@ CfreeJit* cfree_jit_from_image(LinkImage* img) {
u64 image_end = 0;
u64 master_size;
int needs_exec = 0;
+ int needs_input_materialize = 0;
u32 i;
if (!img) return NULL;
@@ -335,14 +369,26 @@ CfreeJit* cfree_jit_from_image(LinkImage* img) {
}
/* Master reservation is zeroed; BSS is naturally zero. */
- /* Copy each segment's file bytes to its write alias. */
+ /* Copy synthetic segment buffers to their write aliases. In JIT mode,
+ * ordinary input-section segments intentionally have NULL payload buffers
+ * and are materialized directly from input Buf chunks below. */
metrics_scope_begin(c, "jit.copy_segments");
for (i = 0; i < img->nsegments; ++i) {
const LinkSegment* seg = &img->segments[i];
if (seg->file_size == 0) continue;
+ if (!img->segment_bytes[i]) {
+ needs_input_materialize = 1;
+ continue;
+ }
metrics_count(c, "jit.segment_bytes", seg->file_size);
memcpy(segs[i].write, img->segment_bytes[i], (size_t)seg->file_size);
}
+ if (needs_input_materialize) {
+ if (!img->linker || !img->linker->jit_mode)
+ compiler_panic(c, no_loc(),
+ "cfree_jit_from_image: segment bytes are not materialized");
+ jit_copy_input_section_bytes(img, segs);
+ }
metrics_scope_end(c, "jit.copy_segments");
/* Apply relocations. The patch site bytes go through the write
diff --git a/src/link/link_layout.c b/src/link/link_layout.c
@@ -361,12 +361,14 @@ void link_layout_sections(Linker* l, LinkImage* img, const GcLive* g) {
img->nsegments++;
}
- /* Allocate segment buffers and fix up section offsets/vaddrs. */
+ /* Allocate segment buffers and fix up section offsets/vaddrs. The
+ * JIT lane maps input section bytes directly into execmem, so ordinary
+ * segment payload buffers would be copied only to be copied again. */
for (b = 0; b < SEG_NBUCKETS; ++b) {
if (!bucket_seg[b]) continue;
{
LinkSegment* seg = &img->segments[bucket_seg[b] - 1];
- if (seg->file_size) {
+ if (seg->file_size && !l->jit_mode) {
img->segment_bytes[bucket_seg[b] - 1] =
(u8*)h->alloc(h, (size_t)seg->file_size, 16);
if (!img->segment_bytes[bucket_seg[b] - 1])
@@ -756,7 +758,7 @@ static void link_layout_sections_scripted(Linker* l, LinkImage* img,
seg->align = align_max;
seg->nsections = nsec_in_seg;
file_cursor += file_size_accum;
- if (file_size_accum) {
+ if (file_size_accum && !l->jit_mode) {
img->segment_bytes[img->nsegments] =
(u8*)h->alloc(h, (size_t)file_size_accum, 16);
if (!img->segment_bytes[img->nsegments])
@@ -981,7 +983,7 @@ LinkImage* link_resolve(Linker* l) {
metrics_count(l->c, "link.segments", img->nsegments);
metrics_scope_end(l->c, "link.layout_sections");
metrics_scope_begin(l->c, "link.emit_segment_bytes");
- link_emit_segment_bytes(l, img);
+ if (!l->jit_mode) link_emit_segment_bytes(l, img);
metrics_scope_end(l->c, "link.emit_segment_bytes");
link_assign_symbol_vaddrs(l, img);
link_emit_array_boundaries(l, img);