mech_core/program/compiler/
context.rs1use crate::*;
2use super::*;
3
4#[derive(Debug)]
5pub struct CompileCtx {
6 pub reg_map: HashMap<usize, Register>,
8 pub symbols: HashMap<u64, Register>,
10 pub symbol_ptrs: HashMap<u64, usize>,
12 pub dictionary: HashMap<u64, String>,
14 pub mutable_symbols: HashSet<u64>,
16 pub types: TypeSection,
17 pub features: HashSet<FeatureFlag>,
18 pub const_entries: Vec<ConstEntry>,
19 pub const_blob: Vec<u8>,
20 pub instrs: Vec<EncodedInstr>,
21 pub next_reg: Register,
22}
23
24#[cfg(feature = "compiler")]
25impl CompileCtx {
26 pub fn new() -> Self {
27 Self {
28 reg_map: HashMap::new(),
29 symbols: HashMap::new(),
30 mutable_symbols: HashSet::new(),
31 dictionary: HashMap::new(),
32 types: TypeSection::new(),
33 symbol_ptrs: HashMap::new(),
34 features: HashSet::new(),
35 const_entries: Vec::new(),
36 const_blob: Vec::new(),
37 instrs: Vec::new(),
38 next_reg: 0,
39 }
40 }
41
42 pub fn clear(&mut self) {
43 self.reg_map.clear();
44 self.symbols.clear();
45 self.dictionary.clear();
46 self.mutable_symbols.clear();
47 self.types = TypeSection::new();
48 self.features.clear();
49 self.const_entries.clear();
50 self.const_blob.clear();
51 self.instrs.clear();
52 self.next_reg = 0;
53 }
54
55 pub fn define_symbol(&mut self, id: usize, reg: Register, name: &str, mutable: bool) {
56 let symbol_id = hash_str(name);
57 self.symbols.insert(symbol_id, reg);
58 self.symbol_ptrs.insert(symbol_id, id);
59 self.dictionary.insert(symbol_id, name.to_string());
60 if mutable {
61 self.mutable_symbols.insert(symbol_id);
62 }
63 }
64
65 pub fn alloc_register_for_ptr(&mut self, ptr: usize) -> Register {
66 if let Some(&r) = self.reg_map.get(&ptr) { return r; }
67 let r = self.next_reg;
68 self.next_reg += 1;
69 self.reg_map.insert(ptr, r);
70 r
71 }
72
73 pub fn emit_const_load(&mut self, dst: Register, const_id: u32) {
74 self.instrs.push(EncodedInstr::ConstLoad { dst, const_id });
75 }
76 pub fn emit_nullop(&mut self, fxn_id: u64, dst: Register) {
77 self.instrs.push(EncodedInstr::NullOp { fxn_id, dst });
78 }
79 pub fn emit_unop(&mut self, fxn_id: u64, dst: Register, src: Register) {
80 self.instrs.push(EncodedInstr::UnOp { fxn_id, dst, src });
81 }
82 pub fn emit_binop(&mut self, fxn_id: u64, dst: Register, lhs: Register, rhs: Register) {
83 self.instrs.push(EncodedInstr::BinOp { fxn_id, dst, lhs, rhs });
84 }
85 pub fn emit_ternop(&mut self, fxn_id: u64, dst: Register, a: Register, b: Register, c: Register) {
86 self.instrs.push(EncodedInstr::TernOp { fxn_id, dst, a, b, c });
87 }
88 pub fn emit_quadop(&mut self, fxn_id: u64, dst: Register, a: Register, b: Register, c: Register, d: Register) {
89 self.instrs.push(EncodedInstr::QuadOp { fxn_id, dst, a, b, c, d });
90 }
91 pub fn emit_varop(&mut self, fxn_id: u64, dst: Register, args: Vec<Register>) {
92 self.instrs.push(EncodedInstr::VarArg { fxn_id, dst, args });
93 }
94 pub fn emit_ret(&mut self, src: Register) {
95 self.instrs.push(EncodedInstr::Ret { src })
96 }
97
98 pub fn compile_const(&mut self, bytes: &[u8], value_kind: ValueKind) -> MResult<u32> {
99 let type_id = self.types.get_or_intern(&value_kind);
100 let align = value_kind.align();
101 let next_blob_len = self.const_blob.len() as u64;
102 let padded_off = align_up(next_blob_len, align as u64);
103 if padded_off > next_blob_len {
104 self.const_blob.resize(padded_off as usize, 0);
106 }
107 self.features.insert(FeatureFlag::Builtin(value_kind.to_feature_kind()));
108 let offset = self.const_blob.len() as u64;
109 self.const_blob.extend_from_slice(bytes);
110 let length = (self.const_blob.len() as u64) - offset;
111 let entry = ConstEntry {
112 type_id,
113 enc: ConstEncoding::Inline,
114 align: align as u8,
115 flags: 0,
116 reserved: 0,
117 offset,
118 length,
119 };
120 let const_id = self.const_entries.len() as u32;
121 self.const_entries.push(entry);
122 Ok(const_id)
123 }
124
125 pub fn compile(&mut self) -> MResult<Vec<u8>> {
126
127 let header_size = ByteCodeHeader::HEADER_SIZE as u64;
128 let feat_bytes_len: u64 = 4 + (self.features.len() as u64) * 8;
129 let types_bytes_len: u64 = self.types.byte_len();
130 let const_tbl_len: u64 = (self.const_entries.len() as u64) * ConstEntry::byte_len();
131 let const_blob_len: u64 = self.const_blob.len() as u64;
132 let symbols_len: u64 = (self.symbols.len() as u64) * 13; let instr_bytes_len: u64 = self.instrs.iter().map(|i| i.byte_len()).sum();
134 let dict_len: u64 = self.dictionary.values().map(|s| s.len() as u64 + 12).sum(); let mut offset = header_size; let feature_off = offset; offset += feat_bytes_len; let types_off = offset; offset += types_bytes_len; let const_tbl_off = offset; offset += const_tbl_len; let const_blob_off = offset; offset += const_blob_len; let symbols_off = offset; offset += symbols_len; let instr_off = offset; offset += instr_bytes_len; let dict_off = offset; offset += dict_len; let file_len_before_trailer = offset;
146 let trailer_len = 4u64;
147 let full_file_len = file_len_before_trailer + trailer_len;
148
149 let header = ByteCodeHeader {
151 magic: *b"MECH",
152 version: 1,
153 mech_ver: parse_version_to_u16(env!("CARGO_PKG_VERSION")).unwrap(),
154 flags: 0,
155 reg_count: self.next_reg,
156 instr_count: self.instrs.len() as u32,
157 feature_count: self.features.len() as u32,
158 feature_off,
159
160 types_count: self.types.entries.len() as u32,
161 types_off,
162
163 const_count: self.const_entries.len() as u32,
164 const_tbl_off,
165 const_tbl_len,
166 const_blob_off,
167 const_blob_len,
168
169 symbols_len,
170 symbols_off,
171
172 instr_off,
173 instr_len: instr_bytes_len,
174
175 dict_len,
176 dict_off,
177
178 reserved: 0,
179 };
180
181 let mut buf = Cursor::new(Vec::<u8>::with_capacity(full_file_len as usize));
182
183 header.write_to(&mut buf)?;
185
186 buf.write_u32::<LittleEndian>(self.features.len() as u32)?;
188 for f in &self.features {
189 buf.write_u64::<LittleEndian>(f.as_u64())?;
190 }
191
192 self.types.write_to(&mut buf)?;
194
195 for entry in &self.const_entries {
197 entry.write_to(&mut buf)?;
198 }
199
200 if !self.const_blob.is_empty() {
201 buf.write_all(&self.const_blob)?;
202 }
203
204 for (id, reg) in &self.symbols {
206 let mutable = self.mutable_symbols.contains(id);
207 let entry = SymbolEntry::new(*id, mutable, *reg);
208 entry.write_to(&mut buf)?;
209 }
210
211 for ins in &self.instrs {
213 ins.write_to(&mut buf)?;
214 }
215
216 for (id, name) in &self.dictionary {
218 let dict_entry = DictEntry::new(*id, name);
219 dict_entry.write_to(&mut buf)?;
220 }
221
222 let pos = buf.position();
224 if pos != file_len_before_trailer {
225 return Err(MechError {file: file!().to_string(),tokens: vec![],msg: format!("Buffer position mismatch: expected {}, got {}", file_len_before_trailer, pos),id: line!(),kind: MechErrorKind::GenericError("Buffer position mismatch".to_string()),});
226 }
227
228 let bytes_so_far = buf.get_ref().as_slice();
229 let checksum = crc32fast::hash(bytes_so_far);
230 buf.write_u32::<LittleEndian>(checksum)?;
231
232 if buf.position() != full_file_len {
233 return Err(MechError {file: file!().to_string(),tokens: vec![],msg: format!("Final buffer length mismatch: expected {}, got {}", full_file_len, buf.position()),id: line!(),kind: MechErrorKind::GenericError("Final buffer length mismatch".to_string()),});
234 }
235
236 Ok(buf.into_inner())
237 }
238}
239
240#[inline]
241fn align_up(offset: u64, align: u64) -> u64 {
242 if align == 0 { return offset; }
243 ((offset + align - 1) / align) * align
244}