Remove SUBSCRIPT, JUMP_IF_{TRUE,FALSE}_OR_POP (#6810)

* Align ForIter behavior (incomplete)

* Romove JUMP_IF_{TRUE,FALSE}_OR_POP, subscript

* Remove LoadAssetionError

* Update snapshot for ForIter behavior change
This commit is contained in:
Jeong, YunWon
2026-01-20 16:21:23 +09:00
committed by GitHub
parent 52a854a57a
commit f0c3e7d51f
6 changed files with 17 additions and 94 deletions

View File

@@ -218,13 +218,9 @@ opmap = {
'BUILD_CONST_KEY_MAP': 215,
'BREAK': 216,
'CONTINUE': 217,
'JUMP_IF_FALSE_OR_POP': 218,
'JUMP_IF_TRUE_OR_POP': 219,
'JUMP_IF_NOT_EXC_MATCH': 220,
'LOAD_ASSERTION_ERROR': 221,
'RETURN_CONST': 222,
'SET_EXC_INFO': 223,
'SUBSCRIPT': 224,
'INSTRUMENTED_END_FOR': 234,
'INSTRUMENTED_POP_ITER': 235,
'INSTRUMENTED_END_SEND': 236,

View File

@@ -489,7 +489,7 @@ impl Compiler {
match ctx {
ast::ExprContext::Load => {
emit!(self, Instruction::BuildSlice { argc });
emit!(self, Instruction::Subscript);
emit!(self, Instruction::BinarySubscr);
}
ast::ExprContext::Store => {
emit!(self, Instruction::BuildSlice { argc });
@@ -503,7 +503,7 @@ impl Compiler {
// Emit appropriate instruction based on context
match ctx {
ast::ExprContext::Load => emit!(self, Instruction::Subscript),
ast::ExprContext::Load => emit!(self, Instruction::BinarySubscr),
ast::ExprContext::Store => emit!(self, Instruction::StoreSubscr),
ast::ExprContext::Del => emit!(self, Instruction::DeleteSubscr),
ast::ExprContext::Invalid => {
@@ -4929,6 +4929,9 @@ impl Compiler {
if is_async {
emit!(self, Instruction::EndAsyncFor);
} else {
// Pop the iterator after loop ends
emit!(self, Instruction::PopTop);
}
self.compile_statements(orelse)?;
@@ -5987,14 +5990,9 @@ impl Compiler {
self.compile_addcompare(op);
// if comparison result is false, we break with this value; if true, try the next one.
/*
emit!(self, Instruction::Copy { index: 1 });
// emit!(self, Instruction::ToBool); // TODO: Uncomment this
emit!(self, Instruction::PopJumpIfFalse { target: cleanup });
emit!(self, Instruction::PopTop);
*/
emit!(self, Instruction::JumpIfFalseOrPop { target: cleanup });
}
self.compile_expression(last_comparator)?;
@@ -6205,7 +6203,7 @@ impl Compiler {
self.compile_expression(slice)?;
emit!(self, Instruction::Copy { index: 2_u32 });
emit!(self, Instruction::Copy { index: 2_u32 });
emit!(self, Instruction::Subscript);
emit!(self, Instruction::BinarySubscr);
AugAssignKind::Subscript
}
ast::Expr::Attribute(ast::ExprAttribute { value, attr, .. }) => {
@@ -7367,6 +7365,8 @@ impl Compiler {
if is_async {
emit!(self, Instruction::EndAsyncFor);
emit!(self, Instruction::PopTop);
} else {
emit!(self, Instruction::PopTop);
}
}

View File

@@ -1,5 +1,6 @@
---
source: crates/codegen/src/compile.rs
assertion_line: 8626
expression: "compile_exec(\"\\\nasync def test():\n for stop_exc in (StopIteration('spam'), StopAsyncIteration('ham')):\n with self.subTest(type=type(stop_exc)):\n try:\n async with egg():\n raise stop_exc\n except Exception as ex:\n self.assertIs(ex, stop_exc)\n else:\n self.fail(f'{stop_exc} was suppressed')\n\")"
---
3 0 LOAD_CONST (<code object test at ??? file "source_path", line 1>): 1 0 RESUME (0)
@@ -140,7 +141,8 @@ expression: "compile_exec(\"\\\nasync def test():\n for stop_exc in (StopIter
126 POP_EXCEPT
127 RERAISE (1)
>> 128 JUMP_BACKWARD (11)
>> 129 RETURN_CONST (None)
>> 129 POP_TOP
130 RETURN_CONST (None)
1 MAKE_FUNCTION
2 STORE_NAME (0, test)

View File

@@ -272,19 +272,11 @@ pub enum Instruction {
Continue {
target: Arg<Label>,
} = 217,
JumpIfFalseOrPop {
target: Arg<Label>,
} = 218,
JumpIfTrueOrPop {
target: Arg<Label>,
} = 219,
JumpIfNotExcMatch(Arg<Label>) = 220,
LoadAssertionError = 221, // Placeholder
ReturnConst {
idx: Arg<u32>,
} = 222,
SetExcInfo = 223,
Subscript = 224,
// CPython 3.14 RESUME (128)
Resume {
arg: Arg<u32>,
@@ -441,17 +433,9 @@ impl TryFrom<u8> for Instruction {
u8::from(Self::Continue {
target: Arg::marker(),
}),
u8::from(Self::JumpIfFalseOrPop {
target: Arg::marker(),
}),
u8::from(Self::JumpIfTrueOrPop {
target: Arg::marker(),
}),
u8::from(Self::JumpIfNotExcMatch(Arg::marker())),
u8::from(Self::LoadAssertionError),
u8::from(Self::ReturnConst { idx: Arg::marker() }),
u8::from(Self::SetExcInfo),
u8::from(Self::Subscript),
];
if (cpython_start..=cpython_end).contains(&value)
@@ -478,8 +462,6 @@ impl InstructionMetadata for Instruction {
| Self::JumpIfNotExcMatch(l)
| Self::PopJumpIfTrue { target: l }
| Self::PopJumpIfFalse { target: l }
| Self::JumpIfTrueOrPop { target: l }
| Self::JumpIfFalseOrPop { target: l }
| Self::ForIter { target: l }
| Self::Break { target: l }
| Self::Continue { target: l }
@@ -525,7 +507,6 @@ impl InstructionMetadata for Instruction {
Self::DeleteGlobal(_) => 0,
Self::DeleteDeref(_) => 0,
Self::LoadFromDictOrDeref(_) => 1,
Self::Subscript => -1,
Self::StoreSubscr => -3,
Self::DeleteSubscr => -2,
Self::LoadAttr { .. } => 0,
@@ -551,20 +532,6 @@ impl InstructionMetadata for Instruction {
Self::Break { .. } => 0,
Self::PopJumpIfTrue { .. } => -1,
Self::PopJumpIfFalse { .. } => -1,
Self::JumpIfTrueOrPop { .. } => {
if jump {
0
} else {
-1
}
}
Self::JumpIfFalseOrPop { .. } => {
if jump {
0
} else {
-1
}
}
Self::MakeFunction => {
// CPython 3.14 style: MakeFunction only pops code object
-1 + 1 // pop code, push function
@@ -584,11 +551,9 @@ impl InstructionMetadata for Instruction {
Self::FormatSimple => 0,
Self::FormatWithSpec => -1,
Self::ForIter { .. } => {
if jump {
-1
} else {
1
}
// jump=False: push next value (+1)
// jump=True: iterator stays on stack, no change (0)
if jump { 0 } else { 1 }
}
Self::IsOp(_) => -1,
Self::ContainsOp(_) => -1,
@@ -684,7 +649,6 @@ impl InstructionMetadata for Instruction {
Self::EndFor => 0,
Self::ExitInitCheck => 0,
Self::InterpreterExit => 0,
Self::LoadAssertionError => 0,
Self::LoadLocals => 0,
Self::ReturnGenerator => 0,
Self::StoreSlice => 0,
@@ -920,9 +884,7 @@ 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::JumpIfFalseOrPop { target } => w!(JUMP_IF_FALSE_OR_POP, target),
Self::JumpIfNotExcMatch(target) => w!(JUMP_IF_NOT_EXC_MATCH, target),
Self::JumpIfTrueOrPop { target } => w!(JUMP_IF_TRUE_OR_POP, target),
Self::ListAppend { i } => w!(LIST_APPEND, i),
Self::ListExtend { i } => w!(LIST_EXTEND, i),
Self::LoadAttr { idx } => {
@@ -994,7 +956,6 @@ impl InstructionMetadata for Instruction {
Self::StoreGlobal(idx) => w!(STORE_GLOBAL, name = idx),
Self::StoreName(idx) => w!(STORE_NAME, name = idx),
Self::StoreSubscr => w!(STORE_SUBSCR),
Self::Subscript => w!(SUBSCRIPT),
Self::Swap { index } => w!(SWAP, index),
Self::ToBool => w!(TO_BOOL),
Self::UnpackEx { args } => w!(UNPACK_EX, args),

View File

@@ -107,9 +107,7 @@ mod opcode {
Instruction::Break { .. }
| Instruction::Continue { .. }
| Instruction::ForIter { .. }
| Instruction::JumpIfFalseOrPop { .. }
| Instruction::JumpIfNotExcMatch(_)
| Instruction::JumpIfTrueOrPop { .. }
| Instruction::PopJumpIfFalse { .. }
| Instruction::PopJumpIfTrue { .. }
| Instruction::Send { .. }

View File

@@ -1139,9 +1139,6 @@ impl ExecutingFrame<'_> {
self.push_value(vm.ctx.new_bool(value).into());
Ok(None)
}
Instruction::JumpIfFalseOrPop { target } => {
self.jump_if_or_pop(vm, target.get(arg), false)
}
Instruction::JumpIfNotExcMatch(target) => {
let b = self.pop_value();
let a = self.pop_value();
@@ -1165,9 +1162,6 @@ impl ExecutingFrame<'_> {
self.push_value(vm.ctx.new_bool(value).into());
self.pop_jump_if(vm, target.get(arg), false)
}
Instruction::JumpIfTrueOrPop { target } => {
self.jump_if_or_pop(vm, target.get(arg), true)
}
Instruction::JumpForward { target } => {
self.jump(target.get(arg));
Ok(None)
@@ -1734,7 +1728,6 @@ impl ExecutingFrame<'_> {
Ok(None)
}
Instruction::StoreSubscr => self.execute_store_subscript(vm),
Instruction::Subscript => self.execute_subscript(vm),
Instruction::Swap { index } => {
let len = self.state.stack.len();
debug_assert!(len > 0, "stack underflow in SWAP");
@@ -2074,14 +2067,6 @@ impl ExecutingFrame<'_> {
}
}
fn execute_subscript(&mut self, vm: &VirtualMachine) -> FrameResult {
let b_ref = self.pop_value();
let a_ref = self.pop_value();
let value = a_ref.get_item(&*b_ref, vm)?;
self.push_value(value);
Ok(None)
}
fn execute_store_subscript(&mut self, vm: &VirtualMachine) -> FrameResult {
let idx = self.pop_value();
let obj = self.pop_value();
@@ -2351,23 +2336,6 @@ impl ExecutingFrame<'_> {
Ok(None)
}
#[inline]
fn jump_if_or_pop(
&mut self,
vm: &VirtualMachine,
target: bytecode::Label,
flag: bool,
) -> FrameResult {
let obj = self.top_value();
let value = obj.to_owned().try_to_bool(vm)?;
if value == flag {
self.jump(target);
} else {
self.pop_value();
}
Ok(None)
}
/// The top of stack contains the iterator, lets push it forward
fn execute_for_iter(&mut self, vm: &VirtualMachine, target: bytecode::Label) -> FrameResult {
let top_of_stack = PyIter::new(self.top_value());
@@ -2380,15 +2348,13 @@ impl ExecutingFrame<'_> {
Ok(None)
}
Ok(PyIterReturn::StopIteration(_)) => {
// Pop iterator from stack:
self.pop_value();
// End of for loop
// CPython 3.14: Do NOT pop iterator here
// POP_ITER instruction will handle cleanup after the loop
self.jump(target);
Ok(None)
}
Err(next_error) => {
// Pop iterator from stack:
// On error, pop iterator and propagate
self.pop_value();
Err(next_error)
}