Flatten nested defs into one table (DFS); also build parent/body-pointer maps so `exec_call` can tell lexical-parent calls (late-bind) from foreign closures (captures stick). */
(&mut self, chunk: &'a SSAChunk, parent_fi: Option<usize>, module_spec: Option<&str>)
| 28 | |
| 29 | /* Flatten nested defs into one table (DFS); also build parent/body-pointer maps so `exec_call` can tell lexical-parent calls (late-bind) from foreign closures (captures stick). */ |
| 30 | pub(crate) fn build_function_table(&mut self, chunk: &'a SSAChunk, parent_fi: Option<usize>, module_spec: Option<&str>) { |
| 31 | let mut indices = Vec::with_capacity(chunk.functions.len()); |
| 32 | for desc in chunk.functions.iter() { |
| 33 | let global = self.functions.len() as u32; |
| 34 | self.functions.push(desc); |
| 35 | self.function_parents.push(parent_fi); |
| 36 | self.fn_module.push(module_spec.map(String::from)); |
| 37 | self.body_to_fi.insert(&desc.1 as *const _, global as usize); |
| 38 | // Bare function name (SSA suffix stripped) for tracebacks. |
| 39 | let name = chunk.names.get(desc.3 as usize).map(|n| ssa_strip(n).to_string()).unwrap_or_default(); |
| 40 | self.function_names.push(name); |
| 41 | indices.push(global); |
| 42 | self.build_function_table(&desc.1, Some(global as usize), module_spec); |
| 43 | } |
| 44 | self.fn_index.push((chunk as *const _, indices)); |
| 45 | |
| 46 | // Bare-name index so the free-load fallback is O(1) instead of re-parsing per miss. |
| 47 | let mut name_versions: super::NameVersionIndex = crate::util::fx::FxHashMap::default(); |
| 48 | for (si, sname) in chunk.names.iter().enumerate() { |
| 49 | if let Some(parsed) = crate::modules::parser::SsaName::parse(sname) { |
| 50 | name_versions |
| 51 | .entry(parsed.bare.to_string()) |
| 52 | .or_default() |
| 53 | .push((parsed.version as i64, si)); |
| 54 | } |
| 55 | } |
| 56 | self.chunk_name_versions.insert(chunk as *const _, name_versions); |
| 57 | for class_body in chunk.classes.iter() { |
| 58 | self.build_function_table(class_body, parent_fi, module_spec); |
| 59 | } |
| 60 | // Recurse into code-module imports; each fn carries its spec so namespaces stay separate. |
| 61 | for entry in chunk.imports.iter() { |
| 62 | if let ImportKind::Code(sub) = &entry.kind { |
| 63 | self.build_function_table(sub, None, Some(&entry.spec)); |
| 64 | } |
| 65 | } |
| 66 | } |
| 67 | |
| 68 | /* Inject `val` into the first `WaitingEvent` waiter's saved stack (innermost sync sub-frame wins) and mark it Ready; queues `val` otherwise. Shared by `push_event` and `run_push_event`. */ |
| 69 | pub fn inject_event(&mut self, val: Val) { |