| 15 | /* IC fast path: Done (consumed+pushed) / TypeMiss (deopt) / Overflow (keep IC, slow handler raises). */ |
| 16 | #[inline] |
| 17 | fn exec_fast(&mut self, fast: FastOp) -> Result<FastOutcome, VmErr> { |
| 18 | let len = self.stack.len(); |
| 19 | if len < 2 { return Ok(FastOutcome::TypeMiss); } |
| 20 | |
| 21 | let a = self.stack[len - 2]; |
| 22 | let b = self.stack[len - 1]; |
| 23 | |
| 24 | let result = match fast { |
| 25 | FastOp::AddFloat if a.is_float() && b.is_float() => Val::float(a.as_float() + b.as_float()), |
| 26 | FastOp::AddInt if a.is_int() && b.is_int() => { |
| 27 | match a.as_int().checked_add(b.as_int()).and_then(Val::int_checked) { |
| 28 | Some(v) => v, |
| 29 | None => return Ok(FastOutcome::Overflow), |
| 30 | } |
| 31 | } |
| 32 | FastOp::SubInt if a.is_int() && b.is_int() => { |
| 33 | match a.as_int().checked_sub(b.as_int()).and_then(Val::int_checked) { |
| 34 | Some(v) => v, |
| 35 | None => return Ok(FastOutcome::Overflow), |
| 36 | } |
| 37 | } |
| 38 | FastOp::MulInt if a.is_int() && b.is_int() => { |
| 39 | let r = a.as_int() as i128 * b.as_int() as i128; |
| 40 | if r >= Val::INT_MIN as i128 && r <= Val::INT_MAX as i128 { Val::int(r as i64) } else { return Ok(FastOutcome::Overflow); } |
| 41 | } |
| 42 | FastOp::MulFloat if a.is_float() && b.is_float() => Val::float(a.as_float() * b.as_float()), |
| 43 | FastOp::ModInt if a.is_int() && b.is_int() => { |
| 44 | let bv = b.as_int(); |
| 45 | if bv == 0 { return Ok(FastOutcome::Overflow); } |
| 46 | Val::int(((a.as_int() % bv) + bv) % bv) |
| 47 | } |
| 48 | FastOp::FloorDivInt if a.is_int() && b.is_int() => { |
| 49 | let bv = b.as_int(); |
| 50 | if bv == 0 { return Ok(FastOutcome::Overflow); } |
| 51 | // floored division (toward -inf), not Euclidean; 47-bit operands can't overflow. |
| 52 | let av = a.as_int(); |
| 53 | let q = av / bv; |
| 54 | let r = av - q * bv; |
| 55 | Val::int(if r != 0 && (r < 0) != (bv < 0) { q - 1 } else { q }) |
| 56 | } |
| 57 | |
| 58 | FastOp::LtInt if a.is_int() && b.is_int() => Val::bool(a.as_int() < b.as_int()), |
| 59 | FastOp::LtFloat if a.is_float() && b.is_float() => Val::bool(a.as_float() < b.as_float()), |
| 60 | FastOp::EqInt if a.is_int() && b.is_int() => Val::bool(a.as_int() == b.as_int()), |
| 61 | FastOp::GtInt if a.is_int() && b.is_int() => Val::bool(a.as_int() > b.as_int()), |
| 62 | FastOp::LtEqInt if a.is_int() && b.is_int() => Val::bool(a.as_int() <= b.as_int()), |
| 63 | FastOp::GtEqInt if a.is_int() && b.is_int() => Val::bool(a.as_int() >= b.as_int()), |
| 64 | FastOp::NotEqInt if a.is_int() && b.is_int() => Val::bool(a.as_int() != b.as_int()), |
| 65 | |
| 66 | FastOp::EqStr if a.is_heap() && b.is_heap() => { |
| 67 | match (self.heap.get(a), self.heap.get(b)) { |
| 68 | (HeapObj::Str(x), HeapObj::Str(y)) => Val::bool(x == y), |
| 69 | _ => return Ok(FastOutcome::TypeMiss), |
| 70 | } |
| 71 | } |
| 72 | |
| 73 | FastOp::AddStr if a.is_heap() && b.is_heap() => { |
| 74 | let (sa, sb) = match (self.heap.get(a), self.heap.get(b)) { |