forked from Rust-related/RustPython
Replace all of callable operations to PyCallable
This commit is contained in:
@@ -4,20 +4,30 @@ use crate::{
|
||||
convert::ToPyObject,
|
||||
identifier,
|
||||
protocol::{PyIter, PyIterIter, PyMapping, PyMappingMethods},
|
||||
types::AsMapping,
|
||||
types::{AsMapping, GenericMethod},
|
||||
AsObject, PyObject, PyObjectRef, PyPayload, PyResult, TryFromObject, VirtualMachine,
|
||||
};
|
||||
use std::{borrow::Borrow, marker::PhantomData, ops::Deref};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone)]
|
||||
pub struct ArgCallable {
|
||||
obj: PyObjectRef, // FIXME: PyCallable
|
||||
obj: PyObjectRef,
|
||||
call: GenericMethod,
|
||||
}
|
||||
|
||||
impl ArgCallable {
|
||||
#[inline(always)]
|
||||
pub fn invoke(&self, args: impl IntoFuncArgs, vm: &VirtualMachine) -> PyResult {
|
||||
vm.invoke(&self.obj, args)
|
||||
(self.call)(&self.obj, args.into_args(vm), vm)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for ArgCallable {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("ArgCallable")
|
||||
.field("obj", &self.obj)
|
||||
.field("call", &format!("{:08x}", self.call as usize))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,11 +54,11 @@ impl From<ArgCallable> for PyObjectRef {
|
||||
|
||||
impl TryFromObject for ArgCallable {
|
||||
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
|
||||
if obj.is_callable() {
|
||||
Ok(ArgCallable { obj })
|
||||
} else {
|
||||
Err(vm.new_type_error(format!("'{}' object is not callable", obj.class().name())))
|
||||
}
|
||||
let Some(callable) = obj.to_callable() else {
|
||||
return Err(vm.new_type_error(format!("'{}' object is not callable", obj.class().name())));
|
||||
};
|
||||
let call = callable.call;
|
||||
Ok(ArgCallable { obj, call })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
function::IntoFuncArgs,
|
||||
types::GenericMethod,
|
||||
{PyObject, PyResult, VirtualMachine}
|
||||
{AsObject, PyObject, PyResult, VirtualMachine},
|
||||
};
|
||||
|
||||
impl PyObject {
|
||||
@@ -28,6 +28,70 @@ impl<'a> PyCallable<'a> {
|
||||
}
|
||||
|
||||
pub fn invoke(&self, args: impl IntoFuncArgs, vm: &VirtualMachine) -> PyResult {
|
||||
(self.call)(self.obj, args.into_args(vm), vm)
|
||||
vm.trace_event(TraceEvent::Call)?;
|
||||
let result = (self.call)(self.obj, args.into_args(vm), vm);
|
||||
vm.trace_event(TraceEvent::Return)?;
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
/// Trace events for sys.settrace and sys.setprofile.
|
||||
enum TraceEvent {
|
||||
Call,
|
||||
Return,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for TraceEvent {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
use TraceEvent::*;
|
||||
match self {
|
||||
Call => write!(f, "call"),
|
||||
Return => write!(f, "return"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl VirtualMachine {
|
||||
/// Call registered trace function.
|
||||
#[inline]
|
||||
fn trace_event(&self, event: TraceEvent) -> PyResult<()> {
|
||||
if self.use_tracing.get() {
|
||||
self._trace_event_inner(event)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
fn _trace_event_inner(&self, event: TraceEvent) -> PyResult<()> {
|
||||
let trace_func = self.trace_func.borrow().to_owned();
|
||||
let profile_func = self.profile_func.borrow().to_owned();
|
||||
if self.is_none(&trace_func) && self.is_none(&profile_func) {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let frame_ref = self.current_frame();
|
||||
if frame_ref.is_none() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let frame = frame_ref.unwrap().as_object().to_owned();
|
||||
let event = self.ctx.new_str(event.to_string()).into();
|
||||
let args = vec![frame, event, self.ctx.none()];
|
||||
|
||||
// temporarily disable tracing, during the call to the
|
||||
// tracing function itself.
|
||||
if !self.is_none(&trace_func) {
|
||||
self.use_tracing.set(false);
|
||||
let res = self.invoke(&trace_func, args.clone());
|
||||
self.use_tracing.set(true);
|
||||
res?;
|
||||
}
|
||||
|
||||
if !self.is_none(&profile_func) {
|
||||
self.use_tracing.set(false);
|
||||
let res = self.invoke(&profile_func, args);
|
||||
self.use_tracing.set(true);
|
||||
res?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,22 +7,6 @@ use crate::{
|
||||
vm::VirtualMachine,
|
||||
};
|
||||
|
||||
/// Trace events for sys.settrace and sys.setprofile.
|
||||
enum TraceEvent {
|
||||
Call,
|
||||
Return,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for TraceEvent {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
use TraceEvent::*;
|
||||
match self {
|
||||
Call => write!(f, "call"),
|
||||
Return => write!(f, "return"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// PyObject support
|
||||
impl VirtualMachine {
|
||||
#[track_caller]
|
||||
@@ -167,68 +151,19 @@ impl VirtualMachine {
|
||||
.invoke(args, self)
|
||||
}
|
||||
|
||||
fn _invoke(&self, callable: &PyObject, args: FuncArgs) -> PyResult {
|
||||
fn _invoke(&self, obj: &PyObject, args: FuncArgs) -> PyResult {
|
||||
vm_trace!("Invoke: {:?} {:?}", callable, args);
|
||||
let slot_call = callable.class().mro_find_map(|cls| cls.slots.call.load());
|
||||
match slot_call {
|
||||
Some(slot_call) => {
|
||||
self.trace_event(TraceEvent::Call)?;
|
||||
let result = slot_call(callable, args, self);
|
||||
self.trace_event(TraceEvent::Return)?;
|
||||
result
|
||||
}
|
||||
None => Err(self.new_type_error(format!(
|
||||
let Some(callable) = obj.to_callable() else {
|
||||
return Err(self.new_type_error(format!(
|
||||
"'{}' object is not callable",
|
||||
callable.class().name()
|
||||
))),
|
||||
}
|
||||
obj.class().name()
|
||||
)));
|
||||
};
|
||||
callable.invoke(args, self)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn invoke(&self, func: &impl AsObject, args: impl IntoFuncArgs) -> PyResult {
|
||||
self._invoke(func.as_object(), args.into_args(self))
|
||||
}
|
||||
|
||||
/// Call registered trace function.
|
||||
#[inline]
|
||||
fn trace_event(&self, event: TraceEvent) -> PyResult<()> {
|
||||
if self.use_tracing.get() {
|
||||
self._trace_event_inner(event)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
fn _trace_event_inner(&self, event: TraceEvent) -> PyResult<()> {
|
||||
let trace_func = self.trace_func.borrow().to_owned();
|
||||
let profile_func = self.profile_func.borrow().to_owned();
|
||||
if self.is_none(&trace_func) && self.is_none(&profile_func) {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let frame_ref = self.current_frame();
|
||||
if frame_ref.is_none() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let frame = frame_ref.unwrap().as_object().to_owned();
|
||||
let event = self.ctx.new_str(event.to_string()).into();
|
||||
let args = vec![frame, event, self.ctx.none()];
|
||||
|
||||
// temporarily disable tracing, during the call to the
|
||||
// tracing function itself.
|
||||
if !self.is_none(&trace_func) {
|
||||
self.use_tracing.set(false);
|
||||
let res = self.invoke(&trace_func, args.clone());
|
||||
self.use_tracing.set(true);
|
||||
res?;
|
||||
}
|
||||
|
||||
if !self.is_none(&profile_func) {
|
||||
self.use_tracing.set(false);
|
||||
let res = self.invoke(&profile_func, args);
|
||||
self.use_tracing.set(true);
|
||||
res?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user