swamp_code_gen/
top_state.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 */
5use crate::code_bld::CodeBuilderOptions;
6use crate::state::CodeGenState;
7use crate::{ConstantInfo, FunctionInData, FunctionIps, GenFunctionInfo};
8use seq_map::SeqMap;
9use source_map_cache::SourceMapWrapper;
10use swamp_semantic::{ConstantId, ConstantRef, InternalFunctionId};
11
12use swamp_attributes::Attributes;
13use swamp_vm_debug_info::{DebugInfo, FunctionDebugInfo};
14use swamp_vm_instr_build::{InstructionBuilderState, PatchPosition};
15use swamp_vm_types::types::FunctionInfoKind;
16use swamp_vm_types::{
17    BinaryInstruction, InstructionPosition, InstructionPositionOffset, InstructionRange, Meta,
18};
19use tracing::error;
20
21/// Top-level container that owns both states
22pub struct TopLevelGenState {
23    pub builder_state: InstructionBuilderState,
24    pub codegen_state: CodeGenState,
25    pub code_builder_options: CodeBuilderOptions,
26}
27
28impl TopLevelGenState {
29    #[must_use]
30    pub fn new(code_builder_options: CodeBuilderOptions) -> Self {
31        Self {
32            builder_state: InstructionBuilderState::new(),
33            codegen_state: CodeGenState::new(),
34            code_builder_options,
35        }
36    }
37
38    #[must_use]
39    pub const fn debug_info(&self) -> &DebugInfo {
40        &self.codegen_state.debug_info
41    }
42    #[must_use]
43    pub const fn function_ips(&self) -> &FunctionIps {
44        &self.codegen_state.function_ips
45    }
46
47    pub fn reserve_space_for_constants(&mut self, constants: &[ConstantRef]) {
48        self.codegen_state.reserve_space_for_constants(constants);
49    }
50
51    #[must_use]
52    pub fn is_host_call(attributes: &Attributes) -> bool {
53        !attributes.get_attributes("host_call").is_empty()
54    }
55    #[must_use]
56    pub fn is_test_call(attributes: &Attributes) -> bool {
57        !attributes.get_attributes("test").is_empty()
58    }
59
60    pub fn finalize(&mut self) {
61        for function_fixup in &self.codegen_state.function_fixups {
62            if let Some(func) = self.codegen_state.function_infos.get(&function_fixup.fn_id) {
63                self.builder_state.patch_call(
64                    PatchPosition(InstructionPosition(function_fixup.patch_position.0.0)),
65                    &func.ip_range.start,
66                );
67            } else {
68                error!(?function_fixup.fn_id, name=function_fixup.internal_function_definition.assigned_name, path=?function_fixup.internal_function_definition.defined_in_module_path,  "couldn't fixup function");
69                panic!(
70                    "couldn't fixup function {}",
71                    function_fixup.internal_function_definition.assigned_name
72                );
73            }
74        }
75
76        self.codegen_state.debug_info.info_for_each_instruction = self.builder_state.meta.clone();
77
78        self.codegen_state.function_fixups.clear();
79    }
80
81    pub fn emit_constants_expression_functions_in_order(
82        &mut self,
83        constants: &[ConstantRef],
84        source_map_wrapper: &SourceMapWrapper,
85    ) {
86        for constant in constants {
87            let target_region = self
88                .codegen_state
89                .constant_offsets
90                .get(&constant.id)
91                .unwrap()
92                .clone();
93
94            let in_data = FunctionInData {
95                function_name_node: constant.name.clone(),
96                kind: FunctionInfoKind::Constant(constant.id as usize),
97                assigned_name: constant.assigned_name.clone(),
98                function_variables: constant.function_scope_state.clone(),
99                return_type: constant.resolved_type.clone(),
100                expression: constant.expr.clone(),
101            };
102
103            let (start_ip, end_ip, function_info) =
104                self.emit_function_preamble(&in_data, source_map_wrapper, true);
105
106            let constant_info = ConstantInfo {
107                ip_range: InstructionRange {
108                    count: InstructionPositionOffset(end_ip.0 - start_ip.0),
109                    start: start_ip,
110                },
111                target_constant_memory: target_region,
112                constant_ref: constant.clone(),
113            };
114
115            self.codegen_state
116                .constant_functions_in_order
117                .insert(constant.id, constant_info)
118                .unwrap();
119
120            self.codegen_state
121                .debug_info
122                .function_table
123                .entries
124                .push(FunctionDebugInfo {
125                    start_pc: start_ip.0,
126                    function_id: constant.id as u16,
127                });
128
129            self.codegen_state
130                .debug_info
131                .function_infos
132                .insert(constant.id as u16, function_info)
133                .unwrap();
134        }
135    }
136
137    #[must_use]
138    pub fn take_instructions_and_constants(
139        self,
140    ) -> (
141        Vec<BinaryInstruction>,
142        SeqMap<ConstantId, ConstantInfo>,
143        SeqMap<InternalFunctionId, GenFunctionInfo>,
144        Vec<u8>,
145        DebugInfo,
146    ) {
147        (
148            self.builder_state.instructions,
149            self.codegen_state.constant_functions_in_order,
150            self.codegen_state.function_infos,
151            self.codegen_state.constants_manager.take_data(),
152            self.codegen_state.debug_info,
153        )
154    }
155
156    #[must_use]
157    pub fn instructions(&self) -> &[BinaryInstruction] {
158        &self.builder_state.instructions
159    }
160
161    #[must_use]
162    pub const fn ip(&self) -> InstructionPosition {
163        InstructionPosition(self.builder_state.instructions.len() as u32)
164    }
165    #[must_use]
166    pub fn meta(&self) -> &[Meta] {
167        &self.builder_state.meta
168    }
169}