Skip to content

Commit 80130f9

Browse files
add copy and patch jit infrastructure with a stencil compilation pipeline
1 parent 3ff34d8 commit 80130f9

18 files changed

Lines changed: 587 additions & 2 deletions

Cargo.lock

Lines changed: 106 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[workspace]
2-
members = ["gabagool", "gabagool-debug-adapter"]
2+
members = ["gabagool", "gabagool-debug-adapter", "gabagool-stencils"]
33
default-members = ["gabagool"]
44
resolver = "2"
55

gabagool-stencils/Cargo.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[package]
2+
name = "gabagool-stencils"
3+
version.workspace = true
4+
edition.workspace = true
5+
authors.workspace = true
6+
license.workspace = true
7+
8+
[dependencies]

gabagool-stencils/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
2+
#ifndef STENCIL_CONTEXT_H
3+
#define STENCIL_CONTEXT_H
4+
5+
#include <stdint.h>
6+
7+
typedef struct StencilContext StencilContext;
8+
9+
// every stencil must be a funciton with this signature
10+
typedef void (*StencilFn)(StencilContext *ctx);
11+
12+
typedef struct {
13+
uint64_t imm0;
14+
uint64_t imm1;
15+
} OpImmediate;
16+
17+
// this is the entire execution state, passed to every stencil
18+
struct StencilContext {
19+
uint64_t *stack;
20+
uint64_t stack_pointer;
21+
uint64_t *locals;
22+
uint64_t *mem_base;
23+
uint64_t mem_len;
24+
uint64_t *globals;
25+
const OpImmediate *imm_table;
26+
const StencilFn *fn_table;
27+
uint32_t pc;
28+
uint8_t snapshot_flag;
29+
uint8_t exit_reason;
30+
uint32_t exit_value;
31+
};
32+
33+
#define EXIT_SNAPSHOT 0
34+
#define EXIT_RETURN 1
35+
36+
#endif

gabagool-stencils/src/stencils.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
2+
#include "stencil_context.h"
3+
4+
void nop(StencilContext *ctx) {
5+
ctx->pc += 1;
6+
7+
if (ctx->snapshot_flag) {
8+
ctx->exit_reason = EXIT_SNAPSHOT;
9+
return;
10+
}
11+
12+
__attribute__((musttail)) return ctx->fn_table[ctx->pc](ctx);
13+
}
14+
15+
void i32_const(StencilContext *ctx) {
16+
ctx->stack[ctx->stack_pointer] = (uint32_t)ctx->imm_table[ctx->pc].imm0;
17+
18+
ctx->stack_pointer += 1;
19+
ctx->pc += 1;
20+
21+
if (ctx->snapshot_flag) {
22+
ctx->exit_reason = EXIT_SNAPSHOT;
23+
return;
24+
}
25+
26+
__attribute__((musttail)) return ctx->fn_table[ctx->pc](ctx);
27+
}
28+
29+
void return_(StencilContext *ctx) { ctx->exit_reason = EXIT_RETURN; }

gabagool/Cargo.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,19 @@ license.workspace = true
1010

1111
[dev-dependencies]
1212
insta = "1"
13+
wat = "1"
14+
15+
[dependencies]
16+
libc = { version = "0.2.183", optional = true }
1317

1418
[build-dependencies]
1519
wast = { version = "245.0.1", optional = true }
20+
cc = { version = "1.2.57", optional = true }
21+
object = { version = "0.38.1", optional = true }
22+
1623

1724
[features]
1825
core-tests = ["wast"]
1926
component-tests = []
2027
debugger = []
28+
jit = ["cc", "libc", "object"]

gabagool/build.rs

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,19 @@ fn main() {
2424
)
2525
.unwrap();
2626
}
27+
28+
#[cfg(feature = "jit")]
29+
jit::generate();
30+
31+
#[cfg(not(feature = "jit"))]
32+
{
33+
let out_dir = std::env::var("OUT_DIR").unwrap();
34+
std::fs::write(
35+
std::path::Path::new(&out_dir).join("stencils_generated.rs"),
36+
"",
37+
)
38+
.unwrap();
39+
}
2740
}
2841

2942
#[cfg(feature = "component-tests")]
@@ -607,3 +620,79 @@ mod spec_tests {
607620
rendered.map(|v| v.join(", "))
608621
}
609622
}
623+
624+
#[cfg(feature = "jit")]
625+
mod jit {
626+
use std::{env, fs, path::Path};
627+
628+
use object::{Object, ObjectSection, ObjectSymbol, SymbolKind};
629+
630+
const STENCIL_NAMES: &[&str] = &["nop", "i32_const", "return_"];
631+
632+
pub fn generate() {
633+
println!("cargo::rerun-if-changed=../gabagool-stencils/src/stencils.c");
634+
println!("cargo::rerun-if-changed=../gabagool-stencils/src/stencil_context.h");
635+
636+
let out_dir = env::var("OUT_DIR").unwrap();
637+
638+
let objects = cc::Build::new()
639+
.file("../gabagool-stencils/src/stencils.c")
640+
.include("../gabagool-stencils/src")
641+
.opt_level(3)
642+
.flag("-fno-stack-protector")
643+
.flag("-fno-asynchronous-unwind-tables")
644+
.flag("-fno-exceptions")
645+
.cargo_metadata(false)
646+
.compile_intermediates();
647+
648+
let objects = objects.first().expect("expect .o file");
649+
650+
let obj_data = fs::read(objects).expect("should exist");
651+
let obj_file = object::File::parse(&*obj_data).expect("should parse");
652+
653+
let text_section = obj_file
654+
.sections()
655+
.find(|s| s.name() == Ok("__text") || s.name() == Ok(".text"))
656+
.expect("text section should exist");
657+
658+
let text_data = text_section.data().unwrap();
659+
let text_addr = text_section.address();
660+
661+
let mut sym_addrs = obj_file
662+
.symbols()
663+
.filter(|s| s.kind() == SymbolKind::Text && s.section_index().is_some())
664+
.filter_map(|s| Some((s.name().ok()?, s.address())))
665+
.collect::<Vec<_>>();
666+
667+
sym_addrs.sort_by_key(|&(_, a)| a);
668+
669+
let mut generated = String::new();
670+
671+
for stencil in STENCIL_NAMES {
672+
let prefixed = format!("_{}", stencil);
673+
let idx = sym_addrs
674+
.iter()
675+
.position(|&(name, _addr)| name == *stencil || name == prefixed)
676+
.unwrap_or_else(|| panic!("symbol {stencil} not found"));
677+
678+
let addr = sym_addrs[idx].1;
679+
let next_addr = sym_addrs
680+
.get(idx + 1)
681+
.map(|s| s.1)
682+
.unwrap_or(text_addr + text_data.len() as u64);
683+
684+
let offset = (addr - text_addr) as usize;
685+
let size = (next_addr - addr) as usize;
686+
687+
let bs = text_data.get(offset..offset + size).expect("valid bytes");
688+
689+
generated.push_str(&format!(
690+
"pub const STENCIL_{}: &[u8] = &{:?};\n",
691+
stencil.to_uppercase(),
692+
bs,
693+
));
694+
}
695+
696+
fs::write(Path::new(&out_dir).join("stencils_generated.rs"), generated).unwrap();
697+
}
698+
}

gabagool/src/debugger.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@ impl Debugger {
320320
}
321321
}
322322

323-
#[cfg(test)]
323+
#[cfg(all(test, not(feature = "jit")))]
324324
mod tests {
325325
use super::*;
326326
use crate::Module;

0 commit comments

Comments
 (0)