Build the const pool: scalars inline, Str/LongInt heap-allocated once and shared. */
(&mut self, chunk: &SSAChunk, heap: &mut HeapPool)
| 69 | |
| 70 | /* Build the const pool: scalars inline, Str/LongInt heap-allocated once and shared. */ |
| 71 | pub fn ensure_const_vals(&mut self, chunk: &SSAChunk, heap: &mut HeapPool) -> Result<&[Val], VmErr> { |
| 72 | if self.const_vals.is_none() { |
| 73 | let mut out = Vec::with_capacity(chunk.constants.len()); |
| 74 | for c in &chunk.constants { |
| 75 | let v = match c { |
| 76 | Value::Int(i) => { |
| 77 | if *i >= Val::INT_MIN && *i <= Val::INT_MAX { Val::int(*i) } |
| 78 | // Defensive path for FFI/wire-format chunks; parser now emits LongInt directly. |
| 79 | else { heap.alloc(HeapObj::LongInt(*i as i128))? } |
| 80 | } |
| 81 | Value::LongInt(i) => { |
| 82 | // Demote when it fits inline so hash/eq stay in sync with literals. |
| 83 | if *i >= Val::INT_MIN as i128 && *i <= Val::INT_MAX as i128 { |
| 84 | Val::int(*i as i64) |
| 85 | } else { |
| 86 | heap.alloc(HeapObj::LongInt(*i))? |
| 87 | } |
| 88 | } |
| 89 | Value::Float(f) => Val::float(*f), |
| 90 | Value::Bool(b) => Val::bool(*b), |
| 91 | Value::None => Val::none(), |
| 92 | Value::Str(s) => heap.alloc(HeapObj::Str(s.to_string()))?, |
| 93 | Value::Bytes(b) => heap.alloc(HeapObj::Bytes(b.clone()))?, |
| 94 | }; |
| 95 | out.push(v); |
| 96 | } |
| 97 | self.const_vals = Some(out); |
| 98 | } |
| 99 | Ok(self.const_vals.as_ref().unwrap()) |
| 100 | } |
| 101 | |
| 102 | /* Direct access (caller must have called ensure_const_vals). */ |
| 103 | pub fn const_vals_ref(&self) -> &[Val] { |