Skip to content

Commit 6979300

Browse files
committed
Start supporting wordcode.
1 parent fedc0ac commit 6979300

File tree

5 files changed

+72
-42
lines changed

5 files changed

+72
-42
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ A Python virtual machine, written in Rust.
2323

2424
## Dependencies
2525

26-
* CPython 3.6 (used as a parser and bytecode compiler). Older versions down to 3.4 should work, but their support is not tested.
26+
* CPython 3.6 (used as a parser and bytecode compiler).
2727
* [Rust](https://www.rust-lang.org/downloads.html)
2828
* [Cargo](https://crates.io/install)
2929

src/marshal/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,6 @@ pub fn check_magic(buf: &[u8]) -> bool {
1818
false
1919
}
2020
else {
21-
3310 <= version /* ≥ 3.4rc2 */ && version < 3390 /* < 3.7 */
21+
3379 <= version /* ≥ 3.6rc1 */ && version < 3390 /* < 3.7 */
2222
}
2323
}

src/processor/instructions.rs

Lines changed: 36 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ pub enum CmpOperator {
1818
}
1919

2020
impl CmpOperator {
21-
pub fn from_bytecode(n: u32) -> Self {
21+
pub fn from_bytecode(n: u8) -> Self {
2222
match n {
2323
0 => CmpOperator::Lt,
2424
1 => CmpOperator::Leq,
@@ -71,7 +71,8 @@ pub enum Instruction {
7171
LoadGlobal(usize),
7272
CallFunction(usize, usize), // nb_args, nb_kwargs
7373
RaiseVarargs(u16),
74-
MakeFunction(usize, usize, usize), // nb_default_args, nb_default_kwargs, nb_annot
74+
MakeFunction(bool, bool, bool, bool), // has_defaults, has_kwdefaults, has_annotations, has_closure
75+
BuildConstKeyMap(usize),
7576
}
7677

7778
#[derive(Debug)]
@@ -123,8 +124,12 @@ impl<'a, I> Iterator for InstructionDecoder<I> where I: Iterator<Item=&'a u8> {
123124
self.pending_nops -= 1;
124125
return Some(Instruction::Nop)
125126
};
126-
self.bytestream.next().map(|opcode| {
127-
match *opcode {
127+
let opcode = self.bytestream.next();
128+
let oparg = self.bytestream.next();
129+
if let (Some(opcode), Some(oparg)) = (opcode, oparg) {
130+
let opcode = *opcode;
131+
let oparg = *oparg;
132+
let inst = match opcode {
128133
1 => Instruction::PopTop,
129134
4 => Instruction::DupTop,
130135
25 => Instruction::BinarySubscr,
@@ -134,37 +139,35 @@ impl<'a, I> Iterator for InstructionDecoder<I> where I: Iterator<Item=&'a u8> {
134139
87 => Instruction::PopBlock,
135140
88 => Instruction::EndFinally,
136141
89 => Instruction::PopExcept,
137-
90 => Instruction::StoreName(self.read_argument() as usize),
138-
93 => Instruction::ForIter(self.read_argument() as usize),
139-
95 => Instruction::StoreAttr(self.read_argument() as usize),
140-
97 => Instruction::StoreGlobal(self.read_argument() as usize),
141-
100 => Instruction::LoadConst(self.read_argument() as usize),
142-
101 => Instruction::LoadName(self.read_argument() as usize),
143-
102 => Instruction::BuildTuple(self.read_argument() as usize),
144-
106 => Instruction::LoadAttr(self.read_argument() as usize),
145-
107 => Instruction::CompareOp(CmpOperator::from_bytecode(self.read_argument())),
146-
110 => Instruction::JumpForward(self.read_argument() as usize + 2), // +2, because JumpForward takes 3 bytes, and the relative address is computed from the next instruction.
147-
113 => Instruction::JumpAbsolute(self.read_argument() as usize),
148-
114 => Instruction::PopJumpIfFalse(self.read_argument() as usize),
149-
116 => Instruction::LoadGlobal(self.read_argument() as usize),
150-
120 => Instruction::SetupLoop(self.read_argument() as usize + 2),
151-
121 => Instruction::SetupExcept(self.read_argument() as usize + 2),
152-
124 => Instruction::LoadFast(self.read_argument() as usize),
153-
125 => Instruction::StoreFast(self.read_argument() as usize),
142+
90 => Instruction::StoreName(oparg as usize),
143+
93 => Instruction::ForIter(oparg as usize),
144+
95 => Instruction::StoreAttr(oparg as usize),
145+
97 => Instruction::StoreGlobal(oparg as usize),
146+
100 => Instruction::LoadConst(oparg as usize),
147+
101 => Instruction::LoadName(oparg as usize),
148+
102 => Instruction::BuildTuple(oparg as usize),
149+
106 => Instruction::LoadAttr(oparg as usize),
150+
107 => Instruction::CompareOp(CmpOperator::from_bytecode(oparg)),
151+
110 => Instruction::JumpForward(oparg as usize),
152+
113 => Instruction::JumpAbsolute(oparg as usize),
153+
114 => Instruction::PopJumpIfFalse(oparg as usize),
154+
116 => Instruction::LoadGlobal(oparg as usize),
155+
120 => Instruction::SetupLoop(oparg as usize + 1),
156+
121 => Instruction::SetupExcept(oparg as usize + 1),
157+
124 => Instruction::LoadFast(oparg as usize),
158+
125 => Instruction::StoreFast(oparg as usize),
154159
130 => Instruction::RaiseVarargs(self.read_argument() as u16),
155-
131 => Instruction::CallFunction(self.read_byte() as usize, self.read_byte() as usize),
156-
132 => {
157-
let arg = self.read_argument();
158-
let nb_pos = arg & 0xFF;
159-
let nb_kw = (arg >> 8) & 0xFF;
160-
//let nb_annot = (arg >> 16) & 0x7FF; // TODO
161-
let nb_annot = 0;
162-
Instruction::MakeFunction(nb_pos as usize, nb_kw as usize, nb_annot as usize)
163-
},
160+
131 => Instruction::CallFunction(oparg as usize, 0),
161+
132 => Instruction::MakeFunction(oparg & 0x01 != 0, oparg & 0x02 != 0, oparg & 0x04 != 0, oparg & 0x08 != 0),
162+
156 => Instruction::BuildConstKeyMap(oparg as usize),
164163
144 => { self.arg_prefix = Some(self.read_argument()); Instruction::Nop },
165-
_ => panic!(format!("Opcode not supported: {}", opcode)),
166-
}
167-
})
164+
_ => panic!(format!("Opcode not supported: {:?}", (opcode, oparg))),
165+
};
166+
Some(inst)
167+
}
168+
else {
169+
None
170+
}
168171
}
169172
}
170173

src/processor/mod.rs

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -523,7 +523,7 @@ fn run_code<EP: EnvProxy>(state: &mut State<EP>, call_stack: &mut Vec<Frame>) ->
523523
}
524524
call_function(state, call_stack, &func, args, kwargs)
525525
},
526-
Instruction::MakeFunction(0, nb_default_kwargs, 0) => {
526+
Instruction::MakeFunction(false, has_kwdefaults, false, false) => {
527527
// TODO: consume default arguments and annotations
528528
let obj = {
529529
let frame = call_stack.last_mut().unwrap();
@@ -540,18 +540,35 @@ fn run_code<EP: EnvProxy>(state: &mut State<EP>, call_stack: &mut Vec<Frame>) ->
540540
};
541541
let frame = call_stack.last_mut().unwrap();
542542
let code = pop_stack!(state, frame.var_stack);
543-
let raw_kwdefaults = py_unwrap!(state, frame.var_stack.pop_n_pairs(nb_default_kwargs), ProcessorError::StackTooSmall);
544543
let mut kwdefaults: HashMap<String, ObjectRef> = HashMap::new();
545-
kwdefaults.reserve(nb_default_kwargs);
546-
for (key, value) in raw_kwdefaults {
547-
match state.store.deref(&key).content {
548-
ObjectContent::String(ref s) => { kwdefaults.insert(s.clone(), value); },
549-
_ => panic!("Defaults' keys must be strings."),
544+
if has_kwdefaults {
545+
let obj = state.store.deref(&pop_stack!(state, frame.var_stack)).content.clone(); // TODO: clone only if necessary
546+
let raw_kwdefaults = match obj {
547+
ObjectContent::Dict(ref d) => d,
548+
_ => panic!("bad type for default kwd"),
549+
};
550+
kwdefaults.reserve(raw_kwdefaults.len());
551+
for &(ref key, ref value) in raw_kwdefaults {
552+
match state.store.deref(&key).content {
553+
ObjectContent::String(ref s) => { kwdefaults.insert(s.clone(), value.clone()); },
554+
_ => panic!("Defaults' keys must be strings."),
555+
}
550556
}
551557
}
552558
let func = state.primitive_objects.new_function(func_name, frame.object.module(&state.store), code, kwdefaults);
553559
frame.var_stack.push(state.store.allocate(func))
554560
},
561+
Instruction::BuildConstKeyMap(size) => {
562+
let frame = call_stack.last_mut().unwrap();
563+
let obj = state.store.deref(&pop_stack!(state, frame.var_stack)).content.clone(); // TODO: clone only if necessary
564+
let keys: Vec<ObjectRef> = match obj {
565+
ObjectContent::Tuple(ref v) => v.clone(),
566+
_ => panic!("bad BuildConstKeyMap keys argument."),
567+
};
568+
let values: Vec<ObjectRef> = frame.var_stack.peek(size).unwrap().iter().map(|r| (*r).clone()).collect();
569+
let dict = state.primitive_objects.new_dict(keys.into_iter().zip(values).collect());
570+
frame.var_stack.push(state.store.allocate(dict))
571+
}
555572
_ => panic!(format!("todo: instruction {:?}", instruction)),
556573
}
557574
};

src/varstack.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ pub trait VarStack : Debug {
99
fn push(&mut self, value: Self::Item);
1010
fn pop_all_and_get_n_last(&mut self, nb: usize) -> Option<Vec<Self::Item>>;
1111
fn pop_n_pairs(&mut self, nb: usize) -> Option<Vec<(Self::Item, Self::Item)>>;
12+
fn peek(&self, nb: usize) -> Option<Vec<&Self::Item>>;
1213
}
1314

1415
#[derive(Debug)]
@@ -75,4 +76,13 @@ impl<Item: Clone> VarStack for VectorVarStack<Item> where Item: Debug {
7576
pairs
7677
})
7778
}
79+
fn peek(&self, nb: usize) -> Option<Vec<&Self::Item>> {
80+
if nb > self.vector.len() {
81+
None
82+
}
83+
else {
84+
let length = self.vector.len();
85+
Some(self.vector[(length-nb)..length].iter().collect())
86+
}
87+
}
7888
}

0 commit comments

Comments
 (0)