mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-29 03:04:38 +08:00
Newtype LoadSuperAttr oparg (#7002)
This commit is contained in:
1 parent
d7c259c8c9
commit
5b7db1d2d2
5 files changed
+134
-38
No files matched your search
@@ -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 })
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
Reference in new issue
Block a user