Skip to content

Commit 1c95128

Browse files
committed
align psuedo ops to 3.14.2
1 parent 2b5462c commit 1c95128

File tree

5 files changed

+89
-107
lines changed

5 files changed

+89
-107
lines changed

Lib/_opcode_metadata.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -245,10 +245,6 @@
245245
'SETUP_FINALLY': 264,
246246
'SETUP_WITH': 265,
247247
'STORE_FAST_MAYBE_NULL': 266,
248-
'LOAD_ATTR_METHOD': 267,
249-
'LOAD_SUPER_METHOD': 268,
250-
'LOAD_ZERO_SUPER_ATTR': 269,
251-
'LOAD_ZERO_SUPER_METHOD': 270,
252248
}
253249

254250
# CPython 3.13 compatible: opcodes < 44 have no argument

crates/codegen/src/compile.rs

Lines changed: 53 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ use rustpython_compiler_core::{
3131
self, AnyInstruction, Arg as OpArgMarker, BinaryOperator, BuildSliceArgCount, CodeObject,
3232
ComparisonOperator, ConstantData, ConvertValueOparg, Instruction, IntrinsicFunction1,
3333
Invert, OpArg, OpArgType, PseudoInstruction, SpecialMethod, UnpackExArgs,
34+
encode_load_attr_arg, encode_load_super_attr_arg,
3435
},
3536
};
3637
use rustpython_wtf8::Wtf8Buf;
@@ -2108,7 +2109,7 @@ impl Compiler {
21082109
if let Some(alias) = &name.asname {
21092110
for part in name.name.split('.').skip(1) {
21102111
let idx = self.name(part);
2111-
emit!(self, Instruction::LoadAttr { idx });
2112+
self.emit_load_attr(idx);
21122113
}
21132114
self.store_name(alias.as_str())?
21142115
} else {
@@ -6280,7 +6281,7 @@ impl Compiler {
62806281
self.compile_expression(value)?;
62816282
emit!(self, Instruction::Copy { index: 1_u32 });
62826283
let idx = self.name(attr);
6283-
emit!(self, Instruction::LoadAttr { idx });
6284+
self.emit_load_attr(idx);
62846285
AugAssignKind::Attr { idx }
62856286
}
62866287
_ => {
@@ -6615,19 +6616,17 @@ impl Compiler {
66156616
let idx = self.name(attr.as_str());
66166617
match super_type {
66176618
SuperCallType::TwoArg { .. } => {
6618-
// LoadSuperAttr (pseudo) - will be converted to real LoadSuperAttr
6619-
// with flags=0b10 (has_class=true, load_method=false) in ir.rs
6620-
emit!(self, Instruction::LoadSuperAttr { arg: idx });
6619+
self.emit_load_super_attr(idx);
66216620
}
66226621
SuperCallType::ZeroArg => {
6623-
emit!(self, PseudoInstruction::LoadZeroSuperAttr { idx });
6622+
self.emit_load_zero_super_attr(idx);
66246623
}
66256624
}
66266625
} else {
66276626
// Normal attribute access
66286627
self.compile_expression(value)?;
66296628
let idx = self.name(attr.as_str());
6630-
emit!(self, Instruction::LoadAttr { idx });
6629+
self.emit_load_attr(idx);
66316630
}
66326631
}
66336632
ast::Expr::Compare(ast::ExprCompare {
@@ -7070,19 +7069,19 @@ impl Compiler {
70707069
let idx = self.name(attr.as_str());
70717070
match super_type {
70727071
SuperCallType::TwoArg { .. } => {
7073-
emit!(self, PseudoInstruction::LoadSuperMethod { idx });
7072+
self.emit_load_super_method(idx);
70747073
}
70757074
SuperCallType::ZeroArg => {
7076-
emit!(self, PseudoInstruction::LoadZeroSuperMethod { idx });
7075+
self.emit_load_zero_super_method(idx);
70777076
}
70787077
}
70797078
self.codegen_call_helper(0, args)?;
70807079
} else {
7081-
// Normal method call: compile object, then LOAD_ATTR_METHOD
7082-
// LOAD_ATTR_METHOD pushes [method, self_or_null] on stack
7080+
// Normal method call: compile object, then LOAD_ATTR with method flag
7081+
// LOAD_ATTR(method=1) pushes [method, self_or_null] on stack
70837082
self.compile_expression(value)?;
70847083
let idx = self.name(attr.as_str());
7085-
emit!(self, PseudoInstruction::LoadAttrMethod { idx });
7084+
self.emit_load_attr_method(idx);
70867085
self.codegen_call_helper(0, args)?;
70877086
}
70887087
} else {
@@ -7782,6 +7781,48 @@ impl Compiler {
77827781
emit!(self, Instruction::ReturnValue)
77837782
}
77847783

7784+
/// Emit LOAD_ATTR for attribute access (method=false).
7785+
/// Encodes: (name_idx << 1) | 0
7786+
fn emit_load_attr(&mut self, name_idx: u32) {
7787+
let encoded = encode_load_attr_arg(name_idx, false);
7788+
self.emit_arg(encoded, |arg| Instruction::LoadAttr { idx: arg })
7789+
}
7790+
7791+
/// Emit LOAD_ATTR with method flag set (for method calls).
7792+
/// Encodes: (name_idx << 1) | 1
7793+
fn emit_load_attr_method(&mut self, name_idx: u32) {
7794+
let encoded = encode_load_attr_arg(name_idx, true);
7795+
self.emit_arg(encoded, |arg| Instruction::LoadAttr { idx: arg })
7796+
}
7797+
7798+
/// Emit LOAD_SUPER_ATTR for 2-arg super().attr access.
7799+
/// Encodes: (name_idx << 2) | 0b10 (method=0, class=1)
7800+
fn emit_load_super_attr(&mut self, name_idx: u32) {
7801+
let encoded = encode_load_super_attr_arg(name_idx, false, true);
7802+
self.emit_arg(encoded, |arg| Instruction::LoadSuperAttr { arg })
7803+
}
7804+
7805+
/// Emit LOAD_SUPER_ATTR for 2-arg super().method() call.
7806+
/// Encodes: (name_idx << 2) | 0b11 (method=1, class=1)
7807+
fn emit_load_super_method(&mut self, name_idx: u32) {
7808+
let encoded = encode_load_super_attr_arg(name_idx, true, true);
7809+
self.emit_arg(encoded, |arg| Instruction::LoadSuperAttr { arg })
7810+
}
7811+
7812+
/// Emit LOAD_SUPER_ATTR for 0-arg super().attr access.
7813+
/// Encodes: (name_idx << 2) | 0b00 (method=0, class=0)
7814+
fn emit_load_zero_super_attr(&mut self, name_idx: u32) {
7815+
let encoded = encode_load_super_attr_arg(name_idx, false, false);
7816+
self.emit_arg(encoded, |arg| Instruction::LoadSuperAttr { arg })
7817+
}
7818+
7819+
/// Emit LOAD_SUPER_ATTR for 0-arg super().method() call.
7820+
/// Encodes: (name_idx << 2) | 0b01 (method=1, class=0)
7821+
fn emit_load_zero_super_method(&mut self, name_idx: u32) {
7822+
let encoded = encode_load_super_attr_arg(name_idx, true, false);
7823+
self.emit_arg(encoded, |arg| Instruction::LoadSuperAttr { arg })
7824+
}
7825+
77857826
fn emit_return_value(&mut self) {
77867827
emit!(self, Instruction::ReturnValue)
77877828
}

crates/codegen/src/ir.rs

Lines changed: 4 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@ use rustpython_compiler_core::{
77
bytecode::{
88
AnyInstruction, Arg, CodeFlags, CodeObject, CodeUnit, CodeUnits, ConstantData,
99
ExceptionTableEntry, InstrDisplayContext, Instruction, InstructionMetadata, Label, OpArg,
10-
PseudoInstruction, PyCodeLocationInfoKind, encode_exception_table, encode_load_attr_arg,
11-
encode_load_super_attr_arg,
10+
PseudoInstruction, PyCodeLocationInfoKind, encode_exception_table,
1211
},
1312
varint::{write_signed_varint, write_varint},
1413
};
@@ -207,62 +206,16 @@ impl CodeInfo {
207206
.filter(|b| b.next != BlockIdx::NULL || !b.instructions.is_empty())
208207
{
209208
for info in &mut block.instructions {
210-
// Special case for:
211-
// - `Instruction::LoadAttr`
212-
// - `Instruction::LoadSuperAttr`
213-
214-
if let Some(instr) = info.instr.real() {
215-
match instr {
216-
// LOAD_ATTR → encode with method flag=0
217-
Instruction::LoadAttr { idx } => {
218-
let encoded = encode_load_attr_arg(idx.get(info.arg), false);
219-
info.arg = OpArg(encoded);
220-
info.instr = Instruction::LoadAttr { idx: Arg::marker() }.into();
221-
}
222-
// LOAD_SUPER_ATTR → encode with flags=0b10 (method=0, class=1)
223-
Instruction::LoadSuperAttr { arg: idx } => {
224-
let encoded =
225-
encode_load_super_attr_arg(idx.get(info.arg), false, true);
226-
info.arg = OpArg(encoded);
227-
info.instr = Instruction::LoadSuperAttr { arg: Arg::marker() }.into();
228-
}
229-
_ => {}
230-
}
231-
209+
// Real instructions are already encoded by compile.rs
210+
let Some(instr) = info.instr.pseudo() else {
232211
continue;
233-
}
234-
235-
let instr = info.instr.expect_pseudo();
212+
};
236213

237214
match instr {
238-
// LOAD_ATTR_METHOD pseudo → LOAD_ATTR (with method flag=1)
239-
PseudoInstruction::LoadAttrMethod { idx } => {
240-
let encoded = encode_load_attr_arg(idx.get(info.arg), true);
241-
info.arg = OpArg(encoded);
242-
info.instr = Instruction::LoadAttr { idx: Arg::marker() }.into();
243-
}
244215
// POP_BLOCK pseudo → NOP
245216
PseudoInstruction::PopBlock => {
246217
info.instr = Instruction::Nop.into();
247218
}
248-
// LOAD_SUPER_METHOD pseudo → LOAD_SUPER_ATTR (flags=0b11: method=1, class=1)
249-
PseudoInstruction::LoadSuperMethod { idx } => {
250-
let encoded = encode_load_super_attr_arg(idx.get(info.arg), true, true);
251-
info.arg = OpArg(encoded);
252-
info.instr = Instruction::LoadSuperAttr { arg: Arg::marker() }.into();
253-
}
254-
// LOAD_ZERO_SUPER_ATTR pseudo → LOAD_SUPER_ATTR (flags=0b00: method=0, class=0)
255-
PseudoInstruction::LoadZeroSuperAttr { idx } => {
256-
let encoded = encode_load_super_attr_arg(idx.get(info.arg), false, false);
257-
info.arg = OpArg(encoded);
258-
info.instr = Instruction::LoadSuperAttr { arg: Arg::marker() }.into();
259-
}
260-
// LOAD_ZERO_SUPER_METHOD pseudo → LOAD_SUPER_ATTR (flags=0b01: method=1, class=0)
261-
PseudoInstruction::LoadZeroSuperMethod { idx } => {
262-
let encoded = encode_load_super_attr_arg(idx.get(info.arg), true, false);
263-
info.arg = OpArg(encoded);
264-
info.instr = Instruction::LoadSuperAttr { arg: Arg::marker() }.into();
265-
}
266219
// LOAD_CLOSURE pseudo → LOAD_FAST (with varnames offset)
267220
PseudoInstruction::LoadClosure(idx) => {
268221
let varnames_len = varname_cache.len() as u32;

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

Lines changed: 13 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -474,7 +474,13 @@ impl InstructionMetadata for Instruction {
474474
Self::LoadFromDictOrDeref(_) => 1,
475475
Self::StoreSubscr => -3,
476476
Self::DeleteSubscr => -2,
477-
Self::LoadAttr { .. } => 0,
477+
Self::LoadAttr { idx } => {
478+
// Stack effect depends on method flag in encoded oparg
479+
// method=false: pop obj, push attr → effect = 0
480+
// method=true: pop obj, push (method, self_or_null) → effect = +1
481+
let (_, is_method) = decode_load_attr_arg(idx.get(arg));
482+
if is_method { 1 } else { 0 }
483+
}
478484
Self::StoreAttr { .. } => -2,
479485
Self::DeleteAttr { .. } => -1,
480486
Self::LoadCommonConstant { .. } => 1,
@@ -923,47 +929,22 @@ impl InstructionMetadata for Instruction {
923929

924930
/// Instructions used by the compiler. They are not executed by the VM.
925931
///
926-
/// CPython 3.14.2 aligned (256-266), RustPython-specific variants start at 267.
932+
/// CPython 3.14.2 aligned (256-266).
927933
#[derive(Clone, Copy, Debug)]
928934
#[repr(u16)]
929935
pub enum PseudoInstruction {
930936
// CPython 3.14.2 pseudo instructions (256-266)
931937
AnnotationsPlaceholder = 256,
932-
Jump {
933-
target: Arg<Label>,
934-
} = 257,
935-
JumpIfFalse {
936-
target: Arg<Label>,
937-
} = 258,
938-
JumpIfTrue {
939-
target: Arg<Label>,
940-
} = 259,
941-
JumpNoInterrupt {
942-
target: Arg<Label>,
943-
} = 260,
938+
Jump { target: Arg<Label> } = 257,
939+
JumpIfFalse { target: Arg<Label> } = 258,
940+
JumpIfTrue { target: Arg<Label> } = 259,
941+
JumpNoInterrupt { target: Arg<Label> } = 260,
944942
LoadClosure(Arg<NameIdx>) = 261,
945943
PopBlock = 262,
946944
SetupCleanup = 263,
947945
SetupFinally = 264,
948946
SetupWith = 265,
949947
StoreFastMaybeNull(Arg<NameIdx>) = 266,
950-
951-
// RustPython-specific pseudo instructions (267+)
952-
LoadAttrMethod {
953-
idx: Arg<NameIdx>,
954-
} = 267,
955-
// "Zero" variants are for 0-arg super() calls (has_class=false).
956-
// Non-"Zero" variants are for 2-arg super(cls, self) calls (has_class=true).
957-
/// 2-arg super(cls, self).method() - has_class=true, load_method=true
958-
LoadSuperMethod {
959-
idx: Arg<NameIdx>,
960-
} = 268,
961-
LoadZeroSuperAttr {
962-
idx: Arg<NameIdx>,
963-
} = 269,
964-
LoadZeroSuperMethod {
965-
idx: Arg<NameIdx>,
966-
} = 270,
967948
}
968949

969950
const _: () = assert!(mem::size_of::<PseudoInstruction>() == 2);
@@ -982,7 +963,7 @@ impl TryFrom<u16> for PseudoInstruction {
982963
#[inline]
983964
fn try_from(value: u16) -> Result<Self, MarshalError> {
984965
let start = u16::from(Self::AnnotationsPlaceholder);
985-
let end = u16::from(Self::LoadZeroSuperMethod { idx: Arg::marker() });
966+
let end = u16::from(Self::StoreFastMaybeNull(Arg::marker()));
986967

987968
if (start..=end).contains(&value) {
988969
Ok(unsafe { mem::transmute::<u16, Self>(value) })
@@ -1024,10 +1005,6 @@ impl InstructionMetadata for PseudoInstruction {
10241005
Self::SetupFinally => 0,
10251006
Self::SetupWith => 0,
10261007
Self::StoreFastMaybeNull(_) => -1,
1027-
Self::LoadAttrMethod { .. } => 1, // pop obj, push method + self_or_null
1028-
Self::LoadSuperMethod { .. } => -3 + 2, // pop 3, push [method, self_or_null]
1029-
Self::LoadZeroSuperAttr { .. } => -3 + 1, // pop 3, push [attr]
1030-
Self::LoadZeroSuperMethod { .. } => -3 + 2, // pop 3, push [method, self_or_null]
10311008
}
10321009
}
10331010

crates/stdlib/src/_opcode.rs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ mod _opcode {
9292
| Instruction::StoreAttr { .. }
9393
| Instruction::StoreGlobal(_)
9494
| Instruction::StoreName(_)
95-
) | AnyInstruction::Pseudo(PseudoInstruction::LoadAttrMethod { .. }))
95+
))
9696
)
9797
}
9898

@@ -148,8 +148,11 @@ mod _opcode {
148148
}
149149
}
150150

151-
#[pyattr]
151+
// prepare specialization
152+
#[allow(dead_code)]
152153
const ENABLE_SPECIALIZATION: i8 = 1;
154+
#[allow(dead_code)]
155+
const ENABLE_SPECIALIZATION_FT: i8 = 1;
153156

154157
#[derive(FromArgs)]
155158
struct StackEffectArgs {
@@ -303,6 +306,7 @@ mod _opcode {
303306
("NB_INPLACE_SUBTRACT", "-="),
304307
("NB_INPLACE_TRUE_DIVIDE", "/="),
305308
("NB_INPLACE_XOR", "^="),
309+
("NB_SUBSCR", "[]"),
306310
]
307311
.into_iter()
308312
.map(|(a, b)| {
@@ -314,8 +318,19 @@ mod _opcode {
314318
}
315319

316320
#[pyfunction]
317-
fn get_executor(_code: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyObjectRef> {
318-
// TODO
321+
fn get_special_method_names(vm: &VirtualMachine) -> Vec<PyObjectRef> {
322+
["__enter__", "__exit__", "__aenter__", "__aexit__"]
323+
.into_iter()
324+
.map(|x| vm.ctx.new_str(x).into())
325+
.collect()
326+
}
327+
328+
#[pyfunction]
329+
fn get_executor(
330+
_code: PyObjectRef,
331+
_offset: i32,
332+
vm: &VirtualMachine,
333+
) -> PyResult<PyObjectRef> {
319334
Ok(vm.ctx.none())
320335
}
321336

0 commit comments

Comments
 (0)