From ed60687f11939ccae8862ba4eb71f9047576b32b Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Tue, 7 Mar 2023 19:44:46 +0900 Subject: [PATCH] Replace all of callable operations to PyCallable --- vm/src/function/protocol.rs | 28 ++++++++----- vm/src/protocol/callable.rs | 68 ++++++++++++++++++++++++++++++- vm/src/vm/vm_object.rs | 79 ++++--------------------------------- 3 files changed, 92 insertions(+), 83 deletions(-) diff --git a/vm/src/function/protocol.rs b/vm/src/function/protocol.rs index 630d61cebc..5d6c0df8af 100644 --- a/vm/src/function/protocol.rs +++ b/vm/src/function/protocol.rs @@ -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 for PyObjectRef { impl TryFromObject for ArgCallable { fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult { - 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 }) } } diff --git a/vm/src/protocol/callable.rs b/vm/src/protocol/callable.rs index 9e002bc447..22b301b84c 100644 --- a/vm/src/protocol/callable.rs +++ b/vm/src/protocol/callable.rs @@ -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(()) } } diff --git a/vm/src/vm/vm_object.rs b/vm/src/vm/vm_object.rs index b20c446b96..5dbfd0fb58 100644 --- a/vm/src/vm/vm_object.rs +++ b/vm/src/vm/vm_object.rs @@ -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(()) - } }