From dd56d1d5a215e3828a397e3723745fc504d9bc33 Mon Sep 17 00:00:00 2001 From: Joey Hain Date: Fri, 8 Mar 2019 18:52:11 -0800 Subject: [PATCH 1/5] function --- vm/src/obj/objfunction.rs | 34 ++++++++++++++++++++++++++++++---- vm/src/pyobject.rs | 14 +++----------- vm/src/vm.rs | 20 ++++++++++++-------- 3 files changed, 45 insertions(+), 23 deletions(-) diff --git a/vm/src/obj/objfunction.rs b/vm/src/obj/objfunction.rs index 26fee403fa..46e59663d1 100644 --- a/vm/src/obj/objfunction.rs +++ b/vm/src/obj/objfunction.rs @@ -1,8 +1,34 @@ +use crate::frame::ScopeRef; use crate::pyobject::{ - AttributeProtocol, IdProtocol, PyContext, PyFuncArgs, PyObjectPayload, PyResult, TypeProtocol, + AttributeProtocol, IdProtocol, PyContext, PyFuncArgs, PyObjectPayload2, PyObjectRef, PyResult, + TypeProtocol, }; use crate::vm::VirtualMachine; +#[derive(Debug)] +pub struct PyFunction { + // TODO: these shouldn't be public + pub code: PyObjectRef, + pub scope: ScopeRef, + pub defaults: PyObjectRef, +} + +impl PyFunction { + pub fn new(code: PyObjectRef, scope: ScopeRef, defaults: PyObjectRef) -> Self { + PyFunction { + code, + scope, + defaults, + } + } +} + +impl PyObjectPayload2 for PyFunction { + fn required_type(ctx: &PyContext) -> PyObjectRef { + ctx.function_type() + } +} + pub fn init(context: &PyContext) { let function_type = &context.function_type; context.set_attr(&function_type, "__get__", context.new_rustfunc(bind_method)); @@ -79,9 +105,9 @@ fn bind_method(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { } fn function_code(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { - match args.args[0].payload { - PyObjectPayload::Function { ref code, .. } => Ok(code.clone()), - _ => Err(vm.new_type_error("no code".to_string())), + match args.args[0].payload() { + Some(PyFunction { ref code, .. }) => Ok(code.clone()), + None => Err(vm.new_type_error("no code".to_string())), } } diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index 14f7b6e7b1..e5c3f4e5c4 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -24,7 +24,7 @@ use crate::obj::objenumerate; use crate::obj::objfilter; use crate::obj::objfloat::{self, PyFloat}; use crate::obj::objframe; -use crate::obj::objfunction; +use crate::obj::objfunction::{self, PyFunction}; use crate::obj::objgenerator; use crate::obj::objint::{self, PyInt}; use crate::obj::objiter; @@ -657,10 +657,8 @@ impl PyContext { defaults: PyObjectRef, ) -> PyObjectRef { PyObject::new( - PyObjectPayload::Function { - code: code_obj, - scope, - defaults, + PyObjectPayload::AnyRustValue { + value: Box::new(PyFunction::new(code_obj, scope, defaults)), }, self.function_type(), ) @@ -1510,11 +1508,6 @@ pub enum PyObjectPayload { Frame { frame: Frame, }, - Function { - code: PyObjectRef, - scope: ScopeRef, - defaults: PyObjectRef, - }, Generator { frame: PyObjectRef, }, @@ -1548,7 +1541,6 @@ impl fmt::Debug for PyObjectPayload { PyObjectPayload::WeakRef { .. } => write!(f, "weakref"), PyObjectPayload::Iterator { .. } => write!(f, "iterator"), PyObjectPayload::Slice { .. } => write!(f, "slice"), - PyObjectPayload::Function { .. } => write!(f, "function"), PyObjectPayload::Generator { .. } => write!(f, "generator"), PyObjectPayload::BoundMethod { ref function, diff --git a/vm/src/vm.rs b/vm/src/vm.rs index bf5ce74332..63f252bc08 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -18,6 +18,7 @@ use crate::frame::{Scope, ScopeRef}; use crate::obj::objbool; use crate::obj::objcode; use crate::obj::objframe; +use crate::obj::objfunction::PyFunction; use crate::obj::objgenerator; use crate::obj::objiter; use crate::obj::objlist::PyList; @@ -289,13 +290,16 @@ impl VirtualMachine { { let args = args.into(); trace!("Invoke: {:?} {:?}", func_ref, args); + if let Some(PyFunction { + ref code, + ref scope, + ref defaults, + }) = func_ref.payload() + { + return self.invoke_python_function(code, scope, defaults, args); + } match func_ref.payload { PyObjectPayload::RustFunction { ref function } => function(self, args), - PyObjectPayload::Function { - ref code, - ref scope, - ref defaults, - } => self.invoke_python_function(code, scope, defaults, args), PyObjectPayload::BoundMethod { ref function, ref object, @@ -331,11 +335,11 @@ impl VirtualMachine { } pub fn invoke_with_locals(&mut self, function: PyObjectRef, locals: PyObjectRef) -> PyResult { - if let PyObjectPayload::Function { + if let Some(PyFunction { code, scope, - defaults: _defaults, - } = &function.payload + defaults: _, + }) = &function.payload() { let scope = Rc::new(Scope { locals, From 5a74121c76a02e146bf5d6daf28f1f6dbe7752f3 Mon Sep 17 00:00:00 2001 From: Joey Hain Date: Fri, 8 Mar 2019 19:11:01 -0800 Subject: [PATCH 2/5] method --- vm/src/obj/objfunction.rs | 19 +++++++++++++++++++ vm/src/pyobject.rs | 14 ++++---------- vm/src/vm.rs | 13 ++++++++----- 3 files changed, 31 insertions(+), 15 deletions(-) diff --git a/vm/src/obj/objfunction.rs b/vm/src/obj/objfunction.rs index 46e59663d1..432266225b 100644 --- a/vm/src/obj/objfunction.rs +++ b/vm/src/obj/objfunction.rs @@ -29,6 +29,25 @@ impl PyObjectPayload2 for PyFunction { } } +#[derive(Debug)] +pub struct PyMethod { + // TODO: these shouldn't be public + pub object: PyObjectRef, + pub function: PyObjectRef, +} + +impl PyMethod { + pub fn new(object: PyObjectRef, function: PyObjectRef) -> Self { + PyMethod { object, function } + } +} + +impl PyObjectPayload2 for PyMethod { + fn required_type(ctx: &PyContext) -> PyObjectRef { + ctx.bound_method_type() + } +} + pub fn init(context: &PyContext) { let function_type = &context.function_type; context.set_attr(&function_type, "__get__", context.new_rustfunc(bind_method)); diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index e5c3f4e5c4..cd7712c452 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -24,7 +24,7 @@ use crate::obj::objenumerate; use crate::obj::objfilter; use crate::obj::objfloat::{self, PyFloat}; use crate::obj::objframe; -use crate::obj::objfunction::{self, PyFunction}; +use crate::obj::objfunction::{self, PyFunction, PyMethod}; use crate::obj::objgenerator; use crate::obj::objint::{self, PyInt}; use crate::obj::objiter; @@ -666,7 +666,9 @@ impl PyContext { pub fn new_bound_method(&self, function: PyObjectRef, object: PyObjectRef) -> PyObjectRef { PyObject::new( - PyObjectPayload::BoundMethod { function, object }, + PyObjectPayload::AnyRustValue { + value: Box::new(PyMethod::new(object, function)), + }, self.bound_method_type(), ) } @@ -1511,10 +1513,6 @@ pub enum PyObjectPayload { Generator { frame: PyObjectRef, }, - BoundMethod { - function: PyObjectRef, - object: PyObjectRef, - }, WeakRef { referent: PyObjectWeakRef, }, @@ -1542,10 +1540,6 @@ impl fmt::Debug for PyObjectPayload { PyObjectPayload::Iterator { .. } => write!(f, "iterator"), PyObjectPayload::Slice { .. } => write!(f, "slice"), PyObjectPayload::Generator { .. } => write!(f, "generator"), - PyObjectPayload::BoundMethod { - ref function, - ref object, - } => write!(f, "bound-method: {:?} of {:?}", function, object), PyObjectPayload::RustFunction { .. } => write!(f, "rust function"), PyObjectPayload::Frame { .. } => write!(f, "frame"), PyObjectPayload::AnyRustValue { value } => value.fmt(f), diff --git a/vm/src/vm.rs b/vm/src/vm.rs index 63f252bc08..72af935dbf 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -18,7 +18,7 @@ use crate::frame::{Scope, ScopeRef}; use crate::obj::objbool; use crate::obj::objcode; use crate::obj::objframe; -use crate::obj::objfunction::PyFunction; +use crate::obj::objfunction::{PyFunction, PyMethod}; use crate::obj::objgenerator; use crate::obj::objiter; use crate::obj::objlist::PyList; @@ -298,12 +298,15 @@ impl VirtualMachine { { return self.invoke_python_function(code, scope, defaults, args); } + if let Some(PyMethod { + ref function, + ref object, + }) = func_ref.payload() + { + return self.invoke(function.clone(), args.insert(object.clone())); + } match func_ref.payload { PyObjectPayload::RustFunction { ref function } => function(self, args), - PyObjectPayload::BoundMethod { - ref function, - ref object, - } => self.invoke(function.clone(), args.insert(object.clone())), ref payload => { // TODO: is it safe to just invoke __call__ otherwise? trace!("invoke __call__ for: {:?}", payload); From c1180fc564011dda46b095f7c643deeafc822ee6 Mon Sep 17 00:00:00 2001 From: Joey Date: Sat, 9 Mar 2019 08:45:46 -0800 Subject: [PATCH 3/5] builtin_function_or_method --- vm/src/frame.rs | 7 +++++-- vm/src/obj/mod.rs | 1 + vm/src/obj/objbuiltinfunc.rs | 26 ++++++++++++++++++++++++++ vm/src/pyobject.rs | 9 +++------ vm/src/vm.rs | 18 +++++++++--------- 5 files changed, 44 insertions(+), 17 deletions(-) create mode 100644 vm/src/obj/objbuiltinfunc.rs diff --git a/vm/src/frame.rs b/vm/src/frame.rs index db913fe1b8..8e91194a05 100644 --- a/vm/src/frame.rs +++ b/vm/src/frame.rs @@ -11,6 +11,7 @@ use crate::builtins; use crate::bytecode; use crate::import::{import, import_module}; use crate::obj::objbool; +use crate::obj::objbuiltinfunc::PyBuiltinFunction; use crate::obj::objcode; use crate::obj::objdict; use crate::obj::objdict::PyDict; @@ -592,8 +593,10 @@ impl Frame { } bytecode::Instruction::LoadBuildClass => { let rustfunc = PyObject::new( - PyObjectPayload::RustFunction { - function: Box::new(builtins::builtin_build_class_), + PyObjectPayload::AnyRustValue { + value: Box::new(PyBuiltinFunction::new(Box::new( + builtins::builtin_build_class_, + ))), }, vm.ctx.type_type(), ); diff --git a/vm/src/obj/mod.rs b/vm/src/obj/mod.rs index 6cbb5fa66f..3d068df648 100644 --- a/vm/src/obj/mod.rs +++ b/vm/src/obj/mod.rs @@ -1,6 +1,7 @@ //! This package contains the python basic/builtin types pub mod objbool; +pub mod objbuiltinfunc; pub mod objbytearray; pub mod objbytes; pub mod objcode; diff --git a/vm/src/obj/objbuiltinfunc.rs b/vm/src/obj/objbuiltinfunc.rs new file mode 100644 index 0000000000..8e3b2c3422 --- /dev/null +++ b/vm/src/obj/objbuiltinfunc.rs @@ -0,0 +1,26 @@ +use std::fmt; + +use crate::pyobject::{PyContext, PyNativeFunc, PyObjectPayload2, PyObjectRef}; + +pub struct PyBuiltinFunction { + // TODO: shouldn't be public + pub value: PyNativeFunc, +} + +impl PyObjectPayload2 for PyBuiltinFunction { + fn required_type(ctx: &PyContext) -> PyObjectRef { + ctx.builtin_function_or_method_type() + } +} + +impl fmt::Debug for PyBuiltinFunction { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "builtin function") + } +} + +impl PyBuiltinFunction { + pub fn new(value: PyNativeFunc) -> Self { + Self { value } + } +} diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index cd7712c452..740e27ace3 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -14,6 +14,7 @@ use crate::bytecode; use crate::exceptions; use crate::frame::{Frame, Scope, ScopeRef}; use crate::obj::objbool; +use crate::obj::objbuiltinfunc::PyBuiltinFunction; use crate::obj::objbytearray; use crate::obj::objbytes; use crate::obj::objcode; @@ -615,8 +616,8 @@ impl PyContext { F: IntoPyNativeFunc, { PyObject::new( - PyObjectPayload::RustFunction { - function: f.into_func(), + PyObjectPayload::AnyRustValue { + value: Box::new(PyBuiltinFunction::new(f.into_func())), }, self.builtin_function_or_method_type(), ) @@ -1516,9 +1517,6 @@ pub enum PyObjectPayload { WeakRef { referent: PyObjectWeakRef, }, - RustFunction { - function: PyNativeFunc, - }, AnyRustValue { value: Box, }, @@ -1540,7 +1538,6 @@ impl fmt::Debug for PyObjectPayload { PyObjectPayload::Iterator { .. } => write!(f, "iterator"), PyObjectPayload::Slice { .. } => write!(f, "slice"), PyObjectPayload::Generator { .. } => write!(f, "generator"), - PyObjectPayload::RustFunction { .. } => write!(f, "rust function"), PyObjectPayload::Frame { .. } => write!(f, "frame"), PyObjectPayload::AnyRustValue { value } => value.fmt(f), } diff --git a/vm/src/vm.rs b/vm/src/vm.rs index 72af935dbf..32a0104d23 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -16,6 +16,7 @@ use crate::bytecode; use crate::frame::ExecutionResult; use crate::frame::{Scope, ScopeRef}; use crate::obj::objbool; +use crate::obj::objbuiltinfunc::PyBuiltinFunction; use crate::obj::objcode; use crate::obj::objframe; use crate::obj::objfunction::{PyFunction, PyMethod}; @@ -28,8 +29,8 @@ use crate::obj::objstr; use crate::obj::objtuple::PyTuple; use crate::obj::objtype; use crate::pyobject::{ - AttributeProtocol, DictProtocol, IdProtocol, PyContext, PyFuncArgs, PyObjectPayload, - PyObjectRef, PyResult, TypeProtocol, + AttributeProtocol, DictProtocol, IdProtocol, PyContext, PyFuncArgs, PyObjectRef, PyResult, + TypeProtocol, }; use crate::stdlib; use crate::sysmodule; @@ -305,14 +306,13 @@ impl VirtualMachine { { return self.invoke(function.clone(), args.insert(object.clone())); } - match func_ref.payload { - PyObjectPayload::RustFunction { ref function } => function(self, args), - ref payload => { - // TODO: is it safe to just invoke __call__ otherwise? - trace!("invoke __call__ for: {:?}", payload); - self.call_method(&func_ref, "__call__", args) - } + if let Some(PyBuiltinFunction { ref value }) = func_ref.payload() { + return value(self, args); } + + // TODO: is it safe to just invoke __call__ otherwise? + trace!("invoke __call__ for: {:?}", func_ref.payload); + self.call_method(&func_ref, "__call__", args) } fn invoke_python_function( From 53e4591911947bd63530ffaa5947ebc3f7269b12 Mon Sep 17 00:00:00 2001 From: Joey Date: Sat, 9 Mar 2019 09:21:21 -0800 Subject: [PATCH 4/5] frame --- vm/src/frame.rs | 10 ++++++++-- vm/src/obj/objframe.rs | 10 ++-------- vm/src/obj/objgenerator.rs | 4 ++-- vm/src/pyobject.rs | 8 ++------ 4 files changed, 14 insertions(+), 18 deletions(-) diff --git a/vm/src/frame.rs b/vm/src/frame.rs index 8e91194a05..391ab6fe3d 100644 --- a/vm/src/frame.rs +++ b/vm/src/frame.rs @@ -21,8 +21,8 @@ use crate::obj::objlist; use crate::obj::objstr; use crate::obj::objtype; use crate::pyobject::{ - DictProtocol, IdProtocol, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, - TryFromObject, TypeProtocol, + DictProtocol, IdProtocol, PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectPayload2, + PyObjectRef, PyResult, TryFromObject, TypeProtocol, }; use crate::vm::VirtualMachine; @@ -76,6 +76,12 @@ pub struct Frame { pub lasti: RefCell, // index of last instruction ran } +impl PyObjectPayload2 for Frame { + fn required_type(ctx: &PyContext) -> PyObjectRef { + ctx.frame_type() + } +} + // Running a frame can result in one of the below: pub enum ExecutionResult { Return(PyObjectRef), diff --git a/vm/src/obj/objframe.rs b/vm/src/obj/objframe.rs index 37acd33385..459b5a0c3d 100644 --- a/vm/src/obj/objframe.rs +++ b/vm/src/obj/objframe.rs @@ -3,9 +3,7 @@ */ use crate::frame::Frame; -use crate::pyobject::{ - PyContext, PyFuncArgs, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol, -}; +use crate::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol}; use crate::vm::VirtualMachine; pub fn init(context: &PyContext) { @@ -39,9 +37,5 @@ fn frame_fcode(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { } pub fn get_value(obj: &PyObjectRef) -> &Frame { - if let PyObjectPayload::Frame { frame } = &obj.payload { - frame - } else { - panic!("Inner error getting int {:?}", obj); - } + &obj.payload::().unwrap() } diff --git a/vm/src/obj/objgenerator.rs b/vm/src/obj/objgenerator.rs index 05a7a60ae6..9192b07aae 100644 --- a/vm/src/obj/objgenerator.rs +++ b/vm/src/obj/objgenerator.rs @@ -2,7 +2,7 @@ * The mythical generator. */ -use crate::frame::ExecutionResult; +use crate::frame::{ExecutionResult, Frame}; use crate::pyobject::{ PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol, }; @@ -56,7 +56,7 @@ fn generator_send(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { fn send(vm: &mut VirtualMachine, gen: &PyObjectRef, value: &PyObjectRef) -> PyResult { if let PyObjectPayload::Generator { ref frame } = gen.payload { - if let PyObjectPayload::Frame { ref frame } = frame.payload { + if let Some(frame) = frame.payload::() { frame.push_value(value.clone()); } else { panic!("Generator frame isn't a frame."); diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index 740e27ace3..c1dadb92d2 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -625,8 +625,8 @@ impl PyContext { pub fn new_frame(&self, code: PyObjectRef, scope: ScopeRef) -> PyObjectRef { PyObject::new( - PyObjectPayload::Frame { - frame: Frame::new(code, scope), + PyObjectPayload::AnyRustValue { + value: Box::new(Frame::new(code, scope)), }, self.frame_type(), ) @@ -1508,9 +1508,6 @@ pub enum PyObjectPayload { MemoryView { obj: PyObjectRef, }, - Frame { - frame: Frame, - }, Generator { frame: PyObjectRef, }, @@ -1538,7 +1535,6 @@ impl fmt::Debug for PyObjectPayload { PyObjectPayload::Iterator { .. } => write!(f, "iterator"), PyObjectPayload::Slice { .. } => write!(f, "slice"), PyObjectPayload::Generator { .. } => write!(f, "generator"), - PyObjectPayload::Frame { .. } => write!(f, "frame"), PyObjectPayload::AnyRustValue { value } => value.fmt(f), } } From 6eea40799be84c0624cec7ba3fe073bad6aae65c Mon Sep 17 00:00:00 2001 From: Joey Date: Sat, 9 Mar 2019 09:27:58 -0800 Subject: [PATCH 5/5] generator --- vm/src/obj/objgenerator.rs | 20 +++++++++++++++++--- vm/src/pyobject.rs | 4 ---- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/vm/src/obj/objgenerator.rs b/vm/src/obj/objgenerator.rs index 9192b07aae..1babd5c9dc 100644 --- a/vm/src/obj/objgenerator.rs +++ b/vm/src/obj/objgenerator.rs @@ -4,10 +4,22 @@ use crate::frame::{ExecutionResult, Frame}; use crate::pyobject::{ - PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol, + PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectPayload2, PyObjectRef, PyResult, + TypeProtocol, }; use crate::vm::VirtualMachine; +#[derive(Debug)] +pub struct PyGenerator { + frame: PyObjectRef, +} + +impl PyObjectPayload2 for PyGenerator { + fn required_type(ctx: &PyContext) -> PyObjectRef { + ctx.generator_type() + } +} + pub fn init(context: &PyContext) { let generator_type = &context.generator_type; context.set_attr( @@ -29,7 +41,9 @@ pub fn init(context: &PyContext) { pub fn new_generator(vm: &mut VirtualMachine, frame: PyObjectRef) -> PyResult { Ok(PyObject::new( - PyObjectPayload::Generator { frame }, + PyObjectPayload::AnyRustValue { + value: Box::new(PyGenerator { frame }), + }, vm.ctx.generator_type.clone(), )) } @@ -55,7 +69,7 @@ fn generator_send(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { } fn send(vm: &mut VirtualMachine, gen: &PyObjectRef, value: &PyObjectRef) -> PyResult { - if let PyObjectPayload::Generator { ref frame } = gen.payload { + if let Some(PyGenerator { ref frame }) = gen.payload() { if let Some(frame) = frame.payload::() { frame.push_value(value.clone()); } else { diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index c1dadb92d2..c9c7ed02ac 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -1508,9 +1508,6 @@ pub enum PyObjectPayload { MemoryView { obj: PyObjectRef, }, - Generator { - frame: PyObjectRef, - }, WeakRef { referent: PyObjectWeakRef, }, @@ -1534,7 +1531,6 @@ impl fmt::Debug for PyObjectPayload { PyObjectPayload::WeakRef { .. } => write!(f, "weakref"), PyObjectPayload::Iterator { .. } => write!(f, "iterator"), PyObjectPayload::Slice { .. } => write!(f, "slice"), - PyObjectPayload::Generator { .. } => write!(f, "generator"), PyObjectPayload::AnyRustValue { value } => value.fmt(f), } }