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