Skip to content

Commit be1a2a4

Browse files
committed
Start writing processor. Add stack and basic sandbox.
1 parent 6e58fb3 commit be1a2a4

File tree

7 files changed

+213
-19
lines changed

7 files changed

+213
-19
lines changed

src/lib.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
mod marshal;
22
mod objects;
3-
//mod processor;
3+
mod processor;
4+
mod sandbox;
5+
mod stack;
46

57
use std::fmt;
68
use std::io;
@@ -26,7 +28,8 @@ pub fn run_module<R: io::Read>(reader: &mut R) -> Result<(), InterpreterError> {
2628
// TODO: do something with the content of the buffer
2729
let mut store = objects::ObjectStore::new();
2830
let module = try!(marshal::read_object(reader, &mut store).map_err(InterpreterError::Unmarshal));
29-
//processor::run_code_object(module, &mut references);
31+
let mut envproxy = sandbox::MockEnvProxy::new();
32+
processor::run_code_object(&mut envproxy, module, &mut store);
3033
Ok(())
3134
}
3235

src/marshal/mod.rs

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,41 +5,68 @@ use std::io;
55
use std::collections::HashSet;
66
use super::objects::{Code, ObjectContent, Object, ObjectRef, ObjectStore};
77
use self::common::Object as MarshalObject;
8+
use self::common::Code as MarshalCode;
89

910
macro_rules! translate_vector {
1011
( $e:expr, $map:ident, $store:ident ) => { $e.into_iter().map(|o| translate_object(o, $map, $store)).collect() }
1112
}
1213

13-
fn translate_object(marshal_object: MarshalObject, translation_map: &Vec<ObjectRef>, store: &mut ObjectStore) -> ObjectRef {
14+
macro_rules! translate_code_field {
15+
( $code:ident, $expected:ident, $field:ident, $map:ident, $store:ident, $error:expr ) => {
16+
match translate_object_content($code.$field, $map, $store) {
17+
ObjectContent::$expected(v) => v,
18+
_ => panic!($error),
19+
}
20+
};
21+
}
22+
23+
// TODO: more fields
24+
fn translate_code(c: MarshalCode, translation_map: &Vec<ObjectRef>, store: &mut ObjectStore) -> Code {
25+
let code = translate_code_field!(c, Bytes, code, translation_map, store, "Code.code object must be bytes.");
26+
let consts = translate_code_field!(c, Tuple, consts, translation_map, store, "Code.consts object must be a tuple.");
27+
let names = translate_code_field!(c, Tuple, names, translation_map, store, "Code.names object must be a tuple.");
28+
Code { code: code, consts: consts, names: names }
29+
}
30+
31+
fn translate_object_content(marshal_object: MarshalObject, translation_map: &Vec<ObjectRef>, store: &mut ObjectStore) -> ObjectContent {
1432
match marshal_object {
1533
MarshalObject::Hole => panic!("Remaining hole."),
16-
MarshalObject::None => store.allocate(ObjectContent::None),
17-
MarshalObject::False => store.allocate(ObjectContent::False),
18-
MarshalObject::True => store.allocate(ObjectContent::True),
19-
MarshalObject::Int(i) => store.allocate(ObjectContent::Int(i)),
20-
MarshalObject::String(s) => store.allocate(ObjectContent::String(s)),
21-
MarshalObject::Bytes(v) => store.allocate(ObjectContent::Bytes(v)),
34+
MarshalObject::None => ObjectContent::None,
35+
MarshalObject::False => ObjectContent::False,
36+
MarshalObject::True => ObjectContent::True,
37+
MarshalObject::Int(i) => ObjectContent::Int(i),
38+
MarshalObject::String(s) => ObjectContent::String(s),
39+
MarshalObject::Bytes(v) => ObjectContent::Bytes(v),
2240
MarshalObject::Tuple(v) => {
2341
let v = translate_vector!(v, translation_map, store);
24-
store.allocate(ObjectContent::Tuple(v))
42+
ObjectContent::Tuple(v)
2543
},
2644
MarshalObject::List(v) => {
2745
let v = translate_vector!(v, translation_map, store);
28-
store.allocate(ObjectContent::List(v))
46+
ObjectContent::List(v)
2947
},
3048
MarshalObject::Set(v) => {
3149
let v = translate_vector!(v, translation_map, store);
32-
store.allocate(ObjectContent::Set(v))
50+
ObjectContent::Set(v)
3351
},
3452
MarshalObject::FrozenSet(v) => {
3553
let v = translate_vector!(v, translation_map, store);
36-
store.allocate(ObjectContent::FrozenSet(v))
54+
ObjectContent::FrozenSet(v)
3755
},
3856
MarshalObject::Code(c) => {
39-
let code = translate_object(c.code, translation_map, store);
40-
store.allocate(ObjectContent::Code(Code { code: code})) // TODO: more fields
57+
ObjectContent::Code(translate_code(*c, translation_map, store))
4158
},
59+
MarshalObject::Ref(_) => panic!("For references, call translate_and_allocate_object.")
60+
}
61+
}
62+
63+
fn translate_object(marshal_object: MarshalObject, translation_map: &Vec<ObjectRef>, store: &mut ObjectStore) -> ObjectRef {
64+
match marshal_object {
4265
MarshalObject::Ref(i) => translation_map.get(i as usize).unwrap().clone(), // TODO: overflow check
66+
_ => {
67+
let obj_content = translate_object_content(marshal_object, translation_map, store);
68+
store.allocate(obj_content)
69+
},
4370
}
4471
}
4572

src/objects/mod.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
1+
use std::collections::HashSet;
12

23
#[derive(Debug)]
4+
#[derive(Clone)]
35
pub struct Code {/*
46
pub argcount: u32,
57
pub kwonlyargcount: u32,
68
pub nlocals: u32,
79
pub stacksize: u32,
810
pub flags: u32,*/
9-
pub code: ObjectRef,/*
10-
pub consts: Object,
11-
pub names: Object,
11+
pub code: Vec<u8>,
12+
pub consts: Vec<ObjectRef>,
13+
pub names: Vec<ObjectRef>,/*
1214
pub varnames: Object,
1315
pub freevars: Object,
1416
pub cellvars: Object,
@@ -35,7 +37,7 @@ pub enum ObjectContent {
3537

3638
#[derive(Debug)]
3739
pub struct Object {
38-
content: ObjectContent,
40+
pub content: ObjectContent,
3941
}
4042

4143
#[derive(Debug)]
@@ -59,4 +61,9 @@ impl ObjectStore {
5961
self.all_objects.push(Object { content: obj });
6062
obj_ref
6163
}
64+
65+
pub fn deref(&self, obj_ref: &ObjectRef) -> &Object {
66+
// TODO: check the reference is valid
67+
self.all_objects.get(obj_ref.index).unwrap()
68+
}
6269
}

src/processor/instructions.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,12 @@ use std::str::Bytes;
33
#[derive(PartialEq)]
44
#[derive(Debug)]
55
pub enum Instruction {
6+
PopTop,
67
ReturnValue,
8+
LoadConst(usize),
9+
LoadName(usize),
710
LoadFast(u16),
11+
CallFunction(u16),
812
}
913

1014
#[derive(Debug)]
@@ -19,6 +23,13 @@ impl<I> InstructionDecoder<I> where I: Iterator {
1923
}
2024

2125
impl<'a, I> InstructionDecoder<I> where I: Iterator<Item=&'a u8> {
26+
fn read_byte(&mut self) -> u8 {
27+
match (self.bytestream.next(), self.bytestream.next()) {
28+
(Some(b1), Some(b2)) => {
29+
((*b2 as u16) << 8) + (*b1 as u16)},
30+
_ => panic!("End of stream in the middle of an instruction."),
31+
}
32+
}
2233
fn read_argument(&mut self) -> u16 {
2334
match (self.bytestream.next(), self.bytestream.next()) {
2435
(Some(b1), Some(b2)) => {
@@ -34,8 +45,12 @@ impl<'a, I> Iterator for InstructionDecoder<I> where I: Iterator<Item=&'a u8> {
3445
fn next(&mut self) -> Option<Instruction> {
3546
self.bytestream.next().map(|opcode| {
3647
match *opcode {
48+
1 => Instruction::PopTop,
3749
83 => Instruction::ReturnValue,
50+
100 => Instruction::LoadConst(self.read_argument() as usize),
51+
101 => Instruction::LoadName(self.read_argument() as usize),
3852
124 => Instruction::LoadFast(self.read_argument()),
53+
131 => Instruction::CallFunction(self.read_byte(), self.read_byte()),
3954
_ => panic!(format!("Opcode not supported: {}", opcode)),
4055
}
4156
})

src/processor/mod.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,43 @@
11
pub mod instructions;
2+
3+
use super::objects::{Object, Code, ObjectStore, ObjectRef, ObjectContent};
4+
use super::sandbox::EnvProxy;
5+
use super::stack::{Stack, VectorStack};
6+
use self::instructions::Instruction;
7+
8+
pub enum ProcessorError {
9+
CircularReference,
10+
InvalidReference,
11+
NotACodeObject,
12+
CodeObjectIsNotBytes,
13+
InvalidProgramCounter,
14+
StackTooSmall,
15+
InvalidConstIndex,
16+
InvalidNameIndex,
17+
}
18+
19+
fn run_code<EP: EnvProxy>(envproxy: &mut EP, code: Code, store: &mut ObjectStore) -> Result<ObjectRef, ProcessorError> {
20+
let bytecode: Vec<u8> = code.code;
21+
let instructions: Vec<Instruction> = instructions::InstructionDecoder::new(bytecode.iter()).into_iter().collect();
22+
let mut program_counter = 0 as usize;
23+
let mut stack = VectorStack::new();
24+
while true {
25+
let instruction = try!(instructions.get(program_counter).ok_or(ProcessorError::InvalidProgramCounter));
26+
program_counter += 1;
27+
match *instruction {
28+
Instruction::ReturnValue => return Ok(try!(stack.pop().ok_or(ProcessorError::StackTooSmall))),
29+
Instruction::LoadConst(i) => stack.push(try!(code.names.get(i).ok_or(ProcessorError::InvalidConstIndex)).clone()),
30+
Instruction::LoadName(i) => stack.push(try!(code.names.get(i).ok_or(ProcessorError::InvalidNameIndex)).clone()),
31+
_ => panic!(format!("todo: instruction {:?}", *instruction)),
32+
}
33+
};
34+
panic!("Unreachable")
35+
}
36+
37+
pub fn run_code_object<EP: EnvProxy>(envproxy: &mut EP, module: ObjectRef, store: &mut ObjectStore) -> Result<ObjectRef, ProcessorError> {
38+
let code = match store.deref(&module).content {
39+
ObjectContent::Code(ref code) => code.clone(),
40+
_ => return Err(ProcessorError::NotACodeObject),
41+
};
42+
run_code(envproxy, code, store)
43+
}

src/sandbox/mod.rs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
use std::io;
2+
use std::sync::{Arc, Mutex};
3+
4+
/// Real environment (I/O, signals, …) or a mock
5+
pub trait EnvProxy {
6+
type Stdout: io::Write;
7+
fn stdout(&self) -> Self::Stdout;
8+
}
9+
10+
11+
12+
/// An EnvProxy that exposes the real environment
13+
pub struct RealEnvProxy {
14+
}
15+
16+
impl RealEnvProxy {
17+
pub fn new() -> RealEnvProxy {
18+
RealEnvProxy { }
19+
}
20+
}
21+
22+
impl EnvProxy for RealEnvProxy {
23+
type Stdout = io::Stdout;
24+
fn stdout(&self) -> Self::Stdout {
25+
io::stdout()
26+
}
27+
}
28+
29+
30+
31+
struct VectorWriter {
32+
vector: Arc<Mutex<Vec<u8>>>,
33+
}
34+
35+
impl VectorWriter {
36+
pub fn new(vector: Arc<Mutex<Vec<u8>>>) -> VectorWriter {
37+
VectorWriter { vector: vector }
38+
}
39+
}
40+
41+
impl io::Write for VectorWriter {
42+
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
43+
self.vector.lock().unwrap().extend(buf); // TODO: remove unwrap()
44+
Ok(buf.len())
45+
}
46+
fn flush(&mut self) -> io::Result<()> {
47+
Ok(())
48+
}
49+
}
50+
51+
pub struct MockEnvProxy {
52+
stdout_content: Arc<Mutex<Vec<u8>>>,
53+
}
54+
55+
impl MockEnvProxy {
56+
pub fn new() -> MockEnvProxy {
57+
MockEnvProxy { stdout_content: Arc::new(Mutex::new(vec![])) }
58+
}
59+
}
60+
61+
62+
impl EnvProxy for MockEnvProxy {
63+
type Stdout = VectorWriter;
64+
fn stdout(&self) -> Self::Stdout {
65+
VectorWriter::new(self.stdout_content.clone())
66+
}
67+
}

src/stack.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
pub trait Stack {
2+
type Item;
3+
4+
fn top(&self) -> Option<&Self::Item>;
5+
fn pop(&mut self) -> Option<Self::Item>;
6+
fn push(&mut self, value: Self::Item);
7+
}
8+
9+
pub struct VectorStack<Item: Sized> {
10+
vector: Vec<Item>
11+
}
12+
13+
impl<Item> VectorStack<Item> {
14+
pub fn new() -> VectorStack<Item> {
15+
VectorStack { vector: Vec::new() }
16+
}
17+
}
18+
19+
impl<Item> Stack for VectorStack<Item> {
20+
type Item = Item;
21+
22+
fn top(&self) -> Option<&Self::Item> {
23+
self.vector.last()
24+
}
25+
26+
fn pop(&mut self) -> Option<Self::Item> {
27+
self.vector.pop()
28+
}
29+
30+
fn push(&mut self, value: Self::Item) {
31+
self.vector.push(value)
32+
}
33+
}

0 commit comments

Comments
 (0)