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