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():
x = 17
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()
@@ -18,3 +19,8 @@ class TestClass():
assert sys._getframe().f_locals['self'] == self
TestClass()
try:
sys._getframe(100)
except ValueError:
pass

View File

@@ -3,7 +3,6 @@ extern crate rustpython_parser;
use self::rustpython_parser::ast;
use std::collections::hash_map::HashMap;
use std::fmt;
use std::mem;
use std::path::PathBuf;
use super::builtins;
@@ -39,7 +38,6 @@ enum Block {
},
}
#[derive(Clone)]
pub struct Frame {
pub code: bytecode::CodeObject,
// We need 1 stack per frame
@@ -82,22 +80,13 @@ impl Frame {
}
}
pub fn run_frame_full(&mut self, vm: &mut VirtualMachine) -> PyResult {
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> {
pub fn run(&mut self, vm: &mut VirtualMachine) -> Result<ExecutionResult, PyObjectRef> {
let filename = if let Some(source_path) = &self.code.source_path {
source_path.to_string()
} else {
"<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:
let run_obj_name = &self.code.obj_name.to_string();
@@ -146,7 +135,6 @@ impl Frame {
}
};
vm.current_frame = prev_frame;
value
}

View File

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

View File

@@ -2,7 +2,7 @@
* The mythical generator.
*/
use super::super::frame::{ExecutionResult, Frame};
use super::super::frame::ExecutionResult;
use super::super::pyobject::{
AttributeProtocol, PyContext, PyFuncArgs, PyObject, PyObjectKind, PyObjectRef, PyResult,
TypeProtocol,
@@ -17,7 +17,7 @@ pub fn init(context: &PyContext) {
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(
PyObjectKind::Generator { frame: frame },
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 {
if let PyObjectKind::Generator { ref mut frame } = gen.borrow_mut().kind {
if let PyObjectKind::Frame { ref mut frame } = frame.borrow_mut().kind {
frame.push_value(value.clone());
match frame.run_frame(vm)? {
} else {
panic!("Generator frame isn't a frame.");
}
match vm.run_frame(frame.clone())? {
ExecutionResult::Yield(value) => Ok(value),
ExecutionResult::Return(_value) => {
// Stop iteration!

View File

@@ -459,8 +459,13 @@ impl PyContext {
)
}
pub fn new_frame(&self, frame: Frame) -> PyObjectRef {
PyObject::new(PyObjectKind::Frame { frame: frame }, self.frame_type())
pub fn new_frame(&self, code: PyObjectRef, scope: PyObjectRef) -> PyObjectRef {
PyObject::new(
PyObjectKind::Frame {
frame: Frame::new(code, scope),
},
self.frame_type(),
)
}
pub fn new_property(&self, function: RustPyFunc) -> PyObjectRef {
@@ -811,7 +816,7 @@ pub enum PyObjectKind {
defaults: PyObjectRef,
},
Generator {
frame: Frame,
frame: PyObjectRef,
},
BoundMethod {
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 obj::objtype;
use pyobject::{DictProtocol, PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol};
use num_traits::ToPrimitive;
use std::env;
use std::mem;
use std::rc::Rc;
use std::{env, mem};
use vm::VirtualMachine;
/*
* The magic sys module.
@@ -15,12 +18,31 @@ fn argv(ctx: &PyContext) -> PyObjectRef {
ctx.new_list(argv)
}
fn getframe(vm: &mut VirtualMachine, _args: PyFuncArgs) -> PyResult {
if let Some(frame) = &vm.current_frame {
Ok(frame.clone())
} else {
panic!("Current frame is undefined!")
fn getframe(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(
vm,
args,
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 {

View File

@@ -10,7 +10,7 @@ use std::collections::hash_map::HashMap;
use super::builtins;
use super::bytecode;
use super::frame::Frame;
use super::frame::ExecutionResult;
use super::obj::objcode::copy_code;
use super::obj::objgenerator;
use super::obj::objiter;
@@ -35,7 +35,7 @@ pub struct VirtualMachine {
pub sys_module: PyObjectRef,
pub stdlib_inits: HashMap<String, stdlib::StdlibInitFunc>,
pub ctx: PyContext,
pub current_frame: Option<PyObjectRef>,
pub frames: Vec<PyObjectRef>,
}
impl VirtualMachine {
@@ -52,13 +52,32 @@ impl VirtualMachine {
sys_module: sysmod,
stdlib_inits,
ctx: ctx,
current_frame: None,
frames: vec![],
}
}
pub fn run_code_obj(&mut self, code: PyObjectRef, scope: PyObjectRef) -> PyResult {
let mut frame = Frame::new(code, scope);
frame.run_frame_full(self)
let frame = self.ctx.new_frame(code, scope);
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.
@@ -260,13 +279,13 @@ impl VirtualMachine {
self.fill_scope_from_args(&code_object, &scope, args, defaults)?;
// 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 code_object.is_generator {
objgenerator::new_generator(self, frame)
} else {
frame.run_frame_full(self)
self.run_frame_full(frame)
}
}