Skip to content

Commit ee86229

Browse files
committed
Keep a stack of frames on the VM.
1 parent 96c1c5a commit ee86229

File tree

5 files changed

+63
-31
lines changed

5 files changed

+63
-31
lines changed

tests/snippets/getframe.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
def test_function():
1010
x = 17
1111
assert sys._getframe().f_locals is not locals_dict
12-
assert sys._getframe().f_locals['x'] == 17
12+
assert sys._getframe(0).f_locals['x'] == 17
13+
assert sys._getframe(1).f_locals['foo'] == 'bar'
1314

1415
test_function()
1516

@@ -18,3 +19,8 @@ def __init__(self):
1819
assert sys._getframe().f_locals['self'] == self
1920

2021
TestClass()
22+
23+
try:
24+
sys._getframe(100)
25+
except ValueError:
26+
pass

vm/src/frame.rs

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ extern crate rustpython_parser;
33
use self::rustpython_parser::ast;
44
use std::collections::hash_map::HashMap;
55
use std::fmt;
6-
use std::mem;
76
use std::path::PathBuf;
87

98
use super::builtins;
@@ -82,22 +81,13 @@ impl Frame {
8281
}
8382
}
8483

85-
pub fn run_frame_full(&mut self, vm: &mut VirtualMachine) -> PyResult {
86-
match self.run_frame(vm)? {
87-
ExecutionResult::Return(value) => Ok(value),
88-
_ => panic!("Got unexpected result from function"),
89-
}
90-
}
91-
92-
pub fn run_frame(&mut self, vm: &mut VirtualMachine) -> Result<ExecutionResult, PyObjectRef> {
84+
pub fn run(&mut self, vm: &mut VirtualMachine) -> Result<ExecutionResult, PyObjectRef> {
9385
let filename = if let Some(source_path) = &self.code.source_path {
9486
source_path.to_string()
9587
} else {
9688
"<unknown>".to_string()
9789
};
9890

99-
let prev_frame = mem::replace(&mut vm.current_frame, Some(vm.ctx.new_frame(self.clone())));
100-
10191
// This is the name of the object being run:
10292
let run_obj_name = &self.code.obj_name.to_string();
10393

@@ -146,7 +136,6 @@ impl Frame {
146136
}
147137
};
148138

149-
vm.current_frame = prev_frame;
150139
value
151140
}
152141

vm/src/obj/objgenerator.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ fn generator_send(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
4848
fn send(vm: &mut VirtualMachine, gen: &PyObjectRef, value: &PyObjectRef) -> PyResult {
4949
if let PyObjectKind::Generator { ref mut frame } = gen.borrow_mut().kind {
5050
frame.push_value(value.clone());
51-
match frame.run_frame(vm)? {
51+
match vm.run_frame(frame.clone())? {
5252
ExecutionResult::Yield(value) => Ok(value),
5353
ExecutionResult::Return(_value) => {
5454
// Stop iteration!

vm/src/sysmodule.rs

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1+
use super::obj::objint;
2+
use super::obj::objtype;
3+
use super::pyobject::{DictProtocol, PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol};
4+
use super::vm::VirtualMachine;
15
use num_bigint::ToBigInt;
2-
use obj::objtype;
3-
use pyobject::{DictProtocol, PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol};
6+
use num_traits::ToPrimitive;
7+
use std::env;
48
use std::rc::Rc;
5-
use std::{env, mem};
6-
use vm::VirtualMachine;
79

810
/*
911
* The magic sys module.
@@ -15,12 +17,31 @@ fn argv(ctx: &PyContext) -> PyObjectRef {
1517
ctx.new_list(argv)
1618
}
1719

18-
fn getframe(vm: &mut VirtualMachine, _args: PyFuncArgs) -> PyResult {
19-
if let Some(frame) = &vm.current_frame {
20-
Ok(frame.clone())
21-
} else {
22-
panic!("Current frame is undefined!")
23-
}
20+
fn getframe(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
21+
arg_check!(
22+
vm,
23+
args,
24+
required = [],
25+
optional = [(offset, Some(vm.ctx.int_type()))]
26+
);
27+
let idx = match offset {
28+
Some(int) => {
29+
if let Some(offset) = objint::get_value(int).to_usize() {
30+
if offset > vm.frames.len() - 1 {
31+
return Err(vm.new_value_error("call stack is not deep enough".to_string()));
32+
}
33+
offset
34+
} else {
35+
0
36+
}
37+
}
38+
None => 0,
39+
};
40+
41+
let idx = vm.frames.len() - idx - 1;
42+
43+
let frame = &vm.frames[idx];
44+
Ok(frame.clone())
2445
}
2546

2647
fn sys_getrefcount(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {

vm/src/vm.rs

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ use std::collections::hash_map::HashMap;
1010

1111
use super::builtins;
1212
use super::bytecode;
13-
use super::frame::Frame;
13+
use super::frame::{ExecutionResult, Frame};
1414
use super::obj::objcode::copy_code;
15+
use super::obj::objframe;
1516
use super::obj::objgenerator;
1617
use super::obj::objiter;
1718
use super::obj::objsequence;
@@ -35,7 +36,7 @@ pub struct VirtualMachine {
3536
pub sys_module: PyObjectRef,
3637
pub stdlib_inits: HashMap<String, stdlib::StdlibInitFunc>,
3738
pub ctx: PyContext,
38-
pub current_frame: Option<PyObjectRef>,
39+
pub frames: Vec<PyObjectRef>,
3940
}
4041

4142
impl VirtualMachine {
@@ -52,13 +53,28 @@ impl VirtualMachine {
5253
sys_module: sysmod,
5354
stdlib_inits,
5455
ctx: ctx,
55-
current_frame: None,
56+
frames: vec![],
5657
}
5758
}
5859

5960
pub fn run_code_obj(&mut self, code: PyObjectRef, scope: PyObjectRef) -> PyResult {
60-
let mut frame = Frame::new(code, scope);
61-
frame.run_frame_full(self)
61+
self.run_frame_full(Frame::new(code, scope))
62+
}
63+
64+
pub fn run_frame_full(&mut self, frame: Frame) -> PyResult {
65+
match self.run_frame(frame)? {
66+
ExecutionResult::Return(value) => Ok(value),
67+
_ => panic!("Got unexpected result from function"),
68+
}
69+
}
70+
71+
pub fn run_frame(&mut self, frame: Frame) -> Result<ExecutionResult, PyObjectRef> {
72+
let frame = self.ctx.new_frame(frame);
73+
self.frames.push(frame.clone());
74+
let mut frame = objframe::get_value(&frame);
75+
let result = frame.run(self);
76+
self.frames.pop();
77+
result
6278
}
6379

6480
/// Create a new python string object.
@@ -260,13 +276,13 @@ impl VirtualMachine {
260276
self.fill_scope_from_args(&code_object, &scope, args, defaults)?;
261277

262278
// Construct frame:
263-
let mut frame = Frame::new(code.clone(), scope);
279+
let frame = Frame::new(code.clone(), scope);
264280

265281
// If we have a generator, create a new generator
266282
if code_object.is_generator {
267283
objgenerator::new_generator(self, frame)
268284
} else {
269-
frame.run_frame_full(self)
285+
self.run_frame_full(frame)
270286
}
271287
}
272288

0 commit comments

Comments
 (0)