1use crate::lexer::Span;
13use thiserror::Error;
14
15mod access;
16mod cache;
17mod compiler;
18mod entry_points;
19mod format;
20mod host;
21mod instruction;
22mod json;
23mod ops;
24mod projector;
25mod record;
26mod schema;
27mod state;
28mod value;
29mod vm;
30
31pub use cache::{
32 CompiledLinkedProgram, CompiledProcessCache, CompiledProcessCacheKey, CompiledProgramCache,
33 CompiledProgramCacheStats, LinkedProgramCache, LinkedProgramCacheError,
34};
35#[allow(unused_imports)]
36pub(crate) use compiler::*;
37pub use entry_points::{
38 ExecutableProgram, compile, compile_linked, compile_linked_process,
39 compile_module_artifact_process, compile_process, execute, prewarm,
40};
41pub use host::{
42 AbilityOp, AbilityResult, ExecutionEnvironment, ExecutionHost, ExecutionHostError,
43 ExecutionMode, ProcessEvent, ProcessEventKind, ProcessSignal, ProcessStart, ResourceOperation,
44 ResourceOperationBatch, ResourceOperationBatchResult, ResourceOperationResult, Sleep,
45 SleepKind,
46};
47#[allow(unused_imports)]
48pub(crate) use instruction::*;
49pub use json::from_json;
50pub use projector::{
51 BudgetedJsonProjectionConfig, BudgetedJsonProjector, ValueProjectionContext, ValueProjector,
52};
53pub use record::Record;
54#[allow(unused_imports)]
55pub(crate) use record::{Symbol, intern_symbol, lookup_symbol, record_with_capacity, symbol_name};
56#[allow(unused_imports)]
57pub(crate) use schema::{
58 ValidationPlan, compile_schema_value, execute_validate_builtin, execute_validation_plan,
59};
60#[allow(unused_imports)]
61pub(crate) use vm::*;
62#[allow(unused_imports)]
67pub(crate) use access::*;
68#[allow(unused_imports)]
69pub(crate) use format::*;
70#[allow(unused_imports)]
71pub(crate) use json::*;
72#[allow(unused_imports)]
73pub(crate) use ops::*;
74pub use state::{Snapshot, State};
75pub use value::{
76 ImageValue, LASH_HOST_DESCRIPTOR_TYPE_KEY, LASH_HOST_DESCRIPTOR_VALUE_KEY,
77 LASH_HOST_REQUIREMENTS_REF_KEY, LASH_MODULE_REF_KEY, LASH_PROCESS_NAME_KEY,
78 LASH_PROCESS_REF_KEY, LASH_PROCESS_VALUE_KEY, LASH_TYPE_KEY, ListValue, ProjectedBindingError,
79 ProjectedBindings, ProjectedFuture, ProjectedHostDescriptor, ProjectedReadRequest,
80 ProjectedReadResponse, ProjectedValue, ResourceHandle, Value,
81};
82use vm::IterState;
83
84#[derive(Clone, Debug, Error, PartialEq)]
85pub enum RuntimeError {
86 #[error("unknown name `{name}`")]
87 UndefinedVariable { name: String },
88 #[error("`for` expects a list or tuple")]
89 NonListIteration,
90 #[error("`{keyword}` can only be used inside a process body")]
91 SessionProcessAdminOutsideProcess { keyword: &'static str },
92 #[error("`{keyword}` can't be used inside a process body")]
93 ForegroundControlInsideProcess { keyword: &'static str },
94 #[error("unknown builtin `{name}`")]
95 UnknownBuiltin { name: String },
96 #[error("{message}")]
97 TypeError { message: String },
98 #[error("{message}")]
99 ValueError { message: String },
100}
101
102#[derive(Clone, Debug, Error, PartialEq)]
103#[error("{error}")]
104pub struct RuntimeFailure {
105 pub error: RuntimeError,
106 pub span: Option<Span>,
107}
108
109#[derive(Default)]
110pub struct ExecutionScratch {
111 stack: Vec<Value>,
112 iter_stack: Vec<IterState>,
113 slot_values: Vec<Option<Value>>,
114}
115
116impl ExecutionScratch {
117 pub fn new() -> Self {
118 Self::default()
119 }
120}
121
122pub(crate) const COOPERATIVE_YIELD_INSTRUCTION_BUDGET: usize = 1024;
123
124#[derive(Clone)]
125pub struct CompiledProgram {
126 pub(crate) chunk: Chunk,
127 pub(crate) compile_stats: CompileStats,
128}
129
130impl std::fmt::Debug for CompiledProgram {
131 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
132 f.debug_struct("CompiledProgram")
133 .field("instruction_count", &self.chunk.code.len())
134 .field("compile_stats", &self.compile_stats)
135 .finish()
136 }
137}
138
139impl CompiledProgram {
140 pub fn compile_stats(&self) -> &CompileStats {
141 &self.compile_stats
142 }
143
144 pub fn static_graph_json(&self, module_ref: impl Into<String>) -> serde_json::Value {
145 if let Some(context) = &self.chunk.module_context {
146 crate::graph::static_graph_json_for_module_ref(
147 context.module_ref.clone(),
148 &context.process_refs,
149 )
150 } else {
151 crate::graph::static_graph_json_without_ir(module_ref)
152 }
153 }
154}
155
156#[derive(Clone, Debug, PartialEq)]
157pub enum ExecutionOutcome {
158 Continued,
159 Finished(Value),
160 Failed(Value),
161}
162
163#[derive(Clone, Debug, Default)]
164pub struct ProfileReport {
165 instruction_stats: Vec<ProfileStat>,
166 builtin_stats: Vec<ProfileStat>,
167 compile_stats: CompileStats,
168}
169
170impl ProfileReport {
171 pub fn instruction_stats(&self) -> &[ProfileStat] {
172 &self.instruction_stats
173 }
174
175 pub fn builtin_stats(&self) -> &[ProfileStat] {
176 &self.builtin_stats
177 }
178
179 pub fn compile_stats(&self) -> &CompileStats {
180 &self.compile_stats
181 }
182
183 pub fn merge(&mut self, other: &Self) {
184 merge_stats(&mut self.instruction_stats, &other.instruction_stats);
185 merge_stats(&mut self.builtin_stats, &other.builtin_stats);
186 self.compile_stats.merge(&other.compile_stats);
187 }
188}
189
190#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
196pub struct CompileStats {
197 pub type_literals_total: u64,
198 pub type_literals_const_folded: u64,
199 pub type_literals_dynamic: u64,
200 pub type_ref_sites: u64,
201}
202
203impl CompileStats {
204 pub fn merge(&mut self, other: &Self) {
205 self.type_literals_total += other.type_literals_total;
206 self.type_literals_const_folded += other.type_literals_const_folded;
207 self.type_literals_dynamic += other.type_literals_dynamic;
208 self.type_ref_sites += other.type_ref_sites;
209 }
210}
211
212#[derive(Clone, Debug, Default)]
213pub struct ProfileStat {
214 pub name: &'static str,
215 pub count: u64,
216 pub total_ns: u128,
217}
218
219impl ProfileStat {
220 pub fn avg_ns(&self) -> u128 {
221 if self.count == 0 {
222 0
223 } else {
224 self.total_ns / self.count as u128
225 }
226 }
227}
228pub fn unwrap_type_value(value: &Value) -> Option<&Value> {
232 let record = value.as_record()?;
233 if record.len() != 1 {
234 return None;
235 }
236 record.get(LASH_TYPE_KEY)
237}
238
239#[cfg(test)]
240mod tests;