Newtype LoadSuperAttr oparg (#7002)

This commit is contained in:
Shahar Naveh authored and GitHub committed 2026-02-05 21:14:38 +09:00
1 parent d7c259c8c9
commit 5b7db1d2d2
5 files changed
+134 -38

No files matched your search

+22 -6
View File
@@ -30,8 +30,8 @@ use rustpython_compiler_core::{
bytecode::{
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,
Invert, LoadSuperAttr, OpArg, OpArgType, PseudoInstruction, SpecialMethod, UnpackExArgs,
encode_load_attr_arg,
},
};
use rustpython_wtf8::Wtf8Buf;
@@ -7818,28 +7818,44 @@ impl Compiler {
/// 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);
let encoded = LoadSuperAttr::builder()
.name_idx(name_idx)
.is_load_method(false)
.has_class(true)
.build();
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);
let encoded = LoadSuperAttr::builder()
.name_idx(name_idx)
.is_load_method(true)
.has_class(true)
.build();
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);
let encoded = LoadSuperAttr::builder()
.name_idx(name_idx)
.is_load_method(false)
.has_class(false)
.build();
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);
let encoded = LoadSuperAttr::builder()
.name_idx(name_idx)
.is_load_method(true)
.has_class(false)
.build();
self.emit_arg(encoded, |arg| Instruction::LoadSuperAttr { arg })
}
+4 -4
View File
@@ -17,13 +17,13 @@ use rustpython_wtf8::{Wtf8, Wtf8Buf};
pub use crate::bytecode::{
instruction::{
AnyInstruction, Arg, Instruction, InstructionMetadata, PseudoInstruction, StackEffect,
decode_load_attr_arg, decode_load_super_attr_arg, encode_load_attr_arg,
encode_load_super_attr_arg,
decode_load_attr_arg, encode_load_attr_arg,
},
oparg::{
BinaryOperator, BuildSliceArgCount, CommonConstant, ComparisonOperator, ConvertValueOparg,
IntrinsicFunction1, IntrinsicFunction2, Invert, Label, MakeFunctionFlags, NameIdx, OpArg,
OpArgByte, OpArgState, OpArgType, RaiseKind, ResumeType, SpecialMethod, UnpackExArgs,
IntrinsicFunction1, IntrinsicFunction2, Invert, Label, LoadSuperAttr, MakeFunctionFlags,
NameIdx, OpArg, OpArgByte, OpArgState, OpArgType, RaiseKind, ResumeType, SpecialMethod,
UnpackExArgs,
},
};
@@ -6,8 +6,8 @@ use crate::{
oparg::{
BinaryOperator, BuildSliceArgCount, CommonConstant, ComparisonOperator,
ConvertValueOparg, IntrinsicFunction1, IntrinsicFunction2, Invert, Label,
MakeFunctionFlags, NameIdx, OpArg, OpArgByte, OpArgType, RaiseKind, SpecialMethod,
UnpackExArgs,
LoadSuperAttr, MakeFunctionFlags, NameIdx, OpArg, OpArgByte, OpArgType, RaiseKind,
SpecialMethod, UnpackExArgs,
},
},
marshal::MarshalError,
@@ -198,7 +198,7 @@ pub enum Instruction {
method: Arg<SpecialMethod>,
} = 95,
LoadSuperAttr {
arg: Arg<u32>,
arg: Arg<LoadSuperAttr>,
} = 96,
MakeCell(Arg<NameIdx>) = 97,
MapAdd {
@@ -862,13 +862,15 @@ impl InstructionMetadata for Instruction {
Self::LoadName(idx) => w!(LOAD_NAME, name = idx),
Self::LoadSpecial { method } => w!(LOAD_SPECIAL, method),
Self::LoadSuperAttr { arg: idx } => {
let encoded = idx.get(arg);
let (name_idx, load_method, has_class) = decode_load_super_attr_arg(encoded);
let attr_name = name(name_idx);
let oparg = idx.get(arg);
write!(
f,
"{:pad$}({}, {}, method={}, class={})",
"LOAD_SUPER_ATTR", encoded, attr_name, load_method, has_class
"LOAD_SUPER_ATTR",
u32::from(oparg),
name(oparg.name_idx()),
oparg.is_load_method(),
oparg.has_class()
)
}
Self::MakeFunction => w!(MAKE_FUNCTION),
@@ -1304,18 +1306,3 @@ pub const fn decode_load_attr_arg(oparg: u32) -> (u32, bool) {
let name_idx = oparg >> 1;
(name_idx, is_method)
}
/// Encode LOAD_SUPER_ATTR oparg: bit 0 = load_method, bit 1 = has_class, bits 2+ = name index.
#[inline]
pub const fn encode_load_super_attr_arg(name_idx: u32, load_method: bool, has_class: bool) -> u32 {
(name_idx << 2) | ((has_class as u32) << 1) | (load_method as u32)
}
/// Decode LOAD_SUPER_ATTR oparg: returns (name_idx, load_method, has_class).
#[inline]
pub const fn decode_load_super_attr_arg(oparg: u32) -> (u32, bool, bool) {
let load_method = (oparg & 1) == 1;
let has_class = (oparg & 2) == 2;
let name_idx = oparg >> 2;
(name_idx, load_method, has_class)
}
@@ -655,3 +655,97 @@ impl fmt::Display for UnpackExArgs {
write!(f, "before: {}, after: {}", self.before, self.after)
}
}
#[derive(Clone, Copy)]
pub struct LoadSuperAttr(u32);
impl LoadSuperAttr {
#[must_use]
pub const fn new(value: u32) -> Self {
Self(value)
}
#[must_use]
pub fn builder() -> LoadSuperAttrBuilder {
LoadSuperAttrBuilder::default()
}
#[must_use]
pub const fn name_idx(self) -> u32 {
self.0 >> 2
}
#[must_use]
pub const fn is_load_method(self) -> bool {
(self.0 & 1) == 1
}
#[must_use]
pub const fn has_class(self) -> bool {
(self.0 & 2) == 2
}
}
impl OpArgType for LoadSuperAttr {
#[inline(always)]
fn from_op_arg(x: u32) -> Result<Self, MarshalError> {
Ok(x.into())
}
#[inline(always)]
fn to_op_arg(self) -> u32 {
self.into()
}
}
impl From<u32> for LoadSuperAttr {
fn from(value: u32) -> Self {
Self::new(value)
}
}
impl From<LoadSuperAttr> for u32 {
fn from(value: LoadSuperAttr) -> Self {
value.0
}
}
#[derive(Clone, Copy, Default)]
pub struct LoadSuperAttrBuilder {
name_idx: u32,
is_load_method: bool,
has_class: bool,
}
impl LoadSuperAttrBuilder {
#[must_use]
pub const fn build(self) -> LoadSuperAttr {
let value =
(self.name_idx << 2) | ((self.has_class as u32) << 1) | (self.is_load_method as u32);
LoadSuperAttr::new(value)
}
#[must_use]
pub const fn name_idx(mut self, value: u32) -> Self {
self.name_idx = value;
self
}
#[must_use]
pub const fn is_load_method(mut self, value: bool) -> Self {
self.is_load_method = value;
self
}
#[must_use]
pub const fn has_class(mut self, value: bool) -> Self {
self.has_class = value;
self
}
}
impl From<LoadSuperAttrBuilder> for LoadSuperAttr {
fn from(builder: LoadSuperAttrBuilder) -> Self {
builder.build()
}
}
+5 -6
View File
@@ -10,7 +10,7 @@ use crate::{
function::{PyCell, PyCellRef, PyFunction},
tuple::{PyTuple, PyTupleRef},
},
bytecode::{self, Instruction},
bytecode::{self, Instruction, LoadSuperAttr},
convert::{IntoObject, ToPyResult},
coroutine::Coro,
exceptions::ExceptionCtor,
@@ -2859,9 +2859,8 @@ impl ExecutingFrame<'_> {
Ok(None)
}
fn load_super_attr(&mut self, vm: &VirtualMachine, oparg: u32) -> FrameResult {
let (name_idx, load_method, has_class) = bytecode::decode_load_super_attr_arg(oparg);
let attr_name = self.code.names[name_idx as usize];
fn load_super_attr(&mut self, vm: &VirtualMachine, oparg: LoadSuperAttr) -> FrameResult {
let attr_name = self.code.names[oparg.name_idx() as usize];
// Stack layout (bottom to top): [super, class, self]
// Pop in LIFO order: self, class, super
@@ -2871,13 +2870,13 @@ impl ExecutingFrame<'_> {
// Create super object - pass args based on has_class flag
// When super is shadowed, has_class=false means call with 0 args
let super_obj = if has_class {
let super_obj = if oparg.has_class() {
global_super.call((class.clone(), self_obj.clone()), vm)?
} else {
global_super.call((), vm)?
};
if load_method {
if oparg.is_load_method() {
// Method load: push [method, self_or_null]
let method = PyMethod::get(super_obj, attr_name, vm)?;
match method {