swamp_runtime/
lib.rs

1/*
2 * Copyright (c) Peter Bjorklund. All rights reserved. https://github.com/swamp/swamp
3 * Licensed under the MIT License. See LICENSE in the project root for license information.
4 */
5mod err_wrt;
6pub mod prelude;
7
8use seq_map::SeqMap;
9use source_map_cache::{FileId, KeepTrackOfSourceLine, SourceFileLineInfo, SourceMapLookup};
10use source_map_cache::{SourceMap, SourceMapWrapper};
11use std::env::current_dir;
12use std::fmt::Write as FmtWrite;
13use std::hash::{DefaultHasher, Hash, Hasher};
14use std::path::{Path, PathBuf};
15use swamp_analyzer::Program;
16use swamp_code_gen::{ConstantInfo, GenFunctionInfo};
17use swamp_code_gen_program::{CodeGenOptions, code_gen_program};
18pub use swamp_compile::CompileOptions;
19use swamp_dep_loader::{RunMode, swamp_registry_path};
20use swamp_semantic::{ConstantId, InternalFunctionDefinitionRef, InternalFunctionId};
21use swamp_std::pack::pack;
22use swamp_std::print::print_fn;
23use swamp_types::TypeRef;
24use swamp_vm::host::{HostArgs, HostFunctionCallback};
25use swamp_vm::memory::ExecutionMode;
26use swamp_vm::{TrapCode, Vm, VmSetup, VmState};
27use swamp_vm_debug_info::{DebugInfo, DebugInfoForPc};
28use swamp_vm_disasm::{disasm_color, display_lines};
29use swamp_vm_isa::{BinaryInstruction, InstructionPosition};
30use swamp_vm_layout::LayoutCache;
31use swamp_vm_types::InstructionRange;
32use swamp_vm_types::types::BasicTypeKind;
33
34pub struct RunConstantsOptions {
35    pub stderr_adapter: Option<Box<dyn FmtWrite>>,
36}
37
38pub struct RunOptions<'a> {
39    //pub stderr_adapter: Option<Box<dyn FmtWrite>>,
40    pub debug_stats_enabled: bool,
41    pub debug_opcodes_enabled: bool,
42    pub debug_info: &'a DebugInfo,
43    pub source_map_wrapper: SourceMapWrapper<'a>,
44    pub debug_operations_enabled: bool,
45    pub max_count: usize, // dangerous
46    pub use_color: bool,
47    pub debug_memory_enabled: bool,
48}
49
50pub fn run_constants_in_order(
51    vm: &mut Vm,
52    constants_in_order: &SeqMap<ConstantId, ConstantInfo>,
53    host_function_callback: &mut dyn HostFunctionCallback,
54    options: &RunOptions,
55) {
56    vm.memory_mut().set_heap_directly_after_constant_area();
57    for (_key, constant) in constants_in_order {
58        // do not reset heap, all allocations from heap should remain (for now)
59        vm.reset_call_stack();
60
61        if constant.target_constant_memory.ty().is_scalar() {
62        } else {
63            // set memory location into to r0
64            vm.registers[0] = constant.target_constant_memory.addr().0;
65        }
66
67        run_function_with_debug(vm, &constant.ip_range, host_function_callback, options);
68
69        if constant.target_constant_memory.ty().is_scalar() {
70            match constant.target_constant_memory.ty().kind {
71                BasicTypeKind::S32 | BasicTypeKind::Fixed32 | BasicTypeKind::U32 => {
72                    let heap_ptr = vm
73                        .memory_mut()
74                        .get_heap_ptr(constant.target_constant_memory.addr().0 as usize)
75                        .cast::<u32>();
76                    unsafe {
77                        *heap_ptr = vm.registers[0];
78                    }
79                }
80                BasicTypeKind::B8 | BasicTypeKind::U8 => {
81                    let heap_ptr = vm
82                        .memory_mut()
83                        .get_heap_ptr(constant.target_constant_memory.addr().0 as usize)
84                        .cast::<u8>();
85                    unsafe {
86                        *heap_ptr = vm.registers[0] as u8;
87                    }
88                }
89                _ => todo!(),
90            }
91        }
92
93        let return_layout = constant.target_constant_memory.ty();
94
95        assert_eq!(
96            constant.target_constant_memory.size(),
97            return_layout.total_size
98        );
99
100        // TODO: Bring this back
101        /*
102        if let Some(x) = &mut options.stderr_adapter {
103            swamp_vm_pretty_print::print_value(
104                x.as_mut(),
105                vm.frame_memory(),
106                vm.memory(),
107                StackMemoryAddress(0),
108                return_layout,
109                &constant.constant_ref.assigned_name,
110            )
111                .unwrap();
112        }
113
114         */
115    }
116
117    // We need to properly preserve string headers when incorporating heap into constant area
118    vm.memory_mut().incorporate_heap_into_constant_area();
119}
120
121// "/Users/peter/external/swamp_autobattler/scripts"
122#[must_use]
123pub fn crate_and_registry(path_to_swamp: &Path, run_mode: &RunMode) -> SourceMap {
124    let mut mounts = SeqMap::new();
125    //  let path_buf = Path::new(path_to_swamp).to_path_buf();
126    mounts
127        .insert("crate".to_string(), path_to_swamp.to_path_buf())
128        .unwrap();
129
130    if let Some(found_swamp_home) = swamp_registry_path(run_mode) {
131        mounts
132            .insert("registry".to_string(), found_swamp_home)
133            .unwrap();
134    }
135
136    SourceMap::new(&mounts).expect("source map failed")
137}
138
139pub struct CompileAndMaybeCodeGenResult {
140    pub compile: CompileResult,
141    pub codegen: Option<CodeGenResult>,
142}
143
144pub struct CompileResult {
145    pub program: Program,
146}
147
148pub struct CodeGenResult {
149    pub instructions: Vec<BinaryInstruction>,
150    pub constants_in_order: SeqMap<ConstantId, ConstantInfo>,
151    pub functions: SeqMap<InternalFunctionId, GenFunctionInfo>,
152    pub prepared_constant_memory: Vec<u8>,
153    pub layout_cache: LayoutCache,
154    pub debug_info: DebugInfo,
155}
156
157impl CodeGenResult {
158    #[must_use]
159    pub fn find_function(&self, formal_name: &str) -> Option<&GenFunctionInfo> {
160        self.functions
161            .values()
162            .find(|&func| func.internal_function_definition.assigned_name == formal_name)
163    }
164}
165
166pub fn compile_main_path(
167    source_map: &mut SourceMap,
168    root_module_path: &[String],
169    options: &CompileOptions,
170) -> Option<CompileResult> {
171    let program =
172        swamp_compile::bootstrap_and_compile(source_map, root_module_path, options).ok()?;
173
174    Some(CompileResult { program })
175}
176
177#[must_use]
178pub fn code_gen(
179    program: &Program,
180    source_map_wrapper: &SourceMapWrapper,
181    code_gen_options: &CodeGenOptions,
182) -> CodeGenResult {
183    let top_gen_state = code_gen_program(program, source_map_wrapper, code_gen_options);
184
185    let all_types = top_gen_state.codegen_state.layout_cache.clone();
186    let (instructions, constants_in_order, emit_function_infos, constant_memory, debug_info) =
187        top_gen_state.take_instructions_and_constants();
188
189    CodeGenResult {
190        debug_info,
191        instructions,
192        constants_in_order,
193        functions: emit_function_infos,
194        prepared_constant_memory: constant_memory,
195        layout_cache: all_types,
196    }
197}
198
199#[must_use]
200pub fn create_vm_with_standard_settings(
201    instructions: &[BinaryInstruction],
202    prepared_constant_memory: &[u8],
203) -> Vm {
204    let vm_setup = VmSetup {
205        stack_memory_size: 1024 * 1024 * 1024, // 1 GiB
206        heap_memory_size: 512 * 1024,          // 512 KiB for transient heap allocation (strings)
207        constant_memory: prepared_constant_memory.to_vec(),
208        debug_opcodes_enabled: false,
209        debug_stats_enabled: false,
210        debug_operations_enabled: false,
211    };
212
213    Vm::new(instructions.to_vec(), vm_setup)
214}
215
216pub struct VmOptions {
217    pub stack_size: usize,
218    pub heap_size: usize,
219}
220
221#[must_use]
222pub fn create_vm_with_options(
223    instructions: &[BinaryInstruction],
224    prepared_constant_memory: &[u8],
225    vm_options: &VmOptions,
226) -> Vm {
227    let vm_setup = VmSetup {
228        stack_memory_size: vm_options.stack_size,
229        heap_memory_size: vm_options.heap_size,
230        constant_memory: prepared_constant_memory.to_vec(),
231        debug_opcodes_enabled: false,
232        debug_stats_enabled: false,
233        debug_operations_enabled: false,
234    };
235
236    Vm::new(instructions.to_vec(), vm_setup)
237}
238
239pub fn run_first_time(
240    vm: &mut Vm,
241    constants_in_order: &SeqMap<ConstantId, ConstantInfo>,
242    host_function_callback: &mut dyn HostFunctionCallback,
243    options: &RunOptions,
244) {
245    run_constants_in_order(vm, constants_in_order, host_function_callback, options);
246}
247
248pub fn run_as_fast_as_possible(
249    vm: &mut Vm,
250    function_to_run: &GenFunctionInfo,
251    host_function_callback: &mut dyn HostFunctionCallback,
252    run_options: RunOptions,
253) {
254    vm.reset_minimal_stack_and_fp();
255    vm.state = VmState::Normal;
256    vm.debug_opcodes_enabled = false;
257    vm.debug_operations_enabled = run_options.debug_operations_enabled;
258    vm.debug_stats_enabled = run_options.debug_stats_enabled;
259
260    vm.execute_from_ip(&function_to_run.ip_range.start, host_function_callback);
261    if matches!(vm.state, VmState::Trap(_) | VmState::Panic(_)) {
262        show_crash_info(vm, run_options.debug_info, &run_options.source_map_wrapper);
263    }
264}
265
266fn calculate_memory_checksum(memory: &[u8]) -> u64 {
267    let mut hasher = DefaultHasher::new();
268    memory.hash(&mut hasher);
269    hasher.finish()
270}
271
272pub fn run_function(
273    vm: &mut Vm,
274    ip_range: &InstructionRange,
275    host_function_callback: &mut dyn HostFunctionCallback,
276    run_options: &RunOptions,
277) {
278    vm.reset_minimal_stack_and_fp();
279
280    vm.state = VmState::Normal;
281
282    vm.execute_from_ip(&ip_range.start, host_function_callback);
283
284    if matches!(vm.state, VmState::Trap(_) | VmState::Panic(_)) {
285        show_crash_info(vm, run_options.debug_info, &run_options.source_map_wrapper);
286    }
287}
288
289pub fn show_call_stack(
290    vm: &Vm,
291    debug_info: &DebugInfo,
292    info: &DebugInfoForPc,
293    source_map_wrapper: &SourceMapWrapper,
294) {
295    // Show call stack
296    eprintln!("\nšŸ“ž Call stack:");
297
298    // Current function (where the crash occurred)
299    if info.meta.node.span.file_id != 0 {
300        let (line, _column) = source_map_wrapper.source_map.get_span_location_utf8(
301            info.meta.node.span.file_id,
302            info.meta.node.span.offset as usize,
303        );
304        let relative_path = source_map_wrapper
305            .source_map
306            .fetch_relative_filename(info.meta.node.span.file_id);
307
308        // Get the actual source line
309        if let Some(source_line) =
310            source_map_wrapper.get_source_line(info.meta.node.span.file_id as FileId, line)
311        {
312            eprintln!(
313                "  {}: {} {}",
314                tinter::bright_cyan("0"),
315                tinter::blue(&info.function_debug_info.name),
316                tinter::bright_black("(current)")
317            );
318            eprintln!(
319                "{:4} {} {}",
320                tinter::bright_black(&line.to_string()),
321                tinter::green("|"),
322                source_line.trim()
323            );
324            eprintln!(
325                "{} {}",
326                tinter::bright_black("->"),
327                tinter::cyan(&format!("{relative_path}:{line}"))
328            );
329        } else {
330            eprintln!(
331                "  {}: {} {}",
332                tinter::bright_cyan("0"),
333                tinter::blue(&info.function_debug_info.name),
334                tinter::bright_black("(current)")
335            );
336            eprintln!(
337                "{} {}",
338                tinter::bright_black("->"),
339                tinter::cyan(&format!("{relative_path}:{line}"))
340            );
341        }
342    } else {
343        eprintln!(
344            "  {}: {} {}",
345            tinter::bright_cyan("0"),
346            tinter::blue(&info.function_debug_info.name),
347            tinter::bright_black("(current)")
348        );
349    }
350
351    let call_stack = vm.call_stack();
352    for (i, frame) in call_stack.iter().enumerate().rev() {
353        let frame_pc = if frame.return_address > 0 {
354            frame.return_address - 1
355        } else {
356            frame.return_address
357        };
358
359        if let Some(frame_info) = debug_info.fetch(frame_pc) {
360            if frame_info.meta.node.span.file_id != 0 {
361                let (line, _column) = source_map_wrapper.source_map.get_span_location_utf8(
362                    frame_info.meta.node.span.file_id,
363                    frame_info.meta.node.span.offset as usize,
364                );
365                let relative_path = source_map_wrapper
366                    .source_map
367                    .fetch_relative_filename(frame_info.meta.node.span.file_id);
368
369                if let Some(source_line) = source_map_wrapper
370                    .get_source_line(frame_info.meta.node.span.file_id as FileId, line)
371                {
372                    eprintln!(
373                        "  {}: {}",
374                        tinter::bright_cyan(&(i + 1).to_string()),
375                        tinter::blue(&frame_info.function_debug_info.name)
376                    );
377                    eprintln!(
378                        "{:4} {} {}",
379                        tinter::bright_black(&line.to_string()),
380                        tinter::green("|"),
381                        source_line.trim()
382                    );
383                    eprintln!(
384                        "{} {}",
385                        tinter::bright_black("->"),
386                        tinter::cyan(&format!("{relative_path}:{line}"))
387                    );
388                } else {
389                    eprintln!(
390                        "  {}: {}",
391                        tinter::bright_cyan(&(i + 1).to_string()),
392                        tinter::blue(&frame_info.function_debug_info.name)
393                    );
394                    eprintln!(
395                        "{} {}",
396                        tinter::bright_black("->"),
397                        tinter::cyan(&format!("{relative_path}:{line}"))
398                    );
399                }
400            } else {
401                eprintln!(
402                    "  {}: {}",
403                    tinter::bright_cyan(&(i + 1).to_string()),
404                    tinter::blue(&frame_info.function_debug_info.name)
405                );
406            }
407        } else {
408            eprintln!(
409                "  {}: {} {}",
410                tinter::bright_cyan(&(i + 1).to_string()),
411                tinter::red("<unknown function>"),
412                tinter::bright_black(&format!("(pc: {frame_pc:04X})"))
413            );
414        }
415    }
416}
417
418pub fn show_crash_info(vm: &Vm, debug_info: &DebugInfo, source_map_wrapper: &SourceMapWrapper) {
419    let pc = vm.pc();
420
421    // PC has advanced past the instruction that caused the trap/panic, so look at pc - 1
422
423    let trap_pc = if pc > 0 { pc - 1 } else { pc };
424
425    if let Some(info) = debug_info.fetch(trap_pc) {
426        match &vm.state {
427            VmState::Trap(trap_code) => {
428                eprintln!("\n🚫 VM TRAP: {trap_code}");
429            }
430            VmState::Panic(message) => {
431                eprintln!("\nšŸ’„ VM PANIC: {message}");
432            }
433            _ => unreachable!(),
434        }
435
436        if info.meta.node.span.file_id != 0 {
437            let (line, column) = source_map_wrapper.source_map.get_span_location_utf8(
438                info.meta.node.span.file_id,
439                info.meta.node.span.offset as usize,
440            );
441
442            eprintln!("šŸ“ Source location:");
443            let mut string = String::new();
444            display_lines(
445                &mut string,
446                info.meta.node.span.file_id as FileId,
447                line.saturating_sub(2), // Show a couple lines before
448                line + 2,               // Show a couple lines after
449                source_map_wrapper,
450                true,
451            );
452            eprint!("{string}");
453
454            let relative_path = source_map_wrapper
455                .source_map
456                .fetch_relative_filename(info.meta.node.span.file_id);
457            eprintln!("   at {relative_path}:{line}:{column}");
458        }
459
460        // Also show the instruction that caused the trap/panic
461        let instruction = &vm.instructions()[trap_pc];
462        let disassembler_string = disasm_color(
463            instruction,
464            &info.function_debug_info.frame_memory,
465            &info.meta,
466            &InstructionPosition(trap_pc as u32),
467        );
468        eprintln!("šŸ’» Failing instruction: {trap_pc:04X}> {disassembler_string}");
469
470        show_call_stack(vm, debug_info, &info, source_map_wrapper);
471    }
472}
473
474pub fn run_function_with_debug(
475    vm: &mut Vm,
476    function_to_run: &InstructionRange,
477    host_function_callback: &mut dyn HostFunctionCallback,
478    run_options: &RunOptions,
479) {
480    vm.reset_minimal_stack_and_fp();
481    //vm.reset_debug();
482    vm.state = VmState::Normal;
483    vm.debug_opcodes_enabled = run_options.debug_opcodes_enabled;
484    vm.debug_operations_enabled = run_options.debug_operations_enabled;
485    vm.debug_stats_enabled = run_options.debug_stats_enabled;
486    vm.set_pc(&function_to_run.start);
487
488    let mut debug_count = 0;
489
490    let use_color = run_options.use_color;
491
492    let mut last_line_info = KeepTrackOfSourceLine::new();
493
494    let saved_fp = vm.memory().constant_memory_size;
495    let hash_before: u64 = if run_options.debug_memory_enabled {
496        calculate_memory_checksum(vm.all_memory_up_to(saved_fp))
497    } else {
498        0
499    };
500
501    while !vm.is_execution_complete() {
502        debug_count += 1;
503
504        if run_options.max_count != 0 && (debug_count >= run_options.max_count) {
505            if vm.state == VmState::Normal {
506                vm.internal_trap(TrapCode::StoppedByTestHarness);
507            }
508            break;
509        }
510
511        let pc = vm.pc();
512        #[cfg(feature = "debug_vm")]
513        if run_options.debug_opcodes_enabled {
514            let regs = [
515                0, 1, 2, 3, 4, 5, 6, 7, 8, 128, 129, 130, 131, 132, 133, 134, 135,
516            ];
517            if use_color {
518                print!(
519                    "{}",
520                    tinter::bright_black(&format!("fp:{:08X}, sp:{:08X} ", vm.fp(), vm.sp(),))
521                );
522
523                for reg in regs {
524                    let reg_name = &format!("r{reg}");
525                    print!(
526                        "{}",
527                        tinter::bright_black(&format!("{reg_name:>3}:{:08X}, ", vm.registers[reg]))
528                    );
529                }
530                println!();
531            } else {
532                // TODO!: Use style instead
533                print!("{}", &format!("fp:{:08X}, sp:{:08X}, ", vm.fp(), vm.sp()));
534
535                for reg in regs {
536                    let reg_name = &format!("r{reg}");
537                    print!("{}", &format!("{reg_name:>3}:{:08X}, ", vm.registers[reg]));
538                }
539                println!();
540            }
541
542            let info = run_options.debug_info.fetch(pc).unwrap();
543
544            if info.meta.node.span.file_id != 0 {
545                let (line, column) = run_options
546                    .source_map_wrapper
547                    .source_map
548                    .get_span_location_utf8(
549                        info.meta.node.span.file_id,
550                        info.meta.node.span.offset as usize,
551                    );
552                let source_line_info = SourceFileLineInfo {
553                    row: line,
554                    file_id: info.meta.node.span.file_id as usize,
555                };
556
557                if let Some((start_row, end_row)) =
558                    last_line_info.check_if_new_line(&source_line_info)
559                {
560                    let mut string = String::new();
561                    display_lines(
562                        &mut string,
563                        source_line_info.file_id as FileId,
564                        start_row,
565                        end_row,
566                        &run_options.source_map_wrapper,
567                        true,
568                    );
569                    print!("{string}");
570                }
571            }
572
573            let instruction = &vm.instructions()[pc];
574            let string = disasm_color(
575                instruction,
576                &info.function_debug_info.frame_memory,
577                &info.meta,
578                &InstructionPosition(pc as u32),
579            );
580            println!("{pc:04X}> {string}");
581        }
582
583        vm.step(host_function_callback);
584
585        // Check if VM encountered a trap or panic and show source information
586        if matches!(vm.state, VmState::Trap(_) | VmState::Panic(_)) {
587            show_crash_info(vm, run_options.debug_info, &run_options.source_map_wrapper);
588        }
589
590        if run_options.debug_memory_enabled
591            && vm.memory().execution_mode != ExecutionMode::ConstantEvaluation
592        {
593            // During constant execution, of course the constant memory changes
594            let hash_after = calculate_memory_checksum(vm.all_memory_up_to(saved_fp));
595            //vm.state = VmState::Trap(TrapCode::VecBoundsFail);
596            assert!(
597                (hash_after == hash_before),
598                "INTERNAL ERROR: constant memory has been written to"
599            );
600        }
601    }
602}
603
604pub struct CompileAndCodeGenOptions {
605    pub compile_options: CompileOptions,
606    pub code_gen_options: CodeGenOptions,
607    pub skip_codegen: bool,
608    pub run_mode: RunMode,
609}
610
611pub struct CompileCodeGenAndVmOptions {
612    pub vm_options: VmOptions,
613    pub codegen: CompileAndCodeGenOptions,
614}
615
616#[must_use]
617pub fn compile_and_code_gen(
618    source_map: &mut SourceMap,
619    main_module_path: &[String],
620    options: &CompileAndCodeGenOptions,
621) -> Option<CompileAndMaybeCodeGenResult> {
622    let current_dir = PathBuf::from(Path::new(""));
623
624    let compile_result = compile_main_path(source_map, main_module_path, &options.compile_options)?;
625
626    let source_map_wrapper = SourceMapWrapper {
627        source_map,
628        current_dir,
629    };
630
631    let maybe_code_gen_result =
632        if options.skip_codegen || !compile_result.program.state.errors().is_empty() {
633            None
634        } else {
635            let code_gen_result = code_gen(
636                &compile_result.program,
637                &source_map_wrapper,
638                &options.code_gen_options,
639            );
640            Some(code_gen_result)
641        };
642
643    Some(CompileAndMaybeCodeGenResult {
644        compile: compile_result,
645        codegen: maybe_code_gen_result,
646    })
647}
648
649pub struct CompileCodeGenVmResult {
650    pub compile: CompileResult,
651    pub codegen: CodeGenAndVmResult,
652}
653
654pub enum CompileAndVmResult {
655    CompileOnly(CompileResult),
656    CompileAndVm(CompileCodeGenVmResult),
657}
658
659pub struct CodeGenAndVmResult {
660    pub vm: Vm,
661    pub code_gen_result: CodeGenResult,
662}
663
664pub struct StandardOnlyHostCallbacks {}
665
666impl HostFunctionCallback for StandardOnlyHostCallbacks {
667    fn dispatch_host_call(&mut self, args: HostArgs) {
668        match args.function_id {
669            1 => print_fn(args),
670            2 => pack(args),
671
672            _ => panic!("unknown external {}", args.function_id),
673        }
674    }
675}
676
677impl CompileCodeGenVmResult {
678    #[must_use]
679    pub fn get_internal_member_function(
680        &self,
681        ty: &TypeRef,
682        member_function_str: &str,
683    ) -> Option<&InternalFunctionDefinitionRef> {
684        self.compile
685            .program
686            .state
687            .associated_impls
688            .get_internal_member_function(ty, member_function_str)
689    }
690    #[must_use]
691    pub fn get_gen_internal_member_function(
692        &self,
693        ty: &TypeRef,
694        member_function_str: &str,
695    ) -> Option<&GenFunctionInfo> {
696        let x = self
697            .get_internal_member_function(ty, member_function_str)
698            .unwrap();
699
700        self.codegen
701            .code_gen_result
702            .functions
703            .get(&x.program_unique_id)
704    }
705}
706
707#[must_use]
708pub fn compile_codegen_and_create_vm_and_run_first_time(
709    source_map: &mut SourceMap,
710    root_module: &[String],
711    compile_and_code_gen_options: CompileCodeGenAndVmOptions,
712) -> Option<CompileAndVmResult> {
713    let result =
714        compile_codegen_and_create_vm(source_map, root_module, &compile_and_code_gen_options);
715    if let Some(mut first_result) = result {
716        if let CompileAndVmResult::CompileAndVm(found_result) = &mut first_result {
717            let mut callbacks = StandardOnlyHostCallbacks {};
718            let run_first_options = RunOptions {
719                debug_stats_enabled: false,
720                debug_opcodes_enabled: false,
721                debug_operations_enabled: false,
722                use_color: true,
723                max_count: 0,
724                debug_info: &found_result.codegen.code_gen_result.debug_info,
725                source_map_wrapper: SourceMapWrapper {
726                    source_map,
727                    current_dir: current_dir().unwrap(),
728                },
729                debug_memory_enabled: false,
730            };
731
732            run_first_time(
733                &mut found_result.codegen.vm,
734                &found_result.codegen.code_gen_result.constants_in_order,
735                &mut callbacks,
736                &run_first_options,
737            );
738            Some(first_result)
739        } else {
740            None
741        }
742    } else {
743        None
744    }
745}
746
747/// The root module is needed so it knows which mod that should be considered.
748#[must_use]
749pub fn compile_codegen_and_create_vm(
750    source_map: &mut SourceMap,
751    root_module: &[String],
752    compile_and_code_gen_options: &CompileCodeGenAndVmOptions,
753) -> Option<CompileAndVmResult> {
754    let compile_and_maybe_code_gen = compile_and_code_gen(
755        source_map,
756        root_module,
757        &compile_and_code_gen_options.codegen,
758    )?;
759
760    if let Some(code_gen_result) = compile_and_maybe_code_gen.codegen {
761        let vm = create_vm_with_options(
762            &code_gen_result.instructions,
763            &code_gen_result.prepared_constant_memory,
764            &compile_and_code_gen_options.vm_options,
765        );
766
767        let code_gen_and_vm = CodeGenAndVmResult {
768            vm,
769            code_gen_result,
770        };
771
772        Some(CompileAndVmResult::CompileAndVm(CompileCodeGenVmResult {
773            compile: compile_and_maybe_code_gen.compile,
774            codegen: code_gen_and_vm,
775        }))
776    } else {
777        Some(CompileAndVmResult::CompileOnly(
778            compile_and_maybe_code_gen.compile,
779        ))
780    }
781}