Skip to content

Commit 5f8f38d

Browse files
committed
Fix test__opcode.py
1 parent cf536b7 commit 5f8f38d

3 files changed

Lines changed: 26 additions & 14 deletions

File tree

Lib/test/test__opcode.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ def test_is_valid(self):
3838
opcodes = [dis.opmap[opname] for opname in names]
3939
self.check_bool_function_result(_opcode.is_valid, opcodes, True)
4040

41-
@unittest.expectedFailure # TODO: RUSTPYTHON; KeyError: 'BINARY_OP_ADD_INT'
4241
def test_opmaps(self):
4342
def check_roundtrip(name, map):
4443
return self.assertEqual(opcode.opname[map[name]], name)
@@ -116,7 +115,6 @@ def test_stack_effect_jump(self):
116115

117116

118117
class SpecializationStatsTests(unittest.TestCase):
119-
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: 'load_attr' not found in []
120118
def test_specialization_stats(self):
121119
stat_names = ["success", "failure", "hit", "deferred", "miss", "deopt"]
122120
specialized_opcodes = [

crates/compiler-core/src/bytecode/instruction.rs

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -462,7 +462,7 @@ impl TryFrom<u8> for Instruction {
462462
impl Instruction {
463463
/// Returns `true` if this is any instrumented opcode
464464
/// (regular INSTRUMENTED_*, INSTRUMENTED_LINE, or INSTRUMENTED_INSTRUCTION).
465-
pub fn is_instrumented(self) -> bool {
465+
pub const fn is_instrumented(self) -> bool {
466466
self.to_base().is_some()
467467
|| matches!(self, Self::InstrumentedLine | Self::InstrumentedInstruction)
468468
}
@@ -509,7 +509,7 @@ impl Instruction {
509509
///
510510
/// The returned base opcode uses `Arg::marker()` for typed fields —
511511
/// only the opcode byte matters since `replace_op` preserves the arg byte.
512-
pub fn to_base(self) -> Option<Self> {
512+
pub const fn to_base(self) -> Option<Self> {
513513
Some(match self {
514514
Self::InstrumentedResume => Self::Resume {
515515
context: Arg::marker(),
@@ -555,11 +555,10 @@ impl Instruction {
555555
_ => return None,
556556
})
557557
}
558-
559-
/// Map a specialized opcode back to its adaptive (base) variant.
558+
/// Map a specialized or instrumented opcode back to its adaptive (base) variant.
560559
/// `_PyOpcode_Deopt`
561-
pub fn deoptimize(self) -> Self {
562-
match self {
560+
pub const fn deopt(self) -> Option<Self> {
561+
Some(match self {
563562
// RESUME specializations
564563
Self::ResumeCheck => Self::Resume {
565564
context: Arg::marker(),
@@ -678,17 +677,27 @@ impl Instruction {
678677
Self::CallKwBoundMethod | Self::CallKwPy | Self::CallKwNonPy => Self::CallKw {
679678
argc: Arg::marker(),
680679
},
681-
// Instrumented opcodes map back to their base
682-
_ => match self.to_base() {
683-
Some(base) => base,
684-
None => self,
685-
},
680+
_ => return None,
681+
})
682+
}
683+
684+
/// Map a specialized opcode back to its adaptive (base) variant.
685+
pub const fn deoptimize(self) -> Self {
686+
match self.deopt() {
687+
Some(v) => v,
688+
None => {
689+
// Instrumented opcodes map back to their base
690+
match self.to_base() {
691+
Some(v) => v,
692+
None => self,
693+
}
694+
}
686695
}
687696
}
688697

689698
/// Number of CACHE code units that follow this instruction.
690699
/// _PyOpcode_Caches
691-
pub fn cache_entries(self) -> usize {
700+
pub const fn cache_entries(self) -> usize {
692701
match self {
693702
// LOAD_ATTR: 9 cache entries
694703
Self::LoadAttr { .. }

crates/stdlib/src/_opcode.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,11 @@ mod _opcode {
197197

198198
let opcode = Opcode::try_from_pyint(args.opcode, vm)?;
199199

200+
// Raise ValueError if specialized.
201+
if opcode.inner().real().is_some_and(|op| op.deopt().is_some()) {
202+
return Err(vm.new_value_error("invalid opcode or oparg"));
203+
}
204+
200205
let _ = jump; // Python API accepts jump but it's not used
201206
Ok(opcode.stack_effect(oparg))
202207
}

0 commit comments

Comments
 (0)