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