PyMethod is internal concept of VirtualMachine

This commit is contained in:
Jeong Yunwon
2022-04-23 09:23:53 +09:00
parent 8d75d18597
commit 082f4bdc59
7 changed files with 152 additions and 157 deletions

View File

@@ -16,8 +16,8 @@ use crate::{
scope::Scope,
stdlib::builtins,
types::PyComparisonOp,
AsObject, PyMethod, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject,
VirtualMachine,
vm::PyMethod,
AsObject, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject, VirtualMachine,
};
use indexmap::IndexMap;
use itertools::Itertools;

View File

@@ -78,7 +78,7 @@ pub mod vm;
pub use self::convert::{TryFromBorrowedObject, TryFromObject};
// pyobject items
pub use self::object::{AsObject, PyMethod, PyPayload, PyRefExact, PyResult};
pub use self::object::{AsObject, PyPayload, PyRefExact, PyResult};
// pyobjectrc items
pub use self::object::{Py, PyObject, PyObjectRef, PyRef, PyWeakRef};
pub use self::types::PyStructSequence;

View File

@@ -4,10 +4,8 @@ use super::{
};
use crate::common::lock::PyRwLockReadGuard;
use crate::{
builtins::{object, pystr, PyBaseExceptionRef, PyType},
builtins::{PyBaseExceptionRef, PyType},
convert::{ToPyObject, ToPyResult, TryFromObject},
function::IntoFuncArgs,
types::PyTypeFlags,
VirtualMachine,
};
use std::{borrow::Borrow, fmt, ops::Deref};
@@ -276,151 +274,3 @@ where
self.map(|res| T::to_pyobject(res, vm))
}
}
pub trait PyObjectWrap
where
Self: AsObject,
{
fn into_object(self) -> PyObjectRef;
}
impl<T> From<T> for PyObjectRef
where
T: PyObjectWrap,
{
#[inline(always)]
fn from(py_ref: T) -> Self {
py_ref.into_object()
}
}
#[derive(Debug)]
pub enum PyMethod {
Function {
target: PyObjectRef,
func: PyObjectRef,
},
Attribute(PyObjectRef),
}
impl PyMethod {
pub fn get(obj: PyObjectRef, name: pystr::PyStrRef, vm: &VirtualMachine) -> PyResult<Self> {
let cls = obj.class();
let getattro = cls.mro_find_map(|cls| cls.slots.getattro.load()).unwrap();
if getattro as usize != object::PyBaseObject::getattro as usize {
drop(cls);
return obj.get_attr(name, vm).map(Self::Attribute);
}
let mut is_method = false;
let cls_attr = match cls.get_attr(name.as_str()) {
Some(descr) => {
let descr_cls = descr.class();
let descr_get = if descr_cls.slots.flags.has_feature(PyTypeFlags::METHOD_DESCR) {
is_method = true;
None
} else {
let descr_get = descr_cls.mro_find_map(|cls| cls.slots.descr_get.load());
if let Some(descr_get) = descr_get {
if descr_cls
.mro_find_map(|cls| cls.slots.descr_set.load())
.is_some()
{
drop(descr_cls);
let cls = cls.into_owned().into();
return descr_get(descr, Some(obj), Some(cls), vm).map(Self::Attribute);
}
}
descr_get
};
drop(descr_cls);
Some((descr, descr_get))
}
None => None,
};
if let Some(dict) = obj.dict() {
if let Some(attr) = dict.get_item_opt(name.clone(), vm)? {
return Ok(Self::Attribute(attr));
}
}
if let Some((attr, descr_get)) = cls_attr {
match descr_get {
None if is_method => {
drop(cls);
Ok(Self::Function {
target: obj,
func: attr,
})
}
Some(descr_get) => {
let cls = cls.into_owned().into();
descr_get(attr, Some(obj), Some(cls), vm).map(Self::Attribute)
}
None => Ok(Self::Attribute(attr)),
}
} else if let Some(getter) = cls.get_attr("__getattr__") {
drop(cls);
vm.invoke(&getter, (obj, name)).map(Self::Attribute)
} else {
let exc = vm.new_attribute_error(format!(
"'{}' object has no attribute '{}'",
cls.name(),
name
));
vm.set_attribute_error_context(&exc, obj.clone(), name);
Err(exc)
}
}
pub(crate) fn get_special(
obj: PyObjectRef,
name: &str,
vm: &VirtualMachine,
) -> PyResult<Result<Self, PyObjectRef>> {
let obj_cls = obj.class();
let func = match obj_cls.get_attr(name) {
Some(f) => f,
None => {
drop(obj_cls);
return Ok(Err(obj));
}
};
let meth = if func
.class()
.slots
.flags
.has_feature(PyTypeFlags::METHOD_DESCR)
{
drop(obj_cls);
Self::Function { target: obj, func }
} else {
let obj_cls = obj_cls.into_owned().into();
let attr = vm
.call_get_descriptor_specific(func, Some(obj), Some(obj_cls))
.unwrap_or_else(Ok)?;
Self::Attribute(attr)
};
Ok(Ok(meth))
}
pub fn invoke(self, args: impl IntoFuncArgs, vm: &VirtualMachine) -> PyResult {
let (func, args) = match self {
PyMethod::Function { target, func } => (func, args.into_method_args(target, vm)),
PyMethod::Attribute(func) => (func, args.into_args(vm)),
};
vm.invoke(&func, args)
}
pub fn invoke_ref(&self, args: impl IntoFuncArgs, vm: &VirtualMachine) -> PyResult {
let (func, args) = match self {
PyMethod::Function { target, func } => {
(func, args.into_method_args(target.clone(), vm))
}
PyMethod::Attribute(func) => (func, args.into_args(vm)),
};
vm.invoke(func, args)
}
}

142
vm/src/vm/method.rs Normal file
View File

@@ -0,0 +1,142 @@
//! This module will be replaced once #3100 is done
//! Do not expose this type to outside of this crate
use super::VirtualMachine;
use crate::{
builtins::{PyBaseObject, PyStrRef},
function::IntoFuncArgs,
object::{AsObject, PyObjectRef, PyResult},
types::PyTypeFlags,
};
#[derive(Debug)]
pub enum PyMethod {
Function {
target: PyObjectRef,
func: PyObjectRef,
},
Attribute(PyObjectRef),
}
impl PyMethod {
pub fn get(obj: PyObjectRef, name: PyStrRef, vm: &VirtualMachine) -> PyResult<Self> {
let cls = obj.class();
let getattro = cls.mro_find_map(|cls| cls.slots.getattro.load()).unwrap();
if getattro as usize != PyBaseObject::getattro as usize {
drop(cls);
return obj.get_attr(name, vm).map(Self::Attribute);
}
let mut is_method = false;
let cls_attr = match cls.get_attr(name.as_str()) {
Some(descr) => {
let descr_cls = descr.class();
let descr_get = if descr_cls.slots.flags.has_feature(PyTypeFlags::METHOD_DESCR) {
is_method = true;
None
} else {
let descr_get = descr_cls.mro_find_map(|cls| cls.slots.descr_get.load());
if let Some(descr_get) = descr_get {
if descr_cls
.mro_find_map(|cls| cls.slots.descr_set.load())
.is_some()
{
drop(descr_cls);
let cls = cls.into_owned().into();
return descr_get(descr, Some(obj), Some(cls), vm).map(Self::Attribute);
}
}
descr_get
};
drop(descr_cls);
Some((descr, descr_get))
}
None => None,
};
if let Some(dict) = obj.dict() {
if let Some(attr) = dict.get_item_opt(name.clone(), vm)? {
return Ok(Self::Attribute(attr));
}
}
if let Some((attr, descr_get)) = cls_attr {
match descr_get {
None if is_method => {
drop(cls);
Ok(Self::Function {
target: obj,
func: attr,
})
}
Some(descr_get) => {
let cls = cls.into_owned().into();
descr_get(attr, Some(obj), Some(cls), vm).map(Self::Attribute)
}
None => Ok(Self::Attribute(attr)),
}
} else if let Some(getter) = cls.get_attr("__getattr__") {
drop(cls);
vm.invoke(&getter, (obj, name)).map(Self::Attribute)
} else {
let exc = vm.new_attribute_error(format!(
"'{}' object has no attribute '{}'",
cls.name(),
name
));
vm.set_attribute_error_context(&exc, obj.clone(), name);
Err(exc)
}
}
pub(crate) fn get_special(
obj: PyObjectRef,
name: &str,
vm: &VirtualMachine,
) -> PyResult<Result<Self, PyObjectRef>> {
let obj_cls = obj.class();
let func = match obj_cls.get_attr(name) {
Some(f) => f,
None => {
drop(obj_cls);
return Ok(Err(obj));
}
};
let meth = if func
.class()
.slots
.flags
.has_feature(PyTypeFlags::METHOD_DESCR)
{
drop(obj_cls);
Self::Function { target: obj, func }
} else {
let obj_cls = obj_cls.into_owned().into();
let attr = vm
.call_get_descriptor_specific(func, Some(obj), Some(obj_cls))
.unwrap_or_else(Ok)?;
Self::Attribute(attr)
};
Ok(Ok(meth))
}
pub fn invoke(self, args: impl IntoFuncArgs, vm: &VirtualMachine) -> PyResult {
let (func, args) = match self {
PyMethod::Function { target, func } => (func, args.into_method_args(target, vm)),
PyMethod::Attribute(func) => (func, args.into_args(vm)),
};
vm.invoke(&func, args)
}
#[allow(dead_code)]
pub fn invoke_ref(&self, args: impl IntoFuncArgs, vm: &VirtualMachine) -> PyResult {
let (func, args) = match self {
PyMethod::Function { target, func } => {
(func, args.into_method_args(target.clone(), vm))
}
PyMethod::Attribute(func) => (func, args.into_args(vm)),
};
vm.invoke(func, args)
}
}

View File

@@ -7,6 +7,7 @@
mod compile;
mod context;
mod interpreter;
mod method;
mod setting;
pub mod thread;
mod vm_new;
@@ -42,6 +43,7 @@ use std::{
pub use context::Context;
pub use interpreter::Interpreter;
pub(crate) use method::PyMethod;
pub use setting::Settings;
// Objects are live when they are on stack, or referenced by a name (for now)

View File

@@ -1,8 +1,9 @@
use super::PyMethod;
use crate::{
builtins::{PyBaseExceptionRef, PyList, PyStr},
function::{FuncArgs, IntoFuncArgs},
object::{AsObject, PyObject, PyObjectRef, PyPayload, PyResult},
vm::VirtualMachine,
AsObject, PyMethod, PyObject, PyObjectRef, PyPayload, PyResult,
};
/// Trace events for sys.settrace and sys.setprofile.

View File

@@ -1,10 +1,10 @@
use super::{PyMethod, VirtualMachine};
use crate::{
builtins::{PyInt, PyIntRef},
function::PyArithmeticValue,
object::{AsObject, PyObject, PyObjectRef, PyResult},
protocol::PyIterReturn,
types::PyComparisonOp,
vm::VirtualMachine,
AsObject, PyMethod, PyObject, PyObjectRef, PyResult,
};
/// Collection of operators