mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
align psuedo ops to 3.14.2
This commit is contained in:
4
Lib/_opcode_metadata.py
vendored
4
Lib/_opcode_metadata.py
vendored
@@ -245,10 +245,6 @@ opmap = {
|
||||
'SETUP_FINALLY': 264,
|
||||
'SETUP_WITH': 265,
|
||||
'STORE_FAST_MAYBE_NULL': 266,
|
||||
'LOAD_ATTR_METHOD': 267,
|
||||
'LOAD_SUPER_METHOD': 268,
|
||||
'LOAD_ZERO_SUPER_ATTR': 269,
|
||||
'LOAD_ZERO_SUPER_METHOD': 270,
|
||||
}
|
||||
|
||||
# CPython 3.13 compatible: opcodes < 44 have no argument
|
||||
|
||||
@@ -31,6 +31,7 @@ use rustpython_compiler_core::{
|
||||
self, AnyInstruction, Arg as OpArgMarker, BinaryOperator, BuildSliceArgCount, CodeObject,
|
||||
ComparisonOperator, ConstantData, ConvertValueOparg, Instruction, IntrinsicFunction1,
|
||||
Invert, OpArg, OpArgType, PseudoInstruction, SpecialMethod, UnpackExArgs,
|
||||
encode_load_attr_arg, encode_load_super_attr_arg,
|
||||
},
|
||||
};
|
||||
use rustpython_wtf8::Wtf8Buf;
|
||||
@@ -2108,7 +2109,7 @@ impl Compiler {
|
||||
if let Some(alias) = &name.asname {
|
||||
for part in name.name.split('.').skip(1) {
|
||||
let idx = self.name(part);
|
||||
emit!(self, Instruction::LoadAttr { idx });
|
||||
self.emit_load_attr(idx);
|
||||
}
|
||||
self.store_name(alias.as_str())?
|
||||
} else {
|
||||
@@ -6280,7 +6281,7 @@ impl Compiler {
|
||||
self.compile_expression(value)?;
|
||||
emit!(self, Instruction::Copy { index: 1_u32 });
|
||||
let idx = self.name(attr);
|
||||
emit!(self, Instruction::LoadAttr { idx });
|
||||
self.emit_load_attr(idx);
|
||||
AugAssignKind::Attr { idx }
|
||||
}
|
||||
_ => {
|
||||
@@ -6615,19 +6616,17 @@ impl Compiler {
|
||||
let idx = self.name(attr.as_str());
|
||||
match super_type {
|
||||
SuperCallType::TwoArg { .. } => {
|
||||
// LoadSuperAttr (pseudo) - will be converted to real LoadSuperAttr
|
||||
// with flags=0b10 (has_class=true, load_method=false) in ir.rs
|
||||
emit!(self, Instruction::LoadSuperAttr { arg: idx });
|
||||
self.emit_load_super_attr(idx);
|
||||
}
|
||||
SuperCallType::ZeroArg => {
|
||||
emit!(self, PseudoInstruction::LoadZeroSuperAttr { idx });
|
||||
self.emit_load_zero_super_attr(idx);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Normal attribute access
|
||||
self.compile_expression(value)?;
|
||||
let idx = self.name(attr.as_str());
|
||||
emit!(self, Instruction::LoadAttr { idx });
|
||||
self.emit_load_attr(idx);
|
||||
}
|
||||
}
|
||||
ast::Expr::Compare(ast::ExprCompare {
|
||||
@@ -7070,19 +7069,19 @@ impl Compiler {
|
||||
let idx = self.name(attr.as_str());
|
||||
match super_type {
|
||||
SuperCallType::TwoArg { .. } => {
|
||||
emit!(self, PseudoInstruction::LoadSuperMethod { idx });
|
||||
self.emit_load_super_method(idx);
|
||||
}
|
||||
SuperCallType::ZeroArg => {
|
||||
emit!(self, PseudoInstruction::LoadZeroSuperMethod { idx });
|
||||
self.emit_load_zero_super_method(idx);
|
||||
}
|
||||
}
|
||||
self.codegen_call_helper(0, args)?;
|
||||
} else {
|
||||
// Normal method call: compile object, then LOAD_ATTR_METHOD
|
||||
// LOAD_ATTR_METHOD pushes [method, self_or_null] on stack
|
||||
// Normal method call: compile object, then LOAD_ATTR with method flag
|
||||
// LOAD_ATTR(method=1) pushes [method, self_or_null] on stack
|
||||
self.compile_expression(value)?;
|
||||
let idx = self.name(attr.as_str());
|
||||
emit!(self, PseudoInstruction::LoadAttrMethod { idx });
|
||||
self.emit_load_attr_method(idx);
|
||||
self.codegen_call_helper(0, args)?;
|
||||
}
|
||||
} else {
|
||||
@@ -7782,6 +7781,48 @@ impl Compiler {
|
||||
emit!(self, Instruction::ReturnValue)
|
||||
}
|
||||
|
||||
/// Emit LOAD_ATTR for attribute access (method=false).
|
||||
/// Encodes: (name_idx << 1) | 0
|
||||
fn emit_load_attr(&mut self, name_idx: u32) {
|
||||
let encoded = encode_load_attr_arg(name_idx, false);
|
||||
self.emit_arg(encoded, |arg| Instruction::LoadAttr { idx: arg })
|
||||
}
|
||||
|
||||
/// Emit LOAD_ATTR with method flag set (for method calls).
|
||||
/// Encodes: (name_idx << 1) | 1
|
||||
fn emit_load_attr_method(&mut self, name_idx: u32) {
|
||||
let encoded = encode_load_attr_arg(name_idx, true);
|
||||
self.emit_arg(encoded, |arg| Instruction::LoadAttr { idx: arg })
|
||||
}
|
||||
|
||||
/// Emit LOAD_SUPER_ATTR for 2-arg super().attr access.
|
||||
/// Encodes: (name_idx << 2) | 0b10 (method=0, class=1)
|
||||
fn emit_load_super_attr(&mut self, name_idx: u32) {
|
||||
let encoded = encode_load_super_attr_arg(name_idx, false, true);
|
||||
self.emit_arg(encoded, |arg| Instruction::LoadSuperAttr { arg })
|
||||
}
|
||||
|
||||
/// Emit LOAD_SUPER_ATTR for 2-arg super().method() call.
|
||||
/// Encodes: (name_idx << 2) | 0b11 (method=1, class=1)
|
||||
fn emit_load_super_method(&mut self, name_idx: u32) {
|
||||
let encoded = encode_load_super_attr_arg(name_idx, true, true);
|
||||
self.emit_arg(encoded, |arg| Instruction::LoadSuperAttr { arg })
|
||||
}
|
||||
|
||||
/// Emit LOAD_SUPER_ATTR for 0-arg super().attr access.
|
||||
/// Encodes: (name_idx << 2) | 0b00 (method=0, class=0)
|
||||
fn emit_load_zero_super_attr(&mut self, name_idx: u32) {
|
||||
let encoded = encode_load_super_attr_arg(name_idx, false, false);
|
||||
self.emit_arg(encoded, |arg| Instruction::LoadSuperAttr { arg })
|
||||
}
|
||||
|
||||
/// Emit LOAD_SUPER_ATTR for 0-arg super().method() call.
|
||||
/// Encodes: (name_idx << 2) | 0b01 (method=1, class=0)
|
||||
fn emit_load_zero_super_method(&mut self, name_idx: u32) {
|
||||
let encoded = encode_load_super_attr_arg(name_idx, true, false);
|
||||
self.emit_arg(encoded, |arg| Instruction::LoadSuperAttr { arg })
|
||||
}
|
||||
|
||||
fn emit_return_value(&mut self) {
|
||||
emit!(self, Instruction::ReturnValue)
|
||||
}
|
||||
|
||||
@@ -7,8 +7,7 @@ use rustpython_compiler_core::{
|
||||
bytecode::{
|
||||
AnyInstruction, Arg, CodeFlags, CodeObject, CodeUnit, CodeUnits, ConstantData,
|
||||
ExceptionTableEntry, InstrDisplayContext, Instruction, InstructionMetadata, Label, OpArg,
|
||||
PseudoInstruction, PyCodeLocationInfoKind, encode_exception_table, encode_load_attr_arg,
|
||||
encode_load_super_attr_arg,
|
||||
PseudoInstruction, PyCodeLocationInfoKind, encode_exception_table,
|
||||
},
|
||||
varint::{write_signed_varint, write_varint},
|
||||
};
|
||||
@@ -207,62 +206,16 @@ impl CodeInfo {
|
||||
.filter(|b| b.next != BlockIdx::NULL || !b.instructions.is_empty())
|
||||
{
|
||||
for info in &mut block.instructions {
|
||||
// Special case for:
|
||||
// - `Instruction::LoadAttr`
|
||||
// - `Instruction::LoadSuperAttr`
|
||||
|
||||
if let Some(instr) = info.instr.real() {
|
||||
match instr {
|
||||
// LOAD_ATTR → encode with method flag=0
|
||||
Instruction::LoadAttr { idx } => {
|
||||
let encoded = encode_load_attr_arg(idx.get(info.arg), false);
|
||||
info.arg = OpArg(encoded);
|
||||
info.instr = Instruction::LoadAttr { idx: Arg::marker() }.into();
|
||||
}
|
||||
// LOAD_SUPER_ATTR → encode with flags=0b10 (method=0, class=1)
|
||||
Instruction::LoadSuperAttr { arg: idx } => {
|
||||
let encoded =
|
||||
encode_load_super_attr_arg(idx.get(info.arg), false, true);
|
||||
info.arg = OpArg(encoded);
|
||||
info.instr = Instruction::LoadSuperAttr { arg: Arg::marker() }.into();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// Real instructions are already encoded by compile.rs
|
||||
let Some(instr) = info.instr.pseudo() else {
|
||||
continue;
|
||||
}
|
||||
|
||||
let instr = info.instr.expect_pseudo();
|
||||
};
|
||||
|
||||
match instr {
|
||||
// LOAD_ATTR_METHOD pseudo → LOAD_ATTR (with method flag=1)
|
||||
PseudoInstruction::LoadAttrMethod { idx } => {
|
||||
let encoded = encode_load_attr_arg(idx.get(info.arg), true);
|
||||
info.arg = OpArg(encoded);
|
||||
info.instr = Instruction::LoadAttr { idx: Arg::marker() }.into();
|
||||
}
|
||||
// POP_BLOCK pseudo → NOP
|
||||
PseudoInstruction::PopBlock => {
|
||||
info.instr = Instruction::Nop.into();
|
||||
}
|
||||
// LOAD_SUPER_METHOD pseudo → LOAD_SUPER_ATTR (flags=0b11: method=1, class=1)
|
||||
PseudoInstruction::LoadSuperMethod { idx } => {
|
||||
let encoded = encode_load_super_attr_arg(idx.get(info.arg), true, true);
|
||||
info.arg = OpArg(encoded);
|
||||
info.instr = Instruction::LoadSuperAttr { arg: Arg::marker() }.into();
|
||||
}
|
||||
// LOAD_ZERO_SUPER_ATTR pseudo → LOAD_SUPER_ATTR (flags=0b00: method=0, class=0)
|
||||
PseudoInstruction::LoadZeroSuperAttr { idx } => {
|
||||
let encoded = encode_load_super_attr_arg(idx.get(info.arg), false, false);
|
||||
info.arg = OpArg(encoded);
|
||||
info.instr = Instruction::LoadSuperAttr { arg: Arg::marker() }.into();
|
||||
}
|
||||
// LOAD_ZERO_SUPER_METHOD pseudo → LOAD_SUPER_ATTR (flags=0b01: method=1, class=0)
|
||||
PseudoInstruction::LoadZeroSuperMethod { idx } => {
|
||||
let encoded = encode_load_super_attr_arg(idx.get(info.arg), true, false);
|
||||
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;
|
||||
|
||||
@@ -474,7 +474,13 @@ impl InstructionMetadata for Instruction {
|
||||
Self::LoadFromDictOrDeref(_) => 1,
|
||||
Self::StoreSubscr => -3,
|
||||
Self::DeleteSubscr => -2,
|
||||
Self::LoadAttr { .. } => 0,
|
||||
Self::LoadAttr { idx } => {
|
||||
// Stack effect depends on method flag in encoded oparg
|
||||
// method=false: pop obj, push attr → effect = 0
|
||||
// method=true: pop obj, push (method, self_or_null) → effect = +1
|
||||
let (_, is_method) = decode_load_attr_arg(idx.get(arg));
|
||||
if is_method { 1 } else { 0 }
|
||||
}
|
||||
Self::StoreAttr { .. } => -2,
|
||||
Self::DeleteAttr { .. } => -1,
|
||||
Self::LoadCommonConstant { .. } => 1,
|
||||
@@ -923,47 +929,22 @@ impl InstructionMetadata for Instruction {
|
||||
|
||||
/// Instructions used by the compiler. They are not executed by the VM.
|
||||
///
|
||||
/// CPython 3.14.2 aligned (256-266), RustPython-specific variants start at 267.
|
||||
/// CPython 3.14.2 aligned (256-266).
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[repr(u16)]
|
||||
pub enum PseudoInstruction {
|
||||
// CPython 3.14.2 pseudo instructions (256-266)
|
||||
AnnotationsPlaceholder = 256,
|
||||
Jump {
|
||||
target: Arg<Label>,
|
||||
} = 257,
|
||||
JumpIfFalse {
|
||||
target: Arg<Label>,
|
||||
} = 258,
|
||||
JumpIfTrue {
|
||||
target: Arg<Label>,
|
||||
} = 259,
|
||||
JumpNoInterrupt {
|
||||
target: Arg<Label>,
|
||||
} = 260,
|
||||
Jump { target: Arg<Label> } = 257,
|
||||
JumpIfFalse { target: Arg<Label> } = 258,
|
||||
JumpIfTrue { target: Arg<Label> } = 259,
|
||||
JumpNoInterrupt { target: Arg<Label> } = 260,
|
||||
LoadClosure(Arg<NameIdx>) = 261,
|
||||
PopBlock = 262,
|
||||
SetupCleanup = 263,
|
||||
SetupFinally = 264,
|
||||
SetupWith = 265,
|
||||
StoreFastMaybeNull(Arg<NameIdx>) = 266,
|
||||
|
||||
// RustPython-specific pseudo instructions (267+)
|
||||
LoadAttrMethod {
|
||||
idx: Arg<NameIdx>,
|
||||
} = 267,
|
||||
// "Zero" variants are for 0-arg super() calls (has_class=false).
|
||||
// Non-"Zero" variants are for 2-arg super(cls, self) calls (has_class=true).
|
||||
/// 2-arg super(cls, self).method() - has_class=true, load_method=true
|
||||
LoadSuperMethod {
|
||||
idx: Arg<NameIdx>,
|
||||
} = 268,
|
||||
LoadZeroSuperAttr {
|
||||
idx: Arg<NameIdx>,
|
||||
} = 269,
|
||||
LoadZeroSuperMethod {
|
||||
idx: Arg<NameIdx>,
|
||||
} = 270,
|
||||
}
|
||||
|
||||
const _: () = assert!(mem::size_of::<PseudoInstruction>() == 2);
|
||||
@@ -982,7 +963,7 @@ impl TryFrom<u16> for PseudoInstruction {
|
||||
#[inline]
|
||||
fn try_from(value: u16) -> Result<Self, MarshalError> {
|
||||
let start = u16::from(Self::AnnotationsPlaceholder);
|
||||
let end = u16::from(Self::LoadZeroSuperMethod { idx: Arg::marker() });
|
||||
let end = u16::from(Self::StoreFastMaybeNull(Arg::marker()));
|
||||
|
||||
if (start..=end).contains(&value) {
|
||||
Ok(unsafe { mem::transmute::<u16, Self>(value) })
|
||||
@@ -1024,10 +1005,6 @@ impl InstructionMetadata for PseudoInstruction {
|
||||
Self::SetupFinally => 0,
|
||||
Self::SetupWith => 0,
|
||||
Self::StoreFastMaybeNull(_) => -1,
|
||||
Self::LoadAttrMethod { .. } => 1, // pop obj, push method + self_or_null
|
||||
Self::LoadSuperMethod { .. } => -3 + 2, // pop 3, push [method, self_or_null]
|
||||
Self::LoadZeroSuperAttr { .. } => -3 + 1, // pop 3, push [attr]
|
||||
Self::LoadZeroSuperMethod { .. } => -3 + 2, // pop 3, push [method, self_or_null]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ mod _opcode {
|
||||
| Instruction::StoreAttr { .. }
|
||||
| Instruction::StoreGlobal(_)
|
||||
| Instruction::StoreName(_)
|
||||
) | AnyInstruction::Pseudo(PseudoInstruction::LoadAttrMethod { .. }))
|
||||
))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -148,8 +148,11 @@ mod _opcode {
|
||||
}
|
||||
}
|
||||
|
||||
// prepare specialization
|
||||
#[pyattr]
|
||||
const ENABLE_SPECIALIZATION: i8 = 1;
|
||||
#[allow(dead_code)]
|
||||
const ENABLE_SPECIALIZATION_FT: i8 = 1;
|
||||
|
||||
#[derive(FromArgs)]
|
||||
struct StackEffectArgs {
|
||||
@@ -303,6 +306,7 @@ mod _opcode {
|
||||
("NB_INPLACE_SUBTRACT", "-="),
|
||||
("NB_INPLACE_TRUE_DIVIDE", "/="),
|
||||
("NB_INPLACE_XOR", "^="),
|
||||
("NB_SUBSCR", "[]"),
|
||||
]
|
||||
.into_iter()
|
||||
.map(|(a, b)| {
|
||||
@@ -314,8 +318,19 @@ mod _opcode {
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn get_executor(_code: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyObjectRef> {
|
||||
// TODO
|
||||
fn get_special_method_names(vm: &VirtualMachine) -> Vec<PyObjectRef> {
|
||||
["__enter__", "__exit__", "__aenter__", "__aexit__"]
|
||||
.into_iter()
|
||||
.map(|x| vm.ctx.new_str(x).into())
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn get_executor(
|
||||
_code: PyObjectRef,
|
||||
_offset: i32,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<PyObjectRef> {
|
||||
Ok(vm.ctx.none())
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user