(&mut self, inst: InstanceCache, chunk: &SSAChunk, slots: &mut [Val])
| 93 | /* Instance-dunder fast path. Guards the receiver's class identity, invokes the pre-resolved method bypassing `resolve_attr_silent`, and treats `NotImplemented` as a deopt so reflected dispatch can take over via the slow path. Restores the stack on miss so the slow handler reads its operands unchanged. */ |
| 94 | #[inline] |
| 95 | fn exec_inst(&mut self, inst: InstanceCache, chunk: &SSAChunk, slots: &mut [Val]) -> Result<FastOutcome, VmErr> { |
| 96 | let arity = inst.arity as usize; |
| 97 | let len = self.stack.len(); |
| 98 | if len < arity { return Ok(FastOutcome::TypeMiss); } |
| 99 | |
| 100 | let recv_idx = len - arity; |
| 101 | let recv = self.stack[recv_idx]; |
| 102 | if !recv.is_heap() { return Ok(FastOutcome::TypeMiss); } |
| 103 | let class_val = match self.heap.get(recv) { |
| 104 | HeapObj::Instance(c, _) => *c, |
| 105 | _ => return Ok(FastOutcome::TypeMiss), |
| 106 | }; |
| 107 | if class_val.as_heap() != inst.class { return Ok(FastOutcome::TypeMiss); } |
| 108 | |
| 109 | if self.depth >= self.max_calls { return Err(cold_depth()); } |
| 110 | |
| 111 | // Snapshot the operand window before mutating; reused to roll back on deopt. |
| 112 | let mut operands: Vec<Val> = Vec::with_capacity(arity); |
| 113 | operands.extend_from_slice(&self.stack[recv_idx..len]); |
| 114 | self.stack.truncate(recv_idx); |
| 115 | |
| 116 | // SAFETY: `method_bits` was recorded from a live `Val` and `Class` references are immutable, so the function still lives on the heap. |
| 117 | let method = unsafe { Val::from_raw(inst.method_bits) }; |
| 118 | self.pending.method_binding = Some((class_val, recv)); |
| 119 | self.push(method); |
| 120 | for &v in &operands { self.push(v); } |
| 121 | self.exec_call(arity as u16, chunk, slots)?; |
| 122 | |
| 123 | let result = self.pop()?; |
| 124 | if self.heap.is_not_implemented(result) { |
| 125 | // Deopt: restore the original stack window so the slow handler sees its operands. |
| 126 | for &v in &operands { self.push(v); } |
| 127 | return Ok(FastOutcome::TypeMiss); |
| 128 | } |
| 129 | self.push(result); |
| 130 | Ok(FastOutcome::Done) |
| 131 | } |
| 132 | |
| 133 | /* Post-success recording for the instance-dunder IC; ignored when the receiver isn't an instance or the method isn't on its class. */ |
| 134 | #[inline] |
no test coverage detected