Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Lib/_opcode_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,6 @@
'INSTRUMENTED_POP_JUMP_IF_NONE': 252,
'INSTRUMENTED_POP_JUMP_IF_NOT_NONE': 253,
'INSTRUMENTED_LINE': 254,
'LOAD_CLOSURE': 255,
'JUMP': 256,
'JUMP_NO_INTERRUPT': 257,
'RESERVED_258': 258,
Expand All @@ -246,6 +245,7 @@
'SETUP_FINALLY': 265,
'SETUP_WITH': 266,
'STORE_FAST_MAYBE_NULL': 267,
'LOAD_CLOSURE': 268,
}

# CPython 3.13 compatible: opcodes < 44 have no argument
Expand Down
1 change: 0 additions & 1 deletion Lib/test/test__opcode.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ def check_bool_function_result(self, func, ops, expected):
self.assertIsInstance(func(op), bool)
self.assertEqual(func(op), expected)

@unittest.expectedFailure # TODO: RUSTPYTHON; Move LoadClosure to psudoes
def test_invalid_opcodes(self):
invalid = [-100, -1, 255, 512, 513, 1000]
self.check_bool_function_result(_opcode.is_valid, invalid, False)
Expand Down
4 changes: 2 additions & 2 deletions crates/codegen/src/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4074,7 +4074,7 @@ impl Compiler {
}
};

emit!(self, Instruction::LoadClosure(idx.to_u32()));
emit!(self, PseudoInstruction::LoadClosure(idx.to_u32()));
}

// Build tuple of closure variables
Expand Down Expand Up @@ -4297,7 +4297,7 @@ impl Compiler {
.position(|var| *var == "__class__");

if let Some(classcell_idx) = classcell_idx {
emit!(self, Instruction::LoadClosure(classcell_idx.to_u32()));
emit!(self, PseudoInstruction::LoadClosure(classcell_idx.to_u32()));
emit!(self, Instruction::Copy { index: 1_u32 });
let classcell = self.name("__classcell__");
emit!(self, Instruction::StoreName(classcell));
Expand Down
7 changes: 7 additions & 0 deletions crates/codegen/src/ir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,13 @@ impl CodeInfo {
info.arg = OpArg(encoded);
info.instr = Instruction::LoadSuperAttr { arg: Arg::marker() }.into();
}
// LOAD_CLOSURE pseudo → LOAD_FAST (with varnames offset)
PseudoInstruction::LoadClosure(idx) => {
let varnames_len = varname_cache.len() as u32;
let new_idx = varnames_len + idx.get(info.arg);
info.arg = OpArg(new_idx);
info.instr = Instruction::LoadFast(Arg::marker()).into();
}
PseudoInstruction::Jump { .. } => {
// PseudoInstruction::Jump instructions are handled later
}
Expand Down
12 changes: 3 additions & 9 deletions crates/compiler-core/src/bytecode/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -383,8 +383,6 @@ pub enum Instruction {
InstrumentedPopJumpIfNone = 252, // Placeholder
InstrumentedPopJumpIfNotNone = 253, // Placeholder
InstrumentedLine = 254, // Placeholder
// Pseudos (needs to be moved to `PseudoInstruction` enum.
LoadClosure(Arg<NameIdx>) = 255, // TODO: Move to pseudos
}

const _: () = assert!(mem::size_of::<Instruction>() == 1);
Expand Down Expand Up @@ -415,9 +413,6 @@ impl TryFrom<u8> for Instruction {
let instrumented_start = u8::from(Self::InstrumentedResume);
let instrumented_end = u8::from(Self::InstrumentedLine);

// TODO: Remove this; This instruction needs to be pseudo
let load_closure = u8::from(Self::LoadClosure(Arg::marker()));

// RustPython-only opcodes (explicit list to avoid gaps like 125-127)
let custom_ops: &[u8] = &[
u8::from(Self::Break {
Expand Down Expand Up @@ -457,7 +452,6 @@ impl TryFrom<u8> for Instruction {

if (cpython_start..=cpython_end).contains(&value)
|| value == resume_id
|| value == load_closure
|| custom_ops.contains(&value)
|| (specialized_start..=specialized_end).contains(&value)
|| (instrumented_start..=instrumented_end).contains(&value)
Expand Down Expand Up @@ -704,7 +698,6 @@ impl InstructionMetadata for Instruction {
Self::StoreFastStoreFast { .. } => 0,
Self::PopJumpIfNone { .. } => 0,
Self::PopJumpIfNotNone { .. } => 0,
Self::LoadClosure(_) => 1,
Self::BinaryOpAddFloat => 0,
Self::BinaryOpAddInt => 0,
Self::BinaryOpAddUnicode => 0,
Expand Down Expand Up @@ -935,7 +928,6 @@ impl InstructionMetadata for Instruction {
}
Self::LoadBuildClass => w!(LOAD_BUILD_CLASS),
Self::LoadFromDictOrDeref(i) => w!(LOAD_FROM_DICT_OR_DEREF, cell_name = i),
Self::LoadClosure(i) => w!(LOAD_CLOSURE, cell_name = i),
Self::LoadConst { idx } => fmt_const("LOAD_CONST", arg, f, idx),
Self::LoadDeref(idx) => w!(LOAD_DEREF, cell_name = idx),
Self::LoadFast(idx) => w!(LOAD_FAST, varname = idx),
Expand Down Expand Up @@ -1037,6 +1029,7 @@ pub enum PseudoInstruction {
SetupFinally = 265, // Placeholder
SetupWith = 266, // Placeholder
StoreFastMaybeNull = 267, // Placeholder
LoadClosure(Arg<NameIdx>) = 268,
}

const _: () = assert!(mem::size_of::<PseudoInstruction>() == 2);
Expand All @@ -1057,7 +1050,7 @@ impl TryFrom<u16> for PseudoInstruction {
let start = u16::from(Self::Jump {
target: Arg::marker(),
});
let end = u16::from(Self::StoreFastMaybeNull);
let end = u16::from(Self::LoadClosure(Arg::marker()));

if (start..=end).contains(&value) {
Ok(unsafe { mem::transmute::<u16, Self>(value) })
Expand Down Expand Up @@ -1093,6 +1086,7 @@ impl InstructionMetadata for PseudoInstruction {
Self::SetupWith => 0,
Self::StoreFastMaybeNull => 0,
Self::Reserved258 => 0,
Self::LoadClosure(_) => 1,
}
}

Expand Down
1 change: 0 additions & 1 deletion crates/stdlib/src/opcode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,6 @@ mod opcode {
Ok(AnyInstruction::Real(
Instruction::DeleteDeref(_)
| Instruction::LoadFromDictOrDeref(_)
| Instruction::LoadClosure(_)
| Instruction::LoadDeref(_)
| Instruction::StoreDeref(_)
))
Expand Down
31 changes: 21 additions & 10 deletions crates/vm/src/frame.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#[cfg(feature = "flame")]
use crate::bytecode::InstructionMetadata;
use crate::{
AsObject, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject, VirtualMachine,
builtins::{
Expand Down Expand Up @@ -137,10 +139,24 @@ impl Frame {
func_obj: Option<PyObjectRef>,
vm: &VirtualMachine,
) -> Self {
let cells_frees = core::iter::repeat_with(|| PyCell::default().into_ref(&vm.ctx))
.take(code.cellvars.len())
.chain(closure.iter().cloned())
.collect();
let nlocals = code.varnames.len();
let num_cells = code.cellvars.len();
let nfrees = closure.len();

let cells_frees: Box<[PyCellRef]> =
core::iter::repeat_with(|| PyCell::default().into_ref(&vm.ctx))
.take(num_cells)
.chain(closure.iter().cloned())
.collect();

// Extend fastlocals to include varnames + cellvars + freevars (localsplus)
let total_locals = nlocals + num_cells + nfrees;
let mut fastlocals_vec: Vec<Option<PyObjectRef>> = vec![None; total_locals];

// Store cell objects at cellvars and freevars positions
for (i, cell) in cells_frees.iter().enumerate() {
fastlocals_vec[nlocals + i] = Some(cell.clone().into());
}

let state = FrameState {
stack: BoxVec::new(code.max_stackdepth as usize),
Expand All @@ -149,7 +165,7 @@ impl Frame {
};

Self {
fastlocals: PyMutex::new(vec![None; code.varnames.len()].into_boxed_slice()),
fastlocals: PyMutex::new(fastlocals_vec.into_boxed_slice()),
cells_frees,
locals: scope.locals,
globals: scope.globals,
Expand Down Expand Up @@ -1213,11 +1229,6 @@ impl ExecutingFrame<'_> {
});
Ok(None)
}
Instruction::LoadClosure(i) => {
let value = self.cells_frees[i.get(arg) as usize].clone();
self.push_value(value.into());
Ok(None)
}
Instruction::LoadConst { idx } => {
self.push_value(self.code.constants[idx.get(arg) as usize].clone().into());
Ok(None)
Expand Down
Loading