1use swamp_vm_types::opcode::OpCode;
2use swamp_vm_types::{
3 BinaryInstruction, ConstantMemoryAddress, CountU16, FrameMemoryAddress,
4 FrameMemoryAddressIndirectPointer, FrameMemorySize, InstructionPosition, MemoryAddress,
5 MemorySize,
6};
7
8#[derive(Debug)]
9pub struct PatchPosition(pub InstructionPosition);
10
11pub struct InstructionBuilder {
12 pub instructions: Vec<BinaryInstruction>,
13 pub comments: Vec<String>,
14}
15
16impl InstructionBuilder {}
17
18impl InstructionBuilder {}
19
20impl Default for InstructionBuilder {
21 fn default() -> Self {
22 Self::new()
23 }
24}
25
26impl InstructionBuilder {
27 #[must_use]
28 pub const fn new() -> Self {
29 Self {
30 instructions: Vec::new(),
31 comments: Vec::new(),
32 }
33 }
34
35 #[must_use]
36 pub fn position(&self) -> InstructionPosition {
37 InstructionPosition(self.instructions.len() as u16)
38 }
39
40 pub fn add_jmp_if_equal_placeholder(&mut self, comment: &str) -> PatchPosition {
41 let position = self.position();
42
43 self.add_instruction(OpCode::Bz, &[0], comment);
44
45 PatchPosition(position)
46 }
47
48 pub fn add_jmp_if_not_equal_placeholder(&mut self, comment: &str) -> PatchPosition {
49 let position = self.position();
50
51 self.add_instruction(OpCode::Bnz, &[0], comment);
52
53 PatchPosition(position)
54 }
55
56 pub fn add_vec_iter_next_placeholder(
57 &mut self,
58 iterator_target: FrameMemoryAddress,
59 closure_variable: FrameMemoryAddress,
60 comment: &str,
61 ) -> PatchPosition {
62 let position = self.position();
63 self.add_instruction(
64 OpCode::VecIterNext,
65 &[iterator_target.0, closure_variable.0, 0],
66 comment,
67 );
68 PatchPosition(position)
69 }
70
71 pub fn add_vec_iter_next_pair_placeholder(
72 &mut self,
73 iterator_target: FrameMemoryAddress,
74 closure_variable: FrameMemoryAddress,
75 closure_variable_b: FrameMemoryAddress,
76 comment: &str,
77 ) -> PatchPosition {
78 let position = self.position();
79 self.add_instruction(
80 OpCode::VecIterNextPair,
81 &[
82 iterator_target.0,
83 closure_variable.0,
84 closure_variable_b.0,
85 0,
86 ],
87 comment,
88 );
89 PatchPosition(position)
90 }
91
92 pub fn add_eq_u8_immediate(
93 &mut self,
94 source_addr: FrameMemoryAddress,
95 immediate: u8,
96 comment: &str,
97 ) {
98 self.add_instruction(OpCode::Eq8Imm, &[source_addr.0, immediate as u16], comment);
99 }
100
101 pub fn add_call_placeholder(&mut self, comment: &str) -> PatchPosition {
102 let position = self.position();
103 self.add_instruction(OpCode::Call, &[0], comment);
104 PatchPosition(position)
105 }
106
107 pub fn add_jump_placeholder(&mut self, comment: &str) -> PatchPosition {
108 let position = self.position();
109
110 self.add_instruction(OpCode::Jmp, &[0], comment);
111
112 PatchPosition(position)
113 }
114
115 pub fn add_enter(&mut self, size: FrameMemorySize, comment: &str) {
116 self.add_instruction(OpCode::Enter, &[size.0], comment);
117 }
118
119 pub fn add_mov(
121 &mut self,
122 target: FrameMemoryAddress,
123 source: FrameMemoryAddress,
124 size: MemorySize,
125 comment: &str,
126 ) {
127 self.add_instruction(OpCode::Mov, &[target.0, source.0, size.0], comment);
128 }
129
130 pub fn add_movlp(
132 &mut self,
133 target: FrameMemoryAddress,
134 source: FrameMemoryAddress,
135 size: MemorySize,
136 comment: &str,
137 ) {
138 self.add_instruction(OpCode::MovLp, &[target.0, source.0, size.0], comment);
139 }
140
141 pub fn add_ret(&mut self, comment: &str) {
142 self.add_instruction(OpCode::Ret, &[], comment);
143 }
144
145 pub fn add_hlt(&mut self, comment: &str) {
146 self.add_instruction(OpCode::Hlt, &[], comment);
147 }
148
149 pub fn add_call(&mut self, function_ip: &InstructionPosition, comment: &str) {
150 self.add_instruction(OpCode::Call, &[function_ip.0], comment);
151 }
152
153 pub fn add_host_call(
154 &mut self,
155 host_function_id: u16,
156 arguments_size: MemorySize,
157 comment: &str,
158 ) {
159 self.add_instruction(
160 OpCode::HostCall,
161 &[host_function_id, arguments_size.0],
162 comment,
163 );
164 }
165
166 pub fn patch_jump(
169 &mut self,
170 patch_position: PatchPosition,
171 target_position: &InstructionPosition,
172 ) {
173 const JMP_IF_NOT: u8 = OpCode::Bz as u8;
174 const JMP_IF: u8 = OpCode::Bnz as u8;
175 const JMP: u8 = OpCode::Jmp as u8;
176
177 const VEC_ITER_NEXT: u8 = OpCode::VecIterNext as u8;
178 const VEC_ITER_NEXT_PAIR: u8 = OpCode::VecIterNextPair as u8;
179 const MAP_ITER_NEXT: u8 = OpCode::MapIterNext as u8;
180 const MAP_ITER_NEXT_PAIR: u8 = OpCode::MapIterNextPair as u8;
181
182 let instruction = &mut self.instructions[patch_position.0.0 as usize];
183
184 match instruction.opcode {
185 JMP_IF_NOT => {
186 instruction.operands[0] = target_position.0 as u16 - 1;
187 }
188 JMP_IF => {
189 instruction.operands[0] = target_position.0 as u16 - 1;
190 }
191 JMP => {
192 instruction.operands[0] = target_position.0 as u16 - 1;
193 }
194
195 VEC_ITER_NEXT => {
196 instruction.operands[2] = target_position.0 as u16 - 1;
197 }
198
199 MAP_ITER_NEXT => {
200 instruction.operands[2] = target_position.0 as u16 - 1;
201 }
202
203 VEC_ITER_NEXT_PAIR => {
204 instruction.operands[3] = target_position.0 as u16 - 1;
205 }
206
207 MAP_ITER_NEXT_PAIR => {
208 instruction.operands[3] = target_position.0 as u16 - 1;
209 }
210 _ => panic!("Attempted to patch a non-jump instruction at position {patch_position:?}"),
211 }
212 }
213
214 pub fn patch_jump_here(&mut self, jump_position: PatchPosition) {
216 self.patch_jump(jump_position, &self.position());
217 }
218
219 pub fn patch_call(&mut self, patch_position: PatchPosition, ip: &InstructionPosition) {
222 const CALL: u8 = OpCode::Call as u8;
223
224 let instruction = &mut self.instructions[patch_position.0.0 as usize];
225
226 match instruction.opcode {
227 CALL => {
228 instruction.operands[0] = ip.0 as u16 - 1;
229 }
230 _ => panic!("Attempted to patch a non-call instruction at position {patch_position:?}"),
231 }
232 }
233
234 pub fn add_jmp(&mut self, ip: InstructionPosition, comment: &str) {
235 self.add_instruction(OpCode::Jmp, &[ip.0 - 1], comment);
236 }
237
238 pub fn add_map_iter_init(
239 &mut self,
240 iterator_target: FrameMemoryAddress,
241 pointer_to_map: FrameMemoryAddressIndirectPointer,
242 comment: &str,
243 ) {
244 self.add_instruction(
245 OpCode::MapIterInit,
246 &[iterator_target.0, pointer_to_map.0.0],
247 comment,
248 );
249 }
250
251 pub fn add_map_iter_next(
252 &mut self,
253 iterator_target: FrameMemoryAddress,
254 closure_variable: FrameMemoryAddress,
255 instruction_position: InstructionPosition,
256 comment: &str,
257 ) {
258 self.add_instruction(
259 OpCode::MapIterNext,
260 &[
261 iterator_target.0,
262 closure_variable.0,
263 instruction_position.0,
264 ],
265 comment,
266 );
267 }
268
269 pub fn add_map_iter_next_pair(
270 &mut self,
271 iterator_target: FrameMemoryAddress,
272 closure_variable_key: FrameMemoryAddress,
273 closure_variable_value: FrameMemoryAddress,
274 instruction_position: InstructionPosition,
275 comment: &str,
276 ) {
277 self.add_instruction(
278 OpCode::MapIterNextPair,
279 &[
280 iterator_target.0,
281 closure_variable_key.0,
282 closure_variable_value.0,
283 instruction_position.0,
284 ],
285 comment,
286 );
287 }
288
289 pub fn add_string_from_constant_slice(
290 &mut self,
291 target_string: FrameMemoryAddress,
292 constant_addr: ConstantMemoryAddress,
293 byte_count: MemorySize,
294 comment: &str,
295 ) {
296 let (lower_bits, upper_bits) = Self::convert_to_lower_and_upper(constant_addr.0);
297
298 self.add_instruction(
299 OpCode::StringFromConstantSlice,
300 &[target_string.0, lower_bits, upper_bits, byte_count.0],
301 comment,
302 );
303 }
304
305 pub fn add_string_append(
306 &mut self,
307 dst_offset: FrameMemoryAddress,
308 lhs_offset: FrameMemoryAddress,
309 rhs_offset: FrameMemoryAddress,
310 comment: &str,
311 ) {
312 self.add_instruction(
313 OpCode::StringAppend,
314 &[dst_offset.0, lhs_offset.0, rhs_offset.0],
315 comment,
316 );
317 }
318
319 pub fn add_string_len(
320 &mut self,
321 len_target: FrameMemoryAddress,
322 indirect: FrameMemoryAddressIndirectPointer,
323 comment: &str,
324 ) {
325 self.add_instruction(OpCode::StringLen, &[len_target.0, indirect.0.0], comment);
326 }
327
328 pub fn add_vec_from_slice(
329 &mut self,
330 target: FrameMemoryAddress,
331 source_slice: FrameMemoryAddress,
332 element_size: MemorySize,
333 element_count: CountU16,
334 comment: &str,
335 ) {
336 self.add_instruction(
337 OpCode::VecFromSlice,
338 &[target.0, source_slice.0, element_size.0, element_count.0],
339 comment,
340 );
341 }
342
343 pub fn add_vec_iter_init(
344 &mut self,
345 iterator_target: FrameMemoryAddress,
346 pointer_to_vec: FrameMemoryAddressIndirectPointer,
347 comment: &str,
348 ) {
349 self.add_instruction(
350 OpCode::VecIterInit,
351 &[iterator_target.0, pointer_to_vec.0.0],
352 comment,
353 );
354 }
355
356 pub fn add_vec_iter_next(
357 &mut self,
358 iterator_target: FrameMemoryAddress,
359 closure_variable: FrameMemoryAddress,
360 instruction_position: InstructionPosition,
361 comment: &str,
362 ) {
363 self.add_instruction(
364 OpCode::VecIterNext,
365 &[
366 iterator_target.0,
367 closure_variable.0,
368 instruction_position.0,
369 ],
370 comment,
371 );
372 }
373
374 pub fn add_vec_iter_next_pair(
375 &mut self,
376 iterator_target: FrameMemoryAddress,
377 closure_variable_key: FrameMemoryAddress,
378 closure_variable_value: FrameMemoryAddress,
379 instruction_position: InstructionPosition,
380 comment: &str,
381 ) {
382 self.add_instruction(
383 OpCode::VecIterNextPair,
384 &[
385 iterator_target.0,
386 closure_variable_key.0,
387 closure_variable_value.0,
388 instruction_position.0,
389 ],
390 comment,
391 );
392 }
393
394 fn convert_to_lower_and_upper(data: u32) -> (u16, u16) {
395 let lower_bits = (data & 0xFFFF) as u16;
396 let upper_bits = (data >> 16) as u16;
397
398 (lower_bits, upper_bits)
399 }
400
401 pub fn add_ld32(&mut self, dst_offset: FrameMemoryAddress, value: i32, comment: &str) {
402 let (lower_bits, upper_bits) = Self::convert_to_lower_and_upper(value as u32);
403
404 self.add_instruction(
405 OpCode::Ld32,
406 &[dst_offset.0, lower_bits, upper_bits],
407 comment,
408 );
409 }
410
411 pub fn add_ld_constant(
412 &mut self,
413 target_addr: FrameMemoryAddress,
414 constant_addr: ConstantMemoryAddress,
415 size: MemorySize,
416 comment: &str,
417 ) {
418 let value_u32 = constant_addr.0;
419
420 let lower_bits = (value_u32 & 0xFFFF) as u16;
421 let upper_bits = (value_u32 >> 16) as u16;
422
423 self.add_instruction(
424 OpCode::LdConst,
425 &[target_addr.0, lower_bits, upper_bits, size.0],
426 comment,
427 );
428 }
429
430 pub fn add_ld8(&mut self, dst_offset: FrameMemoryAddress, value: u8, comment: &str) {
431 self.add_instruction(OpCode::Ld8, &[dst_offset.0, value as u16], comment);
432 }
433
434 pub fn add_add_i32(
435 &mut self,
436 dst_offset: FrameMemoryAddress,
437 lhs_offset: FrameMemoryAddress,
438 rhs_offset: FrameMemoryAddress,
439 comment: &str,
440 ) {
441 self.add_instruction(
442 OpCode::AddI32,
443 &[dst_offset.0, lhs_offset.0, rhs_offset.0],
444 comment,
445 );
446 }
447
448 pub fn add_add_f32(
449 &mut self,
450 dst_offset: FrameMemoryAddress,
451 lhs_offset: FrameMemoryAddress,
452 rhs_offset: FrameMemoryAddress,
453 comment: &str,
454 ) {
455 self.add_instruction(
456 OpCode::AddF32,
457 &[dst_offset.0, lhs_offset.0, rhs_offset.0],
458 comment,
459 );
460 }
461
462 pub fn add_mul_i32(
463 &mut self,
464 dst_offset: FrameMemoryAddress,
465 lhs_offset: FrameMemoryAddress,
466 rhs_offset: FrameMemoryAddress,
467 comment: &str,
468 ) {
469 self.add_instruction(
470 OpCode::MulI32,
471 &[dst_offset.0, lhs_offset.0, rhs_offset.0],
472 comment,
473 );
474 }
475
476 pub fn add_neg_i32(
477 &mut self,
478 target: FrameMemoryAddress,
479 source: FrameMemoryAddress,
480 comment: &str,
481 ) {
482 self.add_instruction(OpCode::NegI32, &[target.0, source.0], comment);
483 }
484
485 pub fn add_neg_f32(
486 &mut self,
487 target: FrameMemoryAddress,
488 source: FrameMemoryAddress,
489 comment: &str,
490 ) {
491 self.add_instruction(OpCode::NegF32, &[target.0, source.0], comment);
492 }
493
494 pub fn add_jmp_if(
495 &mut self,
496 condition_offset: FrameMemoryAddress,
497 jmp_target: &InstructionPosition,
498 comment: &str,
499 ) {
500 self.add_instruction(OpCode::Bnz, &[condition_offset.0, jmp_target.0], comment);
501 }
502
503 pub fn add_jmp_if_not(
504 &mut self,
505 condition_offset: MemoryAddress,
506 jmp_target: InstructionPosition,
507 comment: &str,
508 ) {
509 self.add_instruction(OpCode::Bz, &[condition_offset.0, jmp_target.0], comment);
510 }
511
512 pub fn add_lt_i32(
513 &mut self,
514 lhs_offset: FrameMemoryAddress,
515 rhs_offset: FrameMemoryAddress,
516 comment: &str,
517 ) {
518 self.add_instruction(OpCode::LtI32, &[lhs_offset.0, rhs_offset.0], comment);
519 }
520
521 pub fn add_gt_i32(
522 &mut self,
523 lhs_offset: FrameMemoryAddress,
524 rhs_offset: FrameMemoryAddress,
525 comment: &str,
526 ) {
527 self.add_instruction(OpCode::GtI32, &[lhs_offset.0, rhs_offset.0], comment);
528 }
529
530 pub fn add_tst8(&mut self, addr: FrameMemoryAddress, comment: &str) {
531 self.add_instruction(OpCode::Tst8, &[addr.0], comment);
532 }
533
534 pub fn add_map_new_from_slice(
536 &mut self,
537 map_target_addr: FrameMemoryAddress,
538 slice_source_addr: FrameMemoryAddress,
539 key_size: MemorySize,
540 value_size: MemorySize,
541 count: CountU16,
542 comment: &str,
543 ) {
544 self.add_instruction(
545 OpCode::MapNewFromPairs,
546 &[
547 map_target_addr.0,
548 slice_source_addr.0,
549 key_size.0,
550 value_size.0,
551 count.0,
552 ],
553 comment,
554 );
555 }
556
557 pub fn add_map_remove(
558 &mut self,
559 map_target_addr: FrameMemoryAddress,
560 key_addr: FrameMemoryAddress,
561 comment: &str,
562 ) {
563 self.add_instruction(OpCode::MapRemove, &[map_target_addr.0, key_addr.0], comment);
564 }
565
566 fn add_instruction(&mut self, op_code: OpCode, operands: &[u16], comment: &str) {
567 let mut array: [u16; 5] = [0; 5];
568 assert!(operands.len() <= 5);
569 let len = operands.len();
570 array[..len].copy_from_slice(&operands[..len]);
571 self.instructions.push(BinaryInstruction {
572 opcode: op_code as u8,
573 operands: array,
574 });
575 self.comments.push(comment.to_string());
576 }
577 pub fn add_ld_u16(&mut self, dest: FrameMemoryAddress, data: u16, comment: &str) {
578 self.add_instruction(OpCode::Ld16, &[dest.0, data], comment);
579 }
580
581 }