From e462eea78890cd3f8491caecd46f927b15b4027d Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Fri, 27 Mar 2026 10:40:28 +0100 Subject: [PATCH 1/8] Base resume context --- crates/compiler-core/src/bytecode.rs | 4 +- .../compiler-core/src/bytecode/instruction.rs | 2 +- crates/compiler-core/src/bytecode/oparg.rs | 121 ++++++++++-------- 3 files changed, 71 insertions(+), 56 deletions(-) diff --git a/crates/compiler-core/src/bytecode.rs b/crates/compiler-core/src/bytecode.rs index cd23458bf99..d099ed251c1 100644 --- a/crates/compiler-core/src/bytecode.rs +++ b/crates/compiler-core/src/bytecode.rs @@ -27,7 +27,7 @@ pub use crate::bytecode::{ BinaryOperator, BuildSliceArgCount, CommonConstant, ComparisonOperator, ConvertValueOparg, IntrinsicFunction1, IntrinsicFunction2, Invert, Label, LoadAttr, LoadSuperAttr, MakeFunctionFlag, MakeFunctionFlags, NameIdx, OpArg, OpArgByte, OpArgState, OpArgType, - RaiseKind, ResumeType, SpecialMethod, UnpackExArgs, + RaiseKind, SpecialMethod, UnpackExArgs, }, }; @@ -1041,7 +1041,7 @@ impl CodeObject { } // arrow and offset - let arrow = if label_targets.contains(&Label::new(offset as u32)) { + let arrow = if label_targets.contains(&Label::from_u32(offset as u32)) { ">>" } else { " " diff --git a/crates/compiler-core/src/bytecode/instruction.rs b/crates/compiler-core/src/bytecode/instruction.rs index 86ed1da7436..76dc6a79381 100644 --- a/crates/compiler-core/src/bytecode/instruction.rs +++ b/crates/compiler-core/src/bytecode/instruction.rs @@ -304,7 +304,7 @@ pub enum Instruction { } = 120, // CPython 3.14 RESUME (128) Resume { - context: Arg, + context: Arg, } = 128, // CPython 3.14 specialized opcodes (129-211) BinaryOpAddFloat = 129, // Placeholder diff --git a/crates/compiler-core/src/bytecode/oparg.rs b/crates/compiler-core/src/bytecode/oparg.rs index ba00180c97c..3b28d699d7e 100644 --- a/crates/compiler-core/src/bytecode/oparg.rs +++ b/crates/compiler-core/src/bytecode/oparg.rs @@ -276,48 +276,6 @@ impl fmt::Display for ConvertValueOparg { } } -/// Resume type for the RESUME instruction -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] -pub enum ResumeType { - AtFuncStart, - AfterYield, - AfterYieldFrom, - AfterAwait, - Other(u32), -} - -impl From for ResumeType { - fn from(value: u32) -> Self { - match value { - 0 => Self::AtFuncStart, - 5 => Self::AfterYield, - 2 => Self::AfterYieldFrom, - 3 => Self::AfterAwait, - _ => Self::Other(value), - } - } -} - -impl From for u32 { - fn from(typ: ResumeType) -> Self { - match typ { - ResumeType::AtFuncStart => 0, - ResumeType::AfterYield => 5, - ResumeType::AfterYieldFrom => 2, - ResumeType::AfterAwait => 3, - ResumeType::Other(v) => v, - } - } -} - -impl core::fmt::Display for ResumeType { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - u32::from(*self).fmt(f) - } -} - -impl OpArgType for ResumeType {} - pub type NameIdx = u32; impl OpArgType for u32 {} @@ -756,14 +714,8 @@ macro_rules! newtype_oparg { impl $name { /// Creates a new [`$name`] instance. #[must_use] - pub const fn new(value: u32) -> Self { - Self(value) - } - - /// Alias to [`$name::new`]. - #[must_use] pub const fn from_u32(value: u32) -> Self { - Self::new(value) + Self(value) } /// Returns the oparg as a `u32` value. @@ -843,15 +795,78 @@ newtype_oparg!( pub struct Label(u32) ); +newtype_oparg!( + /// Context for [`Instruction::Resume`]. + /// + /// The oparg consists of two parts: + /// 1. [`Context::location`]: Indicates where the instruction occurs. + /// 2. [`Context::is_exception_depth1`]: Is the instruction is at except-depth 1. + #[derive(Clone, Copy)] + #[repr(transparent)] + pub struct ResumeContext(u32) +); + +impl ResumeContext { + /// [CPython `RESUME_OPARG_LOCATION_MASK`](https://github.com/python/cpython/blob/v3.14.3/Include/internal/pycore_opcode_utils.h#L84) + pub const LOCATION_MASK: u32 = 0x3; + + /// [CPython `RESUME_OPARG_DEPTH1_MASK`](https://github.com/python/cpython/blob/v3.14.3/Include/internal/pycore_opcode_utils.h#L85) + pub const DEPTH1_MASK: u32 = 0x4; + + #[must_use] + fn new(_location: ResumeLocation, _is_exception_depth1: bool) -> Self { + todo!() + } + + /// Resume location is determined by [`Self::LOCATION_MASK`]. + #[must_use] + pub fn location(&self) -> ResumeLocation { + // SAFETY: The mask should return a value that is in range. + unsafe { ResumeLocation::try_from(self.as_u32() & Self::LOCATION_MASK).unwrap_unchecked() } + } + + /// True if the bit at [`Self::DEPTH1_MASK`] is on. + #[must_use] + pub const fn is_exception_depth1(&self) -> bool { + (self.as_u32() & Self::DEPTH1_MASK) != 0 + } +} + +#[derive(Copy, Clone)] +pub enum ResumeLocation { + /// At the start of a function, which is neither a generator, coroutine nor an async generator. + AtFuncStart, + /// After a `yield` expression. + AfterYield, + /// After a `yield from` expression. + AfterYieldFrom, + /// After an `await` expression. + AfterAwait, +} + +impl TryFrom for ResumeLocation { + type Error = MarshalError; + + fn try_from(value: u32) -> Result { + Ok(match value { + 0 => Self::AtFuncStart, + 1 => Self::AfterYield, + 2 => Self::AfterYieldFrom, + 3 => Self::AfterAwait, + _ => return Err(Self::Error::InvalidBytecode), + }) + } +} + impl VarNums { #[must_use] pub const fn idx_1(self) -> VarNum { - VarNum::new(self.0 >> 4) + VarNum::from_u32(self.0 >> 4) } #[must_use] pub const fn idx_2(self) -> VarNum { - VarNum::new(self.0 & 15) + VarNum::from_u32(self.0 & 15) } #[must_use] @@ -887,7 +902,7 @@ impl LoadAttrBuilder { #[must_use] pub const fn build(self) -> LoadAttr { let value = (self.name_idx << 1) | (self.is_method as u32); - LoadAttr::new(value) + LoadAttr::from_u32(value) } #[must_use] @@ -937,7 +952,7 @@ impl LoadSuperAttrBuilder { pub const fn build(self) -> LoadSuperAttr { let value = (self.name_idx << 2) | ((self.has_class as u32) << 1) | (self.is_load_method as u32); - LoadSuperAttr::new(value) + LoadSuperAttr::from_u32(value) } #[must_use] From 009370b24236a8035f07a9a3b0436a66bfe45859 Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Fri, 27 Mar 2026 10:42:02 +0100 Subject: [PATCH 2/8] Fixes for api change --- crates/codegen/src/ir.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/codegen/src/ir.rs b/crates/codegen/src/ir.rs index dc3daa14955..a551146b37c 100644 --- a/crates/codegen/src/ir.rs +++ b/crates/codegen/src/ir.rs @@ -363,7 +363,7 @@ impl CodeInfo { } } - let mut block_to_offset = vec![Label::new(0); blocks.len()]; + let mut block_to_offset = vec![Label::from_u32(0); blocks.len()]; // block_to_index: maps block idx to instruction index (for exception table) // This is the index into the final instructions array, including EXTENDED_ARG and CACHE let mut block_to_index = vec![0u32; blocks.len()]; @@ -372,7 +372,7 @@ impl CodeInfo { loop { let mut num_instructions = 0; for (idx, block) in iter_blocks(&blocks) { - block_to_offset[idx.idx()] = Label::new(num_instructions as u32); + block_to_offset[idx.idx()] = Label::from_u32(num_instructions as u32); // block_to_index uses the same value as block_to_offset but as u32 // because lasti in frame.rs is the index into instructions array // and instructions array index == byte offset (each instruction is 1 CodeUnit) From e4af47d7484ca1afc0cbf3efd7a86cb1abd35a05 Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Fri, 27 Mar 2026 11:02:59 +0100 Subject: [PATCH 3/8] Align codegen --- crates/codegen/src/compile.rs | 27 ++++++++++----- crates/compiler-core/src/bytecode/oparg.rs | 39 ++++++++++++++++++++-- 2 files changed, 56 insertions(+), 10 deletions(-) diff --git a/crates/codegen/src/compile.rs b/crates/codegen/src/compile.rs index 1c09d6bb463..c3ba6ae8c03 100644 --- a/crates/codegen/src/compile.rs +++ b/crates/codegen/src/compile.rs @@ -1277,7 +1277,9 @@ impl Compiler { context: OpArgMarker::marker(), } .into(), - arg: OpArg::new(u32::from(bytecode::ResumeType::AtFuncStart)), + arg: OpArg::new( + oparg::ResumeContext::new(oparg::ResumeLocation::AtFuncStart, false).into(), + ), target: BlockIdx::NULL, location, end_location, @@ -7199,11 +7201,14 @@ impl Compiler { emit!( self, Instruction::Resume { - context: if is_await { - bytecode::ResumeType::AfterAwait - } else { - bytecode::ResumeType::AfterYieldFrom - } + context: oparg::ResumeContext::new( + if is_await { + oparg::ResumeLocation::AfterAwait + } else { + oparg::ResumeLocation::AfterYieldFrom + }, + false + ) } ); @@ -7374,7 +7379,10 @@ impl Compiler { emit!( self, Instruction::Resume { - context: bytecode::ResumeType::AfterYield + context: oparg::ResumeContext::new( + oparg::ResumeLocation::AfterYield, + true, // TODO: Is this always true? + ) } ); } @@ -7596,7 +7604,10 @@ impl Compiler { emit!( compiler, Instruction::Resume { - context: bytecode::ResumeType::AfterYield + context: oparg::ResumeContext::new( + oparg::ResumeLocation::AfterYield, + true, // TODO: Is this always true? + ) } ); emit!(compiler, Instruction::PopTop); diff --git a/crates/compiler-core/src/bytecode/oparg.rs b/crates/compiler-core/src/bytecode/oparg.rs index 3b28d699d7e..28650dd56c9 100644 --- a/crates/compiler-core/src/bytecode/oparg.rs +++ b/crates/compiler-core/src/bytecode/oparg.rs @@ -814,8 +814,14 @@ impl ResumeContext { pub const DEPTH1_MASK: u32 = 0x4; #[must_use] - fn new(_location: ResumeLocation, _is_exception_depth1: bool) -> Self { - todo!() + pub const fn new(location: ResumeLocation, is_exception_depth1: bool) -> Self { + let value = if is_exception_depth1 { + Self::DEPTH1_MASK + } else { + 0 + }; + + Self::from_u32(location.as_u32() | value) } /// Resume location is determined by [`Self::LOCATION_MASK`]. @@ -858,6 +864,35 @@ impl TryFrom for ResumeLocation { } } +impl ResumeLocation { + #[must_use] + pub const fn as_u8(&self) -> u8 { + match self { + Self::AtFuncStart => 0, + Self::AfterYield => 1, + Self::AfterYieldFrom => 2, + Self::AfterAwait => 3, + } + } + + #[must_use] + pub const fn as_u32(&self) -> u32 { + self.as_u8() as u32 + } +} + +impl From for u8 { + fn from(location: ResumeLocation) -> Self { + location.as_u8() + } +} + +impl From for u32 { + fn from(location: ResumeLocation) -> Self { + location.as_u32() + } +} + impl VarNums { #[must_use] pub const fn idx_1(self) -> VarNum { From a37bd3cf888fb5087b968835e8d19b388158efd6 Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Fri, 27 Mar 2026 11:07:57 +0100 Subject: [PATCH 4/8] Align `frame.rs` to the api changes --- crates/vm/src/frame.rs | 64 +++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/crates/vm/src/frame.rs b/crates/vm/src/frame.rs index 8dcd626da3b..21ef5fc791f 100644 --- a/crates/vm/src/frame.rs +++ b/crates/vm/src/frame.rs @@ -2437,7 +2437,7 @@ impl ExecutingFrame<'_> { } Instruction::ForIter { .. } => { // Relative forward jump: target = lasti + caches + delta - let target = bytecode::Label::new(self.lasti() + 1 + u32::from(arg)); + let target = bytecode::Label::from_u32(self.lasti() + 1 + u32::from(arg)); self.adaptive(|s, ii, cb| s.specialize_for_iter(vm, u32::from(arg), ii, cb)); self.execute_for_iter(vm, target)?; Ok(None) @@ -3571,7 +3571,7 @@ impl ExecutingFrame<'_> { Instruction::Send { .. } => { // (receiver, v -- receiver, retval) self.adaptive(|s, ii, cb| s.specialize_send(vm, ii, cb)); - let exit_label = bytecode::Label::new(self.lasti() + 1 + u32::from(arg)); + let exit_label = bytecode::Label::from_u32(self.lasti() + 1 + u32::from(arg)); let receiver = self.nth_value(1); let can_fast_send = !self.specialization_eval_frame_active(vm) && (receiver.downcast_ref_if_exact::(vm).is_some() @@ -3609,7 +3609,7 @@ impl ExecutingFrame<'_> { } } Instruction::SendGen => { - let exit_label = bytecode::Label::new(self.lasti() + 1 + u32::from(arg)); + let exit_label = bytecode::Label::from_u32(self.lasti() + 1 + u32::from(arg)); // Stack: [receiver, val] — peek receiver before popping let receiver = self.nth_value(1); let can_fast_send = !self.specialization_eval_frame_active(vm) @@ -3740,7 +3740,7 @@ impl ExecutingFrame<'_> { } // Specialized LOAD_ATTR opcodes Instruction::LoadAttrMethodNoDict => { - let oparg = LoadAttr::new(u32::from(arg)); + let oparg = LoadAttr::from_u32(u32::from(arg)); let cache_base = self.lasti() as usize; let owner = self.top_value(); @@ -3759,7 +3759,7 @@ impl ExecutingFrame<'_> { } } Instruction::LoadAttrMethodLazyDict => { - let oparg = LoadAttr::new(u32::from(arg)); + let oparg = LoadAttr::from_u32(u32::from(arg)); let cache_base = self.lasti() as usize; let owner = self.top_value(); @@ -3779,7 +3779,7 @@ impl ExecutingFrame<'_> { } } Instruction::LoadAttrMethodWithValues => { - let oparg = LoadAttr::new(u32::from(arg)); + let oparg = LoadAttr::from_u32(u32::from(arg)); let cache_base = self.lasti() as usize; let attr_name = self.code.names[oparg.name_idx() as usize]; @@ -3814,7 +3814,7 @@ impl ExecutingFrame<'_> { self.load_attr_slow(vm, oparg) } Instruction::LoadAttrInstanceValue => { - let oparg = LoadAttr::new(u32::from(arg)); + let oparg = LoadAttr::from_u32(u32::from(arg)); let cache_base = self.lasti() as usize; let attr_name = self.code.names[oparg.name_idx() as usize]; @@ -3836,7 +3836,7 @@ impl ExecutingFrame<'_> { self.load_attr_slow(vm, oparg) } Instruction::LoadAttrWithHint => { - let oparg = LoadAttr::new(u32::from(arg)); + let oparg = LoadAttr::from_u32(u32::from(arg)); let cache_base = self.lasti() as usize; let attr_name = self.code.names[oparg.name_idx() as usize]; @@ -3861,7 +3861,7 @@ impl ExecutingFrame<'_> { self.load_attr_slow(vm, oparg) } Instruction::LoadAttrModule => { - let oparg = LoadAttr::new(u32::from(arg)); + let oparg = LoadAttr::from_u32(u32::from(arg)); let cache_base = self.lasti() as usize; let attr_name = self.code.names[oparg.name_idx() as usize]; @@ -3885,7 +3885,7 @@ impl ExecutingFrame<'_> { self.load_attr_slow(vm, oparg) } Instruction::LoadAttrNondescriptorNoDict => { - let oparg = LoadAttr::new(u32::from(arg)); + let oparg = LoadAttr::from_u32(u32::from(arg)); let cache_base = self.lasti() as usize; let owner = self.top_value(); @@ -3907,7 +3907,7 @@ impl ExecutingFrame<'_> { self.load_attr_slow(vm, oparg) } Instruction::LoadAttrNondescriptorWithValues => { - let oparg = LoadAttr::new(u32::from(arg)); + let oparg = LoadAttr::from_u32(u32::from(arg)); let cache_base = self.lasti() as usize; let attr_name = self.code.names[oparg.name_idx() as usize]; @@ -3945,7 +3945,7 @@ impl ExecutingFrame<'_> { self.load_attr_slow(vm, oparg) } Instruction::LoadAttrClass => { - let oparg = LoadAttr::new(u32::from(arg)); + let oparg = LoadAttr::from_u32(u32::from(arg)); let cache_base = self.lasti() as usize; let owner = self.top_value(); @@ -3968,7 +3968,7 @@ impl ExecutingFrame<'_> { self.load_attr_slow(vm, oparg) } Instruction::LoadAttrClassWithMetaclassCheck => { - let oparg = LoadAttr::new(u32::from(arg)); + let oparg = LoadAttr::from_u32(u32::from(arg)); let cache_base = self.lasti() as usize; let owner = self.top_value(); @@ -3994,7 +3994,7 @@ impl ExecutingFrame<'_> { self.load_attr_slow(vm, oparg) } Instruction::LoadAttrGetattributeOverridden => { - let oparg = LoadAttr::new(u32::from(arg)); + let oparg = LoadAttr::from_u32(u32::from(arg)); let cache_base = self.lasti() as usize; let owner = self.top_value(); let type_version = self.code.instructions.read_cache_u32(cache_base + 1); @@ -4021,7 +4021,7 @@ impl ExecutingFrame<'_> { self.load_attr_slow(vm, oparg) } Instruction::LoadAttrSlot => { - let oparg = LoadAttr::new(u32::from(arg)); + let oparg = LoadAttr::from_u32(u32::from(arg)); let cache_base = self.lasti() as usize; let owner = self.top_value(); @@ -4045,7 +4045,7 @@ impl ExecutingFrame<'_> { self.load_attr_slow(vm, oparg) } Instruction::LoadAttrProperty => { - let oparg = LoadAttr::new(u32::from(arg)); + let oparg = LoadAttr::from_u32(u32::from(arg)); let cache_base = self.lasti() as usize; let owner = self.top_value(); @@ -5247,7 +5247,7 @@ impl ExecutingFrame<'_> { return Ok(None); } } - let oparg = LoadSuperAttr::new(oparg); + let oparg = LoadSuperAttr::from_u32(oparg); self.load_super_attr(vm, oparg) } Instruction::LoadSuperAttrMethod => { @@ -5314,7 +5314,7 @@ impl ExecutingFrame<'_> { return Ok(None); } } - let oparg = LoadSuperAttr::new(oparg); + let oparg = LoadSuperAttr::from_u32(oparg); self.load_super_attr(vm, oparg) } Instruction::CompareOpInt => { @@ -5581,7 +5581,7 @@ impl ExecutingFrame<'_> { self.unpack_sequence(size as u32, vm) } Instruction::ForIterRange => { - let target = bytecode::Label::new(self.lasti() + 1 + u32::from(arg)); + let target = bytecode::Label::from_u32(self.lasti() + 1 + u32::from(arg)); let iter = self.top_value(); if let Some(range_iter) = iter.downcast_ref_if_exact::(vm) { if let Some(value) = range_iter.fast_next() { @@ -5596,7 +5596,7 @@ impl ExecutingFrame<'_> { } } Instruction::ForIterList => { - let target = bytecode::Label::new(self.lasti() + 1 + u32::from(arg)); + let target = bytecode::Label::from_u32(self.lasti() + 1 + u32::from(arg)); let iter = self.top_value(); if let Some(list_iter) = iter.downcast_ref_if_exact::(vm) { if let Some(value) = list_iter.fast_next() { @@ -5611,7 +5611,7 @@ impl ExecutingFrame<'_> { } } Instruction::ForIterTuple => { - let target = bytecode::Label::new(self.lasti() + 1 + u32::from(arg)); + let target = bytecode::Label::from_u32(self.lasti() + 1 + u32::from(arg)); let iter = self.top_value(); if let Some(tuple_iter) = iter.downcast_ref_if_exact::(vm) { if let Some(value) = tuple_iter.fast_next() { @@ -5626,7 +5626,7 @@ impl ExecutingFrame<'_> { } } Instruction::ForIterGen => { - let target = bytecode::Label::new(self.lasti() + 1 + u32::from(arg)); + let target = bytecode::Label::from_u32(self.lasti() + 1 + u32::from(arg)); let iter = self.top_value(); if self.specialization_eval_frame_active(vm) { self.execute_for_iter(vm, target)?; @@ -5868,7 +5868,7 @@ impl ExecutingFrame<'_> { Instruction::InstrumentedJumpForward => { let src_offset = (self.lasti() - 1) * 2; let target_idx = self.lasti() + u32::from(arg); - let target = bytecode::Label::new(target_idx); + let target = bytecode::Label::from_u32(target_idx); self.jump(target); if self.monitoring_mask & monitoring::EVENT_JUMP != 0 { monitoring::fire_jump(vm, self.code, src_offset, target.as_u32() * 2)?; @@ -5878,7 +5878,7 @@ impl ExecutingFrame<'_> { Instruction::InstrumentedJumpBackward => { let src_offset = (self.lasti() - 1) * 2; let target_idx = self.lasti() + 1 - u32::from(arg); - let target = bytecode::Label::new(target_idx); + let target = bytecode::Label::from_u32(target_idx); self.jump(target); if self.monitoring_mask & monitoring::EVENT_JUMP != 0 { monitoring::fire_jump(vm, self.code, src_offset, target.as_u32() * 2)?; @@ -5887,7 +5887,7 @@ impl ExecutingFrame<'_> { } Instruction::InstrumentedForIter => { let src_offset = (self.lasti() - 1) * 2; - let target = bytecode::Label::new(self.lasti() + 1 + u32::from(arg)); + let target = bytecode::Label::from_u32(self.lasti() + 1 + u32::from(arg)); let continued = self.execute_for_iter(vm, target)?; if continued { if self.monitoring_mask & monitoring::EVENT_BRANCH_LEFT != 0 { @@ -5937,7 +5937,7 @@ impl ExecutingFrame<'_> { let obj = self.pop_value(); let value = obj.try_to_bool(vm)?; if value { - self.jump(bytecode::Label::new(target_idx)); + self.jump(bytecode::Label::from_u32(target_idx)); if self.monitoring_mask & monitoring::EVENT_BRANCH_RIGHT != 0 { monitoring::fire_branch_right(vm, self.code, src_offset, target_idx * 2)?; } @@ -5950,7 +5950,7 @@ impl ExecutingFrame<'_> { let obj = self.pop_value(); let value = obj.try_to_bool(vm)?; if !value { - self.jump(bytecode::Label::new(target_idx)); + self.jump(bytecode::Label::from_u32(target_idx)); if self.monitoring_mask & monitoring::EVENT_BRANCH_RIGHT != 0 { monitoring::fire_branch_right(vm, self.code, src_offset, target_idx * 2)?; } @@ -5962,7 +5962,7 @@ impl ExecutingFrame<'_> { let target_idx = self.lasti() + 1 + u32::from(arg); let value = self.pop_value(); if vm.is_none(&value) { - self.jump(bytecode::Label::new(target_idx)); + self.jump(bytecode::Label::from_u32(target_idx)); if self.monitoring_mask & monitoring::EVENT_BRANCH_RIGHT != 0 { monitoring::fire_branch_right(vm, self.code, src_offset, target_idx * 2)?; } @@ -5974,7 +5974,7 @@ impl ExecutingFrame<'_> { let target_idx = self.lasti() + 1 + u32::from(arg); let value = self.pop_value(); if !vm.is_none(&value) { - self.jump(bytecode::Label::new(target_idx)); + self.jump(bytecode::Label::from_u32(target_idx)); if self.monitoring_mask & monitoring::EVENT_BRANCH_RIGHT != 0 { monitoring::fire_branch_right(vm, self.code, src_offset, target_idx * 2)?; } @@ -6366,7 +6366,7 @@ impl ExecutingFrame<'_> { self.push_value(exception.into()); // 4. Jump to handler - self.jump(bytecode::Label::new(entry.target)); + self.jump(bytecode::Label::from_u32(entry.target)); Ok(None) } else { @@ -6971,7 +6971,7 @@ impl ExecutingFrame<'_> { bytecode::Instruction::EndFor | bytecode::Instruction::InstrumentedEndFor ) { - return bytecode::Label::new(target.as_u32() + 1); + return bytecode::Label::from_u32(target.as_u32() + 1); } target } @@ -8952,7 +8952,7 @@ impl ExecutingFrame<'_> { unit.op, bytecode::Instruction::EndFor | bytecode::Instruction::InstrumentedEndFor ) { - bytecode::Label::new(target.as_u32() + 1) + bytecode::Label::from_u32(target.as_u32() + 1) } else { target } From d682618f3aec386bdc830f20955f3f27f83b7bb7 Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Fri, 27 Mar 2026 11:17:42 +0100 Subject: [PATCH 5/8] fix jit --- crates/jit/src/instructions.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/jit/src/instructions.rs b/crates/jit/src/instructions.rs index 956a385e29b..db20b5fd7a6 100644 --- a/crates/jit/src/instructions.rs +++ b/crates/jit/src/instructions.rs @@ -162,7 +162,7 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> { let target = after .checked_add(u32::from(arg)) .ok_or(JitCompileError::BadBytecode)?; - Ok(Label::new(target)) + Ok(Label::from_u32(target)) } fn jump_target_backward( @@ -177,7 +177,7 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> { let target = after .checked_sub(u32::from(arg)) .ok_or(JitCompileError::BadBytecode)?; - Ok(Label::new(target)) + Ok(Label::from_u32(target)) } fn instruction_target( @@ -232,7 +232,7 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> { let mut in_unreachable_code = false; for (offset, &raw_instr) in clean_instructions.iter().enumerate() { - let label = Label::new(offset as u32); + let label = Label::from_u32(offset as u32); let (instruction, arg) = arg_state.get(raw_instr); // If this is a label that some earlier jump can target, From b5d303163c60a3730e11fe34a42235e6e6eda2bf Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Fri, 27 Mar 2026 11:35:33 +0100 Subject: [PATCH 6/8] Use new oparg --- crates/codegen/src/ir.rs | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/crates/codegen/src/ir.rs b/crates/codegen/src/ir.rs index a551146b37c..73da736ef44 100644 --- a/crates/codegen/src/ir.rs +++ b/crates/codegen/src/ir.rs @@ -2188,20 +2188,19 @@ pub(crate) fn label_exception_targets(blocks: &mut [Block]) { } // Set RESUME DEPTH1 flag based on last yield's except depth - if matches!( - blocks[bi].instructions[i].instr.real(), - Some(Instruction::Resume { .. }) - ) { - const RESUME_AT_FUNC_START: u32 = 0; - const RESUME_OPARG_LOCATION_MASK: u32 = 0x3; - const RESUME_OPARG_DEPTH1_MASK: u32 = 0x4; - - if (u32::from(arg) & RESUME_OPARG_LOCATION_MASK) != RESUME_AT_FUNC_START { - if last_yield_except_depth == 1 { - blocks[bi].instructions[i].arg = - OpArg::new(u32::from(arg) | RESUME_OPARG_DEPTH1_MASK); + if let Some(Instruction::Resume { context }) = + blocks[bi].instructions[i].instr.real() + { + let location = context.get(arg).location(); + match location { + oparg::ResumeLocation::AtFuncStart => {} + _ => { + if last_yield_except_depth == 1 { + blocks[bi].instructions[i].arg = + OpArg::new(oparg::ResumeContext::new(location, true).as_u32()); + } + last_yield_except_depth = -1; } - last_yield_except_depth = -1; } } From fb7c1092b4b30d37393e66789fb93d04366e5a7e Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Fri, 27 Mar 2026 11:36:46 +0100 Subject: [PATCH 7/8] Fix doc --- crates/compiler-core/src/bytecode/oparg.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/compiler-core/src/bytecode/oparg.rs b/crates/compiler-core/src/bytecode/oparg.rs index 28650dd56c9..de326f489c5 100644 --- a/crates/compiler-core/src/bytecode/oparg.rs +++ b/crates/compiler-core/src/bytecode/oparg.rs @@ -799,8 +799,8 @@ newtype_oparg!( /// Context for [`Instruction::Resume`]. /// /// The oparg consists of two parts: - /// 1. [`Context::location`]: Indicates where the instruction occurs. - /// 2. [`Context::is_exception_depth1`]: Is the instruction is at except-depth 1. + /// 1. [`ResumeContext::location`]: Indicates where the instruction occurs. + /// 2. [`ResumeContext::is_exception_depth1`]: Is the instruction is at except-depth 1. #[derive(Clone, Copy)] #[repr(transparent)] pub struct ResumeContext(u32) From 07d019a891d030c9b87c04a3a0fe46e967033558 Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Fri, 27 Mar 2026 11:43:01 +0100 Subject: [PATCH 8/8] let `ir` to decide exception depth --- crates/codegen/src/compile.rs | 27 ++++++++-------------- crates/compiler-core/src/bytecode/oparg.rs | 6 +++++ 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/crates/codegen/src/compile.rs b/crates/codegen/src/compile.rs index c3ba6ae8c03..ca63c091cf3 100644 --- a/crates/codegen/src/compile.rs +++ b/crates/codegen/src/compile.rs @@ -1277,9 +1277,7 @@ impl Compiler { context: OpArgMarker::marker(), } .into(), - arg: OpArg::new( - oparg::ResumeContext::new(oparg::ResumeLocation::AtFuncStart, false).into(), - ), + arg: OpArg::new(oparg::ResumeLocation::AtFuncStart.into()), target: BlockIdx::NULL, location, end_location, @@ -7201,14 +7199,11 @@ impl Compiler { emit!( self, Instruction::Resume { - context: oparg::ResumeContext::new( - if is_await { - oparg::ResumeLocation::AfterAwait - } else { - oparg::ResumeLocation::AfterYieldFrom - }, - false - ) + context: if is_await { + oparg::ResumeContext::from(oparg::ResumeLocation::AfterAwait) + } else { + oparg::ResumeContext::from(oparg::ResumeLocation::AfterYieldFrom) + } } ); @@ -7379,10 +7374,7 @@ impl Compiler { emit!( self, Instruction::Resume { - context: oparg::ResumeContext::new( - oparg::ResumeLocation::AfterYield, - true, // TODO: Is this always true? - ) + context: oparg::ResumeContext::from(oparg::ResumeLocation::AfterYield) } ); } @@ -7604,9 +7596,8 @@ impl Compiler { emit!( compiler, Instruction::Resume { - context: oparg::ResumeContext::new( - oparg::ResumeLocation::AfterYield, - true, // TODO: Is this always true? + context: oparg::ResumeContext::from( + oparg::ResumeLocation::AfterYield ) } ); diff --git a/crates/compiler-core/src/bytecode/oparg.rs b/crates/compiler-core/src/bytecode/oparg.rs index de326f489c5..068229f10fd 100644 --- a/crates/compiler-core/src/bytecode/oparg.rs +++ b/crates/compiler-core/src/bytecode/oparg.rs @@ -850,6 +850,12 @@ pub enum ResumeLocation { AfterAwait, } +impl From for ResumeContext { + fn from(location: ResumeLocation) -> Self { + Self::new(location, false) + } +} + impl TryFrom for ResumeLocation { type Error = MarshalError;