Compare commits

...

2 Commits

Author SHA1 Message Date
Adam Kelly
c5b6b61fba Construct PyObjectRef earlier to avoid the need for Clone on Frame. 2018-11-14 08:41:48 +00:00
Adam Kelly
ee86229ff6 Keep a stack of frames on the VM. 2018-11-14 07:49:41 +00:00
7 changed files with 95 additions and 52 deletions

View File

@@ -9,7 +9,8 @@ assert locals_dict['foo'] == foo
def test_function(): def test_function():
x = 17 x = 17
assert sys._getframe().f_locals is not locals_dict assert sys._getframe().f_locals is not locals_dict
assert sys._getframe().f_locals['x'] == 17 assert sys._getframe(0).f_locals['x'] == 17
assert sys._getframe(1).f_locals['foo'] == 'bar'
test_function() test_function()
@@ -18,3 +19,8 @@ class TestClass():
assert sys._getframe().f_locals['self'] == self assert sys._getframe().f_locals['self'] == self
TestClass() TestClass()
try:
sys._getframe(100)
except ValueError:
pass

View File

@@ -3,7 +3,6 @@ extern crate rustpython_parser;
use self::rustpython_parser::ast; use self::rustpython_parser::ast;
use std::collections::hash_map::HashMap; use std::collections::hash_map::HashMap;
use std::fmt; use std::fmt;
use std::mem;
use std::path::PathBuf; use std::path::PathBuf;
use super::builtins; use super::builtins;
@@ -39,7 +38,6 @@ enum Block {
}, },
} }
#[derive(Clone)]
pub struct Frame { pub struct Frame {
pub code: bytecode::CodeObject, pub code: bytecode::CodeObject,
// We need 1 stack per frame // We need 1 stack per frame
@@ -82,22 +80,13 @@ impl Frame {
} }
} }
pub fn run_frame_full(&mut self, vm: &mut VirtualMachine) -> PyResult { pub fn run(&mut self, vm: &mut VirtualMachine) -> Result<ExecutionResult, PyObjectRef> {
match self.run_frame(vm)? {
ExecutionResult::Return(value) => Ok(value),
_ => panic!("Got unexpected result from function"),
}
}
pub fn run_frame(&mut self, vm: &mut VirtualMachine) -> Result<ExecutionResult, PyObjectRef> {
let filename = if let Some(source_path) = &self.code.source_path { let filename = if let Some(source_path) = &self.code.source_path {
source_path.to_string() source_path.to_string()
} else { } else {
"<unknown>".to_string() "<unknown>".to_string()
}; };
let prev_frame = mem::replace(&mut vm.current_frame, Some(vm.ctx.new_frame(self.clone())));
// This is the name of the object being run: // This is the name of the object being run:
let run_obj_name = &self.code.obj_name.to_string(); let run_obj_name = &self.code.obj_name.to_string();
@@ -146,7 +135,6 @@ impl Frame {
} }
}; };
vm.current_frame = prev_frame;
value value
} }

View File

@@ -2,7 +2,6 @@
*/ */
use super::super::frame::Frame;
use super::super::pyobject::{ use super::super::pyobject::{
AttributeProtocol, PyContext, PyFuncArgs, PyObjectKind, PyObjectRef, PyResult, TypeProtocol, AttributeProtocol, PyContext, PyFuncArgs, PyObjectKind, PyObjectRef, PyResult, TypeProtocol,
}; };
@@ -30,26 +29,25 @@ fn frame_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
fn frame_flocals(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { fn frame_flocals(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(vm, args, required = [(frame, Some(vm.ctx.frame_type()))]); arg_check!(vm, args, required = [(frame, Some(vm.ctx.frame_type()))]);
let frame = get_value(frame); if let PyObjectKind::Frame { ref frame } = frame.borrow().kind {
let py_scope = frame.locals.clone(); let py_scope = frame.locals.clone();
let py_scope = py_scope.borrow(); let py_scope = py_scope.borrow();
if let PyObjectKind::Scope { scope } = &py_scope.kind { if let PyObjectKind::Scope { scope } = &py_scope.kind {
Ok(scope.locals.clone()) Ok(scope.locals.clone())
} else {
panic!("The scope isn't a scope!");
}
} else { } else {
panic!("The scope isn't a scope!"); panic!("Frame doesn't contain a frame: {:?}", frame);
} }
} }
fn frame_fcode(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { fn frame_fcode(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(vm, args, required = [(frame, Some(vm.ctx.frame_type()))]); arg_check!(vm, args, required = [(frame, Some(vm.ctx.frame_type()))]);
Ok(vm.ctx.new_code_object(get_value(frame).code)) if let PyObjectKind::Frame { ref frame } = frame.borrow().kind {
} Ok(vm.ctx.new_code_object(frame.code.clone()))
pub fn get_value(obj: &PyObjectRef) -> Frame {
if let PyObjectKind::Frame { frame } = &obj.borrow().kind {
frame.clone()
} else { } else {
panic!("Inner error getting int {:?}", obj); panic!("Frame doesn't contain a frame: {:?}", frame);
} }
} }

View File

@@ -2,7 +2,7 @@
* The mythical generator. * The mythical generator.
*/ */
use super::super::frame::{ExecutionResult, Frame}; use super::super::frame::ExecutionResult;
use super::super::pyobject::{ use super::super::pyobject::{
AttributeProtocol, PyContext, PyFuncArgs, PyObject, PyObjectKind, PyObjectRef, PyResult, AttributeProtocol, PyContext, PyFuncArgs, PyObject, PyObjectKind, PyObjectRef, PyResult,
TypeProtocol, TypeProtocol,
@@ -17,7 +17,7 @@ pub fn init(context: &PyContext) {
generator_type.set_attr("send", context.new_rustfunc(generator_send)); generator_type.set_attr("send", context.new_rustfunc(generator_send));
} }
pub fn new_generator(vm: &mut VirtualMachine, frame: Frame) -> PyResult { pub fn new_generator(vm: &mut VirtualMachine, frame: PyObjectRef) -> PyResult {
let g = PyObject::new( let g = PyObject::new(
PyObjectKind::Generator { frame: frame }, PyObjectKind::Generator { frame: frame },
vm.ctx.generator_type.clone(), vm.ctx.generator_type.clone(),
@@ -47,8 +47,13 @@ fn generator_send(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
fn send(vm: &mut VirtualMachine, gen: &PyObjectRef, value: &PyObjectRef) -> PyResult { fn send(vm: &mut VirtualMachine, gen: &PyObjectRef, value: &PyObjectRef) -> PyResult {
if let PyObjectKind::Generator { ref mut frame } = gen.borrow_mut().kind { if let PyObjectKind::Generator { ref mut frame } = gen.borrow_mut().kind {
frame.push_value(value.clone()); if let PyObjectKind::Frame { ref mut frame } = frame.borrow_mut().kind {
match frame.run_frame(vm)? { frame.push_value(value.clone());
} else {
panic!("Generator frame isn't a frame.");
}
match vm.run_frame(frame.clone())? {
ExecutionResult::Yield(value) => Ok(value), ExecutionResult::Yield(value) => Ok(value),
ExecutionResult::Return(_value) => { ExecutionResult::Return(_value) => {
// Stop iteration! // Stop iteration!

View File

@@ -459,8 +459,13 @@ impl PyContext {
) )
} }
pub fn new_frame(&self, frame: Frame) -> PyObjectRef { pub fn new_frame(&self, code: PyObjectRef, scope: PyObjectRef) -> PyObjectRef {
PyObject::new(PyObjectKind::Frame { frame: frame }, self.frame_type()) PyObject::new(
PyObjectKind::Frame {
frame: Frame::new(code, scope),
},
self.frame_type(),
)
} }
pub fn new_property(&self, function: RustPyFunc) -> PyObjectRef { pub fn new_property(&self, function: RustPyFunc) -> PyObjectRef {
@@ -811,7 +816,7 @@ pub enum PyObjectKind {
defaults: PyObjectRef, defaults: PyObjectRef,
}, },
Generator { Generator {
frame: Frame, frame: PyObjectRef,
}, },
BoundMethod { BoundMethod {
function: PyObjectRef, function: PyObjectRef,

View File

@@ -1,9 +1,12 @@
use super::obj::objint;
use super::obj::objtype;
use super::pyobject::{DictProtocol, PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol};
use super::vm::VirtualMachine;
use num_bigint::ToBigInt; use num_bigint::ToBigInt;
use obj::objtype; use num_traits::ToPrimitive;
use pyobject::{DictProtocol, PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol}; use std::env;
use std::mem;
use std::rc::Rc; use std::rc::Rc;
use std::{env, mem};
use vm::VirtualMachine;
/* /*
* The magic sys module. * The magic sys module.
@@ -15,12 +18,31 @@ fn argv(ctx: &PyContext) -> PyObjectRef {
ctx.new_list(argv) ctx.new_list(argv)
} }
fn getframe(vm: &mut VirtualMachine, _args: PyFuncArgs) -> PyResult { fn getframe(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
if let Some(frame) = &vm.current_frame { arg_check!(
Ok(frame.clone()) vm,
} else { args,
panic!("Current frame is undefined!") required = [],
} optional = [(offset, Some(vm.ctx.int_type()))]
);
let idx = match offset {
Some(int) => {
if let Some(offset) = objint::get_value(int).to_usize() {
if offset > vm.frames.len() - 1 {
return Err(vm.new_value_error("call stack is not deep enough".to_string()));
}
offset
} else {
0
}
}
None => 0,
};
let idx = vm.frames.len() - idx - 1;
let frame = &vm.frames[idx];
Ok(frame.clone())
} }
fn sys_getrefcount(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { fn sys_getrefcount(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {

View File

@@ -10,7 +10,7 @@ use std::collections::hash_map::HashMap;
use super::builtins; use super::builtins;
use super::bytecode; use super::bytecode;
use super::frame::Frame; use super::frame::ExecutionResult;
use super::obj::objcode::copy_code; use super::obj::objcode::copy_code;
use super::obj::objgenerator; use super::obj::objgenerator;
use super::obj::objiter; use super::obj::objiter;
@@ -35,7 +35,7 @@ pub struct VirtualMachine {
pub sys_module: PyObjectRef, pub sys_module: PyObjectRef,
pub stdlib_inits: HashMap<String, stdlib::StdlibInitFunc>, pub stdlib_inits: HashMap<String, stdlib::StdlibInitFunc>,
pub ctx: PyContext, pub ctx: PyContext,
pub current_frame: Option<PyObjectRef>, pub frames: Vec<PyObjectRef>,
} }
impl VirtualMachine { impl VirtualMachine {
@@ -52,13 +52,32 @@ impl VirtualMachine {
sys_module: sysmod, sys_module: sysmod,
stdlib_inits, stdlib_inits,
ctx: ctx, ctx: ctx,
current_frame: None, frames: vec![],
} }
} }
pub fn run_code_obj(&mut self, code: PyObjectRef, scope: PyObjectRef) -> PyResult { pub fn run_code_obj(&mut self, code: PyObjectRef, scope: PyObjectRef) -> PyResult {
let mut frame = Frame::new(code, scope); let frame = self.ctx.new_frame(code, scope);
frame.run_frame_full(self) self.run_frame_full(frame)
}
pub fn run_frame_full(&mut self, frame: PyObjectRef) -> PyResult {
match self.run_frame(frame)? {
ExecutionResult::Return(value) => Ok(value),
_ => panic!("Got unexpected result from function"),
}
}
pub fn run_frame(&mut self, frame: PyObjectRef) -> Result<ExecutionResult, PyObjectRef> {
let result;
self.frames.push(frame.clone());
if let PyObjectKind::Frame { ref mut frame } = frame.borrow_mut().kind {
result = frame.run(self);
} else {
panic!("Frame doesn't contain a frame: {:?}", frame);
}
self.frames.pop();
result
} }
/// Create a new python string object. /// Create a new python string object.
@@ -260,13 +279,13 @@ impl VirtualMachine {
self.fill_scope_from_args(&code_object, &scope, args, defaults)?; self.fill_scope_from_args(&code_object, &scope, args, defaults)?;
// Construct frame: // Construct frame:
let mut frame = Frame::new(code.clone(), scope); let frame = self.ctx.new_frame(code.clone(), scope);
// If we have a generator, create a new generator // If we have a generator, create a new generator
if code_object.is_generator { if code_object.is_generator {
objgenerator::new_generator(self, frame) objgenerator::new_generator(self, frame)
} else { } else {
frame.run_frame_full(self) self.run_frame_full(frame)
} }
} }