Remove JUMP_IF_NOT_EXC_MATCH, SET_EXC_INFO (#6820)

This commit is contained in:
Jeong, YunWon
2026-01-21 01:23:43 +09:00
committed by GitHub
parent 90ff571493
commit 274e8b4b6b
6 changed files with 41 additions and 57 deletions

View File

@@ -216,8 +216,6 @@ opmap = {
'BEFORE_WITH': 213,
'BINARY_SUBSCR': 214,
'BUILD_CONST_KEY_MAP': 215,
'JUMP_IF_NOT_EXC_MATCH': 220,
'SET_EXC_INFO': 223,
'INSTRUMENTED_END_FOR': 234,
'INSTRUMENTED_POP_ITER': 235,
'INSTRUMENTED_END_SEND': 236,

View File

@@ -2925,12 +2925,19 @@ impl Compiler {
// If we gave a typ,
// check if this handler can handle the exception:
if let Some(exc_type) = type_ {
// Duplicate exception for test:
emit!(self, Instruction::Copy { index: 1_u32 });
// Check exception type:
// Stack: [prev_exc, exc]
self.compile_expression(exc_type)?;
emit!(self, Instruction::JumpIfNotExcMatch(next_handler));
// Stack: [prev_exc, exc, type]
emit!(self, Instruction::CheckExcMatch);
// Stack: [prev_exc, exc, bool]
emit!(
self,
Instruction::PopJumpIfFalse {
target: next_handler
}
);
// Stack: [prev_exc, exc]
// We have a match, store in name (except x as y)
if let Some(alias) = name {
@@ -3308,13 +3315,9 @@ impl Compiler {
// Handler matched
// Stack: [prev_exc, orig, list, new_rest, match]
// Note: CheckEgMatch already sets the matched exception as current exception
let handler_except_block = self.new_block();
// Set matched exception as current exception (for __context__ in handler body)
// This ensures that exceptions raised in the handler get the matched part
// as their __context__, not the original full exception group
emit!(self, Instruction::SetExcInfo);
// Store match to name or pop
if let Some(alias) = name {
self.store_name(alias.as_str())?;

View File

@@ -83,10 +83,10 @@ expression: "compile_exec(\"\\\nasync def test():\n for stop_exc in (StopIter
73 RERAISE (1)
>> 74 JUMP_FORWARD (100)
75 PUSH_EXC_INFO
76 COPY (1)
7 77 LOAD_GLOBAL (6, Exception)
78 JUMP_IF_NOT_EXC_MATCH(96)
7 76 LOAD_GLOBAL (6, Exception)
77 CHECK_EXC_MATCH
78 POP_JUMP_IF_FALSE (96)
79 STORE_FAST (1, ex)
8 80 LOAD_GLOBAL (2, self)

View File

@@ -266,8 +266,6 @@ pub enum Instruction {
BuildConstKeyMap {
size: Arg<u32>,
} = 215, // Placeholder
JumpIfNotExcMatch(Arg<Label>) = 220,
SetExcInfo = 223,
// CPython 3.14 RESUME (128)
Resume {
arg: Arg<u32>,
@@ -418,8 +416,6 @@ impl TryFrom<u8> for Instruction {
u8::from(Self::BuildConstKeyMap {
size: Arg::marker(),
}),
u8::from(Self::JumpIfNotExcMatch(Arg::marker())),
u8::from(Self::SetExcInfo),
];
if (cpython_start..=cpython_end).contains(&value)
@@ -443,7 +439,6 @@ impl InstructionMetadata for Instruction {
Self::JumpBackward { target: l }
| Self::JumpBackwardNoInterrupt { target: l }
| Self::JumpForward { target: l }
| Self::JumpIfNotExcMatch(l)
| Self::PopJumpIfTrue { target: l }
| Self::PopJumpIfFalse { target: l }
| Self::ForIter { target: l }
@@ -534,7 +529,6 @@ impl InstructionMetadata for Instruction {
}
Self::IsOp(_) => -1,
Self::ContainsOp(_) => -1,
Self::JumpIfNotExcMatch(_) => -2,
Self::ReturnValue => -1,
Self::Resume { .. } => 0,
Self::YieldValue { .. } => 0,
@@ -544,7 +538,6 @@ impl InstructionMetadata for Instruction {
Self::EndSend => -1,
// CLEANUP_THROW: (sub_iter, last_sent_val, exc) -> (None, value) = 3 pop, 2 push = -1
Self::CleanupThrow => -1,
Self::SetExcInfo => 0,
Self::PushExcInfo => 1, // [exc] -> [prev_exc, exc]
Self::CheckExcMatch => 0, // [exc, type] -> [exc, bool] (pops type, pushes bool)
Self::Reraise { .. } => 0, // Exception raised, stack effect doesn't matter
@@ -858,7 +851,6 @@ impl InstructionMetadata for Instruction {
Self::JumpBackward { target } => w!(JUMP_BACKWARD, target),
Self::JumpBackwardNoInterrupt { target } => w!(JUMP_BACKWARD_NO_INTERRUPT, target),
Self::JumpForward { target } => w!(JUMP_FORWARD, target),
Self::JumpIfNotExcMatch(target) => w!(JUMP_IF_NOT_EXC_MATCH, target),
Self::ListAppend { i } => w!(LIST_APPEND, i),
Self::ListExtend { i } => w!(LIST_EXTEND, i),
Self::LoadAttr { idx } => {
@@ -912,7 +904,6 @@ impl InstructionMetadata for Instruction {
Self::ReturnValue => w!(RETURN_VALUE),
Self::Send { target } => w!(SEND, target),
Self::SetAdd { i } => w!(SET_ADD, i),
Self::SetExcInfo => w!(SET_EXC_INFO),
Self::SetFunctionAttribute { attr } => w!(SET_FUNCTION_ATTRIBUTE, ?attr),
Self::SetupAnnotations => w!(SETUP_ANNOTATIONS),
Self::SetUpdate { i } => w!(SET_UPDATE, i),

View File

@@ -103,7 +103,6 @@ mod opcode {
Self::try_from(opcode).map(|op| op.inner()),
Ok(AnyInstruction::Real(
Instruction::ForIter { .. }
| Instruction::JumpIfNotExcMatch(_)
| Instruction::PopJumpIfFalse { .. }
| Instruction::PopJumpIfTrue { .. }
| Instruction::Send { .. }

View File

@@ -775,6 +775,15 @@ impl ExecutingFrame<'_> {
let exc_value = self.pop_value();
let (rest, matched) =
crate::exceptions::exception_group_match(&exc_value, &match_type, vm)?;
// Set matched exception as current exception (if not None)
// This mirrors CPython's PyErr_SetHandledException(match_o) in CHECK_EG_MATCH
if !vm.is_none(&matched)
&& let Some(exc) = matched.downcast_ref::<PyBaseException>()
{
vm.set_exception(Some(exc.to_owned()));
}
self.push_value(rest);
self.push_value(matched);
Ok(None)
@@ -1119,29 +1128,6 @@ impl ExecutingFrame<'_> {
self.push_value(vm.ctx.new_bool(value).into());
Ok(None)
}
Instruction::JumpIfNotExcMatch(target) => {
let b = self.pop_value();
let a = self.pop_value();
if let Some(tuple_of_exceptions) = b.downcast_ref::<PyTuple>() {
for exception in tuple_of_exceptions {
if !exception
.is_subclass(vm.ctx.exceptions.base_exception_type.into(), vm)?
{
return Err(vm.new_type_error(
"catching classes that do not inherit from BaseException is not allowed",
));
}
}
} else if !b.is_subclass(vm.ctx.exceptions.base_exception_type.into(), vm)? {
return Err(vm.new_type_error(
"catching classes that do not inherit from BaseException is not allowed",
));
}
let value = a.is_instance(&b, vm)?;
self.push_value(vm.ctx.new_bool(value).into());
self.pop_jump_if(vm, target.get(arg), false)
}
Instruction::JumpForward { target } => {
self.jump(target.get(arg));
Ok(None)
@@ -1569,15 +1555,6 @@ impl ExecutingFrame<'_> {
}
Ok(None)
}
Instruction::SetExcInfo => {
// Set the current exception to TOS (for except* handlers)
// This updates sys.exc_info() so bare 'raise' will reraise the matched exception
let exc = self.top_value();
if let Some(exc) = exc.downcast_ref::<PyBaseException>() {
vm.set_exception(Some(exc.to_owned()));
}
Ok(None)
}
Instruction::PushExcInfo => {
// Stack: [exc] -> [prev_exc, exc]
let exc = self.pop_value();
@@ -1600,7 +1577,23 @@ impl ExecutingFrame<'_> {
let exc_type = self.pop_value();
let exc = self.top_value();
// Validate that exc_type is valid for exception matching
// Validate that exc_type inherits from BaseException
if let Some(tuple_of_exceptions) = exc_type.downcast_ref::<PyTuple>() {
for exception in tuple_of_exceptions {
if !exception
.is_subclass(vm.ctx.exceptions.base_exception_type.into(), vm)?
{
return Err(vm.new_type_error(
"catching classes that do not inherit from BaseException is not allowed",
));
}
}
} else if !exc_type.is_subclass(vm.ctx.exceptions.base_exception_type.into(), vm)? {
return Err(vm.new_type_error(
"catching classes that do not inherit from BaseException is not allowed",
));
}
let result = exc.is_instance(&exc_type, vm)?;
self.push_value(vm.ctx.new_bool(result).into());
Ok(None)