mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 10:44:36 +08:00
Switch from 64-bit instruction enum to out-of-line arg values
This commit is contained in:
10 files changed
+1287
-796
No files matched your search
Generated
+1
-1
@@ -2002,8 +2002,8 @@ dependencies = [
|
||||
"lz4_flex",
|
||||
"num-bigint",
|
||||
"num-complex",
|
||||
"num_enum",
|
||||
"serde",
|
||||
"static_assertions",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
|
||||
+432
-327
File diff suppressed because it is too large.
Load diff
+143
-53
@@ -1,12 +1,47 @@
|
||||
use std::ops;
|
||||
|
||||
use crate::IndexSet;
|
||||
use rustpython_compiler_core::{CodeFlags, CodeObject, ConstantData, Instruction, Label, Location};
|
||||
use rustpython_compiler_core::{
|
||||
CodeFlags, CodeObject, CodeUnit, ConstantData, InstrDisplayContext, Instruction, Label,
|
||||
Location, OpArg,
|
||||
};
|
||||
|
||||
pub type BlockIdx = Label;
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub struct BlockIdx(pub u32);
|
||||
impl BlockIdx {
|
||||
pub const NULL: BlockIdx = BlockIdx(u32::MAX);
|
||||
const fn idx(self) -> usize {
|
||||
self.0 as usize
|
||||
}
|
||||
}
|
||||
impl ops::Index<BlockIdx> for [Block] {
|
||||
type Output = Block;
|
||||
fn index(&self, idx: BlockIdx) -> &Block {
|
||||
&self[idx.idx()]
|
||||
}
|
||||
}
|
||||
impl ops::IndexMut<BlockIdx> for [Block] {
|
||||
fn index_mut(&mut self, idx: BlockIdx) -> &mut Block {
|
||||
&mut self[idx.idx()]
|
||||
}
|
||||
}
|
||||
impl ops::Index<BlockIdx> for Vec<Block> {
|
||||
type Output = Block;
|
||||
fn index(&self, idx: BlockIdx) -> &Block {
|
||||
&self[idx.idx()]
|
||||
}
|
||||
}
|
||||
impl ops::IndexMut<BlockIdx> for Vec<Block> {
|
||||
fn index_mut(&mut self, idx: BlockIdx) -> &mut Block {
|
||||
&mut self[idx.idx()]
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct InstructionInfo {
|
||||
/// If the instruction has a Label argument, it's actually a BlockIdx, not a code offset
|
||||
pub instr: Instruction,
|
||||
pub arg: OpArg,
|
||||
pub target: BlockIdx,
|
||||
pub location: Location,
|
||||
}
|
||||
|
||||
@@ -21,7 +56,7 @@ impl Default for Block {
|
||||
fn default() -> Self {
|
||||
Block {
|
||||
instructions: Vec::new(),
|
||||
next: Label(u32::MAX),
|
||||
next: BlockIdx::NULL,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -45,13 +80,13 @@ pub struct CodeInfo {
|
||||
}
|
||||
impl CodeInfo {
|
||||
pub fn finalize_code(mut self, optimize: u8) -> CodeObject {
|
||||
let max_stackdepth = self.max_stackdepth();
|
||||
let cell2arg = self.cell2arg();
|
||||
|
||||
if optimize > 0 {
|
||||
self.dce();
|
||||
}
|
||||
|
||||
let max_stackdepth = self.max_stackdepth();
|
||||
let cell2arg = self.cell2arg();
|
||||
|
||||
let CodeInfo {
|
||||
flags,
|
||||
posonlyarg_count,
|
||||
@@ -61,7 +96,7 @@ impl CodeInfo {
|
||||
first_line_number,
|
||||
obj_name,
|
||||
|
||||
blocks,
|
||||
mut blocks,
|
||||
current_block: _,
|
||||
constants,
|
||||
name_cache,
|
||||
@@ -70,26 +105,50 @@ impl CodeInfo {
|
||||
freevar_cache,
|
||||
} = self;
|
||||
|
||||
let mut num_instructions = 0;
|
||||
let mut instructions = Vec::new();
|
||||
let mut locations = Vec::new();
|
||||
|
||||
let mut block_to_offset = vec![Label(0); blocks.len()];
|
||||
|
||||
for (idx, block) in iter_blocks(&blocks) {
|
||||
block_to_offset[idx.0 as usize] = Label(num_instructions as u32);
|
||||
num_instructions += block.instructions.len();
|
||||
}
|
||||
|
||||
let mut instructions = Vec::with_capacity(num_instructions);
|
||||
let mut locations = Vec::with_capacity(num_instructions);
|
||||
|
||||
for (_, block) in iter_blocks(&blocks) {
|
||||
for info in &block.instructions {
|
||||
let mut instr = info.instr.clone();
|
||||
if let Some(l) = instr.label_arg_mut() {
|
||||
*l = block_to_offset[l.0 as usize];
|
||||
loop {
|
||||
let mut num_instructions = 0;
|
||||
for (idx, block) in iter_blocks(&blocks) {
|
||||
block_to_offset[idx.idx()] = Label(num_instructions as u32);
|
||||
for instr in &block.instructions {
|
||||
num_instructions += instr.arg.instr_size()
|
||||
}
|
||||
instructions.push(instr);
|
||||
locations.push(info.location);
|
||||
}
|
||||
|
||||
instructions.reserve_exact(num_instructions);
|
||||
locations.reserve_exact(num_instructions);
|
||||
|
||||
let mut recompile_extended_arg = false;
|
||||
let mut next_block = BlockIdx(0);
|
||||
while next_block != BlockIdx::NULL {
|
||||
let block = &mut blocks[next_block];
|
||||
for info in &mut block.instructions {
|
||||
let (op, arg, target) = (info.instr, &mut info.arg, info.target);
|
||||
if target != BlockIdx::NULL {
|
||||
let new_arg = OpArg(block_to_offset[target.idx()].0);
|
||||
recompile_extended_arg |= new_arg.instr_size() != arg.instr_size();
|
||||
*arg = new_arg;
|
||||
}
|
||||
let (extras, lo_arg) = arg.split();
|
||||
locations.extend(std::iter::repeat(info.location).take(arg.instr_size()));
|
||||
instructions.extend(
|
||||
extras
|
||||
.map(|byte| CodeUnit::new(Instruction::ExtendedArg, byte))
|
||||
.chain([CodeUnit { op, arg: lo_arg }]),
|
||||
);
|
||||
}
|
||||
next_block = block.next;
|
||||
}
|
||||
|
||||
if !recompile_extended_arg {
|
||||
break;
|
||||
}
|
||||
|
||||
instructions.clear();
|
||||
locations.clear()
|
||||
}
|
||||
|
||||
CodeObject {
|
||||
@@ -166,40 +225,48 @@ impl CodeInfo {
|
||||
let mut stack = Vec::with_capacity(self.blocks.len());
|
||||
let mut startdepths = vec![u32::MAX; self.blocks.len()];
|
||||
startdepths[0] = 0;
|
||||
stack.push(Label(0));
|
||||
stack.push(BlockIdx(0));
|
||||
const DEBUG: bool = false;
|
||||
'process_blocks: while let Some(block) = stack.pop() {
|
||||
let mut depth = startdepths[block.0 as usize];
|
||||
let mut depth = startdepths[block.idx()];
|
||||
if DEBUG {
|
||||
eprintln!("===BLOCK {}===", block.0);
|
||||
}
|
||||
let block = &self.blocks[block.0 as usize];
|
||||
let block = &self.blocks[block];
|
||||
for i in &block.instructions {
|
||||
let instr = &i.instr;
|
||||
let effect = instr.stack_effect(false);
|
||||
let effect = instr.stack_effect(i.arg, false);
|
||||
if DEBUG {
|
||||
eprint!("{instr:?}: {depth} {effect:+} => ");
|
||||
let display_arg = if i.target == BlockIdx::NULL {
|
||||
i.arg
|
||||
} else {
|
||||
OpArg(i.target.0)
|
||||
};
|
||||
let instr_display = instr.display(display_arg, self);
|
||||
eprint!("{instr_display}: {depth} {effect:+} => ");
|
||||
}
|
||||
let new_depth = add_ui(depth, effect);
|
||||
let new_depth = depth.checked_add_signed(effect).unwrap();
|
||||
if DEBUG {
|
||||
eprintln!("{new_depth}");
|
||||
}
|
||||
if new_depth > maxdepth {
|
||||
maxdepth = new_depth
|
||||
}
|
||||
// we don't want to worry about Continue, it uses unwinding to jump to
|
||||
// its targets and as such the stack size is taken care of in frame.rs by setting
|
||||
// we don't want to worry about Break/Continue, they use unwinding to jump to
|
||||
// their targets and as such the stack size is taken care of in frame.rs by setting
|
||||
// it back to the level it was at when SetupLoop was run
|
||||
let jump_label = instr
|
||||
.label_arg()
|
||||
.filter(|_| !matches!(instr, Instruction::Continue { .. }));
|
||||
if let Some(&target_block) = jump_label {
|
||||
let effect = instr.stack_effect(true);
|
||||
let target_depth = add_ui(depth, effect);
|
||||
if i.target != BlockIdx::NULL
|
||||
&& !matches!(
|
||||
instr,
|
||||
Instruction::Continue { .. } | Instruction::Break { .. }
|
||||
)
|
||||
{
|
||||
let effect = instr.stack_effect(i.arg, true);
|
||||
let target_depth = depth.checked_add_signed(effect).unwrap();
|
||||
if target_depth > maxdepth {
|
||||
maxdepth = target_depth
|
||||
}
|
||||
stackdepth_push(&mut stack, &mut startdepths, target_block, target_depth);
|
||||
stackdepth_push(&mut stack, &mut startdepths, i.target, target_depth);
|
||||
}
|
||||
depth = new_depth;
|
||||
if instr.unconditional_branch() {
|
||||
@@ -215,23 +282,46 @@ impl CodeInfo {
|
||||
}
|
||||
}
|
||||
|
||||
fn stackdepth_push(stack: &mut Vec<Label>, startdepths: &mut [u32], target: Label, depth: u32) {
|
||||
let block_depth = &mut startdepths[target.0 as usize];
|
||||
impl InstrDisplayContext for CodeInfo {
|
||||
type Constant = ConstantData;
|
||||
fn get_constant(&self, i: usize) -> &ConstantData {
|
||||
&self.constants[i]
|
||||
}
|
||||
fn get_name(&self, i: usize) -> &str {
|
||||
self.name_cache[i].as_ref()
|
||||
}
|
||||
fn get_varname(&self, i: usize) -> &str {
|
||||
self.varname_cache[i].as_ref()
|
||||
}
|
||||
fn get_cellname(&self, i: usize) -> &str {
|
||||
self.cellvar_cache
|
||||
.get_index(i)
|
||||
.unwrap_or_else(|| &self.freevar_cache[i - self.cellvar_cache.len()])
|
||||
.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
fn stackdepth_push(
|
||||
stack: &mut Vec<BlockIdx>,
|
||||
startdepths: &mut [u32],
|
||||
target: BlockIdx,
|
||||
depth: u32,
|
||||
) {
|
||||
let block_depth = &mut startdepths[target.idx()];
|
||||
if *block_depth == u32::MAX || depth > *block_depth {
|
||||
*block_depth = depth;
|
||||
stack.push(target);
|
||||
}
|
||||
}
|
||||
|
||||
fn add_ui(a: u32, b: i32) -> u32 {
|
||||
if b < 0 {
|
||||
a - b.wrapping_abs() as u32
|
||||
} else {
|
||||
a + b as u32
|
||||
}
|
||||
}
|
||||
|
||||
fn iter_blocks(blocks: &[Block]) -> impl Iterator<Item = (BlockIdx, &Block)> + '_ {
|
||||
let get_idx = move |i: BlockIdx| blocks.get(i.0 as usize).map(|b| (i, b));
|
||||
std::iter::successors(get_idx(Label(0)), move |(_, b)| get_idx(b.next)) // if b.next is u32::MAX that's the end
|
||||
let mut next = BlockIdx(0);
|
||||
std::iter::from_fn(move || {
|
||||
if next == BlockIdx::NULL {
|
||||
return None;
|
||||
}
|
||||
let (idx, b) = (next, &blocks[next]);
|
||||
next = b.next;
|
||||
Some((idx, b))
|
||||
})
|
||||
}
|
||||
Generated
+10
-10
@@ -2,23 +2,23 @@
|
||||
source: compiler/codegen/src/compile.rs
|
||||
expression: "compile_exec(\"\\\nfor stop_exc in (StopIteration('spam'), StopAsyncIteration('ham')):\n with self.subTest(type=type(stop_exc)):\n try:\n async with woohoo():\n raise stop_exc\n except Exception as ex:\n self.assertIs(ex, stop_exc)\n else:\n self.fail(f'{stop_exc} was suppressed')\n\")"
|
||||
---
|
||||
1 0 SetupLoop (69)
|
||||
1 0 SetupLoop
|
||||
1 LoadNameAny (0, StopIteration)
|
||||
2 LoadConst ("spam")
|
||||
3 CallFunctionPositional (1)
|
||||
3 CallFunctionPositional(1)
|
||||
4 LoadNameAny (1, StopAsyncIteration)
|
||||
5 LoadConst ("ham")
|
||||
6 CallFunctionPositional (1)
|
||||
7 BuildTuple (2, false)
|
||||
6 CallFunctionPositional(1)
|
||||
7 BuildTuple (2)
|
||||
8 GetIter
|
||||
>> 9 ForIter (68)
|
||||
10 StoreLocal (2, stop_exc)
|
||||
|
||||
2 11 LoadNameAny (3, self)
|
||||
12 LoadMethod (subTest)
|
||||
12 LoadMethod (4, subTest)
|
||||
13 LoadNameAny (5, type)
|
||||
14 LoadNameAny (2, stop_exc)
|
||||
15 CallFunctionPositional (1)
|
||||
15 CallFunctionPositional(1)
|
||||
16 LoadConst (("type"))
|
||||
17 CallMethodKeyword (1)
|
||||
18 SetupWith (65)
|
||||
@@ -27,7 +27,7 @@ expression: "compile_exec(\"\\\nfor stop_exc in (StopIteration('spam'), StopAsyn
|
||||
3 20 SetupExcept (40)
|
||||
|
||||
4 21 LoadNameAny (6, woohoo)
|
||||
22 CallFunctionPositional (0)
|
||||
22 CallFunctionPositional(0)
|
||||
23 BeforeAsyncWith
|
||||
24 GetAwaitable
|
||||
25 LoadConst (None)
|
||||
@@ -55,7 +55,7 @@ expression: "compile_exec(\"\\\nfor stop_exc in (StopIteration('spam'), StopAsyn
|
||||
44 StoreLocal (8, ex)
|
||||
|
||||
7 45 LoadNameAny (3, self)
|
||||
46 LoadMethod (assertIs)
|
||||
46 LoadMethod (9, assertIs)
|
||||
47 LoadNameAny (8, ex)
|
||||
48 LoadNameAny (2, stop_exc)
|
||||
49 CallMethodPositional (2)
|
||||
@@ -65,7 +65,7 @@ expression: "compile_exec(\"\\\nfor stop_exc in (StopIteration('spam'), StopAsyn
|
||||
>> 53 Raise (Reraise)
|
||||
|
||||
9 >> 54 LoadNameAny (3, self)
|
||||
55 LoadMethod (fail)
|
||||
55 LoadMethod (10, fail)
|
||||
56 LoadConst ("")
|
||||
57 LoadNameAny (2, stop_exc)
|
||||
58 FormatValue (None)
|
||||
@@ -80,6 +80,6 @@ expression: "compile_exec(\"\\\nfor stop_exc in (StopIteration('spam'), StopAsyn
|
||||
66 WithCleanupFinish
|
||||
67 Jump (9)
|
||||
>> 68 PopBlock
|
||||
>> 69 LoadConst (None)
|
||||
69 LoadConst (None)
|
||||
70 ReturnValue
|
||||
|
||||
@@ -15,6 +15,6 @@ itertools = "0.10.3"
|
||||
lz4_flex = "0.9.2"
|
||||
num-bigint = { version = "0.4.3", features = ["serde"] }
|
||||
num-complex = { version = "0.4.0", features = ["serde"] }
|
||||
num_enum = "0.5.7"
|
||||
serde = { version = "1.0.136", features = ["derive"] }
|
||||
static_assertions = "1.1.0"
|
||||
thiserror = "1.0"
|
||||
+476
-222
File diff suppressed because it is too large.
Load diff
+2
-3
@@ -6,8 +6,7 @@ use rustpython_parser::{
|
||||
};
|
||||
|
||||
pub use rustpython_codegen::compile::CompileOpts;
|
||||
pub use rustpython_compiler_core::CodeObject;
|
||||
pub use rustpython_compiler_core::{BaseError as CompileErrorBody, Mode};
|
||||
pub use rustpython_compiler_core::{BaseError as CompileErrorBody, CodeObject, Mode};
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum CompileErrorType {
|
||||
@@ -29,7 +28,7 @@ pub fn compile(
|
||||
source: &str,
|
||||
mode: compile::Mode,
|
||||
source_path: String,
|
||||
opts: compile::CompileOpts,
|
||||
opts: CompileOpts,
|
||||
) -> Result<CodeObject, CompileError> {
|
||||
let mut ast = match parser::parse(source, mode.into(), &source_path) {
|
||||
Ok(x) => x,
|
||||
|
||||
+20
-13
@@ -2,7 +2,7 @@ use cranelift::prelude::*;
|
||||
use num_traits::cast::ToPrimitive;
|
||||
use rustpython_compiler_core::{
|
||||
self as bytecode, BinaryOperator, BorrowedConstant, CodeObject, ComparisonOperator,
|
||||
Instruction, Label, UnaryOperator,
|
||||
Instruction, Label, OpArg, OpArgState, UnaryOperator,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
|
||||
@@ -155,7 +155,9 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> {
|
||||
// label_targets alone
|
||||
let label_targets = bytecode.label_targets();
|
||||
|
||||
let mut arg_state = OpArgState::default();
|
||||
for (offset, instruction) in bytecode.instructions.iter().enumerate() {
|
||||
let (instruction, arg) = arg_state.get(*instruction);
|
||||
let label = Label(offset as u32);
|
||||
if label_targets.contains(&label) {
|
||||
let block = self.get_or_create_block(label);
|
||||
@@ -175,7 +177,7 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> {
|
||||
continue;
|
||||
}
|
||||
|
||||
self.add_instruction(instruction, &bytecode.constants)?;
|
||||
self.add_instruction(instruction, arg, &bytecode.constants)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -214,15 +216,17 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> {
|
||||
|
||||
pub fn add_instruction<C: bytecode::Constant>(
|
||||
&mut self,
|
||||
instruction: &Instruction,
|
||||
instruction: Instruction,
|
||||
arg: OpArg,
|
||||
constants: &[C],
|
||||
) -> Result<(), JitCompileError> {
|
||||
match instruction {
|
||||
Instruction::ExtendedArg => Ok(()),
|
||||
Instruction::JumpIfFalse { target } => {
|
||||
let cond = self.stack.pop().ok_or(JitCompileError::BadBytecode)?;
|
||||
|
||||
let val = self.boolean_val(cond)?;
|
||||
let then_block = self.get_or_create_block(*target);
|
||||
let then_block = self.get_or_create_block(target.get(arg));
|
||||
self.builder.ins().brz(val, then_block, &[]);
|
||||
|
||||
let block = self.builder.create_block();
|
||||
@@ -235,7 +239,7 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> {
|
||||
let cond = self.stack.pop().ok_or(JitCompileError::BadBytecode)?;
|
||||
|
||||
let val = self.boolean_val(cond)?;
|
||||
let then_block = self.get_or_create_block(*target);
|
||||
let then_block = self.get_or_create_block(target.get(arg));
|
||||
self.builder.ins().brnz(val, then_block, &[]);
|
||||
|
||||
let block = self.builder.create_block();
|
||||
@@ -245,13 +249,13 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> {
|
||||
Ok(())
|
||||
}
|
||||
Instruction::Jump { target } => {
|
||||
let target_block = self.get_or_create_block(*target);
|
||||
let target_block = self.get_or_create_block(target.get(arg));
|
||||
self.builder.ins().jump(target_block, &[]);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Instruction::LoadFast(idx) => {
|
||||
let local = self.variables[*idx as usize]
|
||||
let local = self.variables[idx.get(arg) as usize]
|
||||
.as_ref()
|
||||
.ok_or(JitCompileError::BadBytecode)?;
|
||||
self.stack.push(JitValue::from_type_and_value(
|
||||
@@ -262,13 +266,13 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> {
|
||||
}
|
||||
Instruction::StoreFast(idx) => {
|
||||
let val = self.stack.pop().ok_or(JitCompileError::BadBytecode)?;
|
||||
self.store_variable(*idx, val)
|
||||
self.store_variable(idx.get(arg), val)
|
||||
}
|
||||
Instruction::LoadConst { idx } => {
|
||||
self.load_const(constants[*idx as usize].borrow_constant())
|
||||
self.load_const(constants[idx.get(arg) as usize].borrow_constant())
|
||||
}
|
||||
Instruction::BuildTuple { unpack, size } if !unpack => {
|
||||
let elements = self.pop_multiple(*size as usize);
|
||||
Instruction::BuildTuple { size } => {
|
||||
let elements = self.pop_multiple(size.get(arg) as usize);
|
||||
self.stack.push(JitValue::Tuple(elements));
|
||||
Ok(())
|
||||
}
|
||||
@@ -280,7 +284,7 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> {
|
||||
_ => return Err(JitCompileError::NotSupported),
|
||||
};
|
||||
|
||||
if elements.len() != *size as usize {
|
||||
if elements.len() != size.get(arg) as usize {
|
||||
return Err(JitCompileError::NotSupported);
|
||||
}
|
||||
|
||||
@@ -306,6 +310,7 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> {
|
||||
Ok(())
|
||||
}
|
||||
Instruction::CompareOperation { op, .. } => {
|
||||
let op = op.get(arg);
|
||||
// the rhs is popped off first
|
||||
let b = self.stack.pop().ok_or(JitCompileError::BadBytecode)?;
|
||||
let a = self.stack.pop().ok_or(JitCompileError::BadBytecode)?;
|
||||
@@ -347,6 +352,7 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> {
|
||||
}
|
||||
}
|
||||
Instruction::UnaryOperation { op, .. } => {
|
||||
let op = op.get(arg);
|
||||
let a = self.stack.pop().ok_or(JitCompileError::BadBytecode)?;
|
||||
match (op, a) {
|
||||
(UnaryOperator::Minus, JitValue::Int(val)) => {
|
||||
@@ -371,6 +377,7 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> {
|
||||
}
|
||||
}
|
||||
Instruction::BinaryOperation { op } | Instruction::BinaryOperationInplace { op } => {
|
||||
let op = op.get(arg);
|
||||
// the rhs is popped off first
|
||||
let b = self.stack.pop().ok_or(JitCompileError::BadBytecode)?;
|
||||
let a = self.stack.pop().ok_or(JitCompileError::BadBytecode)?;
|
||||
@@ -406,7 +413,7 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> {
|
||||
TrapCode::User(CustomTrapCode::NegativeShiftCount as u16),
|
||||
);
|
||||
|
||||
let out = if *op == BinaryOperator::Lshift {
|
||||
let out = if op == BinaryOperator::Lshift {
|
||||
self.builder.ins().ishl(a, b)
|
||||
} else {
|
||||
self.builder.ins().sshr(a, b)
|
||||
|
||||
+16
-11
@@ -1,6 +1,7 @@
|
||||
use rustpython_compiler_core::{CodeObject, ConstantData, Instruction};
|
||||
use rustpython_compiler_core::{CodeObject, ConstantData, Instruction, OpArg, OpArgState};
|
||||
use rustpython_jit::{CompiledCode, JitType};
|
||||
use std::collections::HashMap;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Function {
|
||||
@@ -62,27 +63,30 @@ impl StackMachine {
|
||||
}
|
||||
|
||||
pub fn run(&mut self, code: CodeObject) {
|
||||
for instruction in code.instructions.into_vec() {
|
||||
if self.process_instruction(instruction, &code.constants, &code.names) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let mut oparg_state = OpArgState::default();
|
||||
code.instructions.iter().try_for_each(|&word| {
|
||||
let (instruction, arg) = oparg_state.get(word);
|
||||
self.process_instruction(instruction, arg, &code.constants, &code.names)
|
||||
});
|
||||
}
|
||||
|
||||
fn process_instruction(
|
||||
&mut self,
|
||||
instruction: Instruction,
|
||||
arg: OpArg,
|
||||
constants: &[ConstantData],
|
||||
names: &[String],
|
||||
) -> bool {
|
||||
) -> ControlFlow<()> {
|
||||
match instruction {
|
||||
Instruction::LoadConst { idx } => {
|
||||
let idx = idx.get(arg);
|
||||
self.stack.push(constants[idx as usize].clone().into())
|
||||
}
|
||||
Instruction::LoadNameAny(idx) => self
|
||||
.stack
|
||||
.push(StackValue::String(names[idx as usize].clone())),
|
||||
.push(StackValue::String(names[idx.get(arg) as usize].clone())),
|
||||
Instruction::StoreLocal(idx) => {
|
||||
let idx = idx.get(arg);
|
||||
self.locals
|
||||
.insert(names[idx as usize].clone(), self.stack.pop().unwrap());
|
||||
}
|
||||
@@ -93,7 +97,7 @@ impl StackMachine {
|
||||
}
|
||||
Instruction::BuildMap { size, .. } => {
|
||||
let mut map = HashMap::new();
|
||||
for _ in 0..size {
|
||||
for _ in 0..size.get(arg) {
|
||||
let value = self.stack.pop().unwrap();
|
||||
let name = if let Some(StackValue::String(name)) = self.stack.pop() {
|
||||
name
|
||||
@@ -135,13 +139,14 @@ impl StackMachine {
|
||||
let i = self.stack.len() - 3;
|
||||
self.stack[i..].rotate_right(1);
|
||||
}
|
||||
Instruction::ReturnValue => return true,
|
||||
Instruction::ReturnValue => return ControlFlow::Break(()),
|
||||
Instruction::ExtendedArg => {}
|
||||
_ => unimplemented!(
|
||||
"instruction {:?} isn't yet supported in py_function!",
|
||||
instruction
|
||||
),
|
||||
}
|
||||
false
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
|
||||
pub fn get_function(&self, name: &str) -> Function {
|
||||
|
||||
+186
-155
@@ -36,9 +36,7 @@ struct Block {
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
enum BlockType {
|
||||
Loop {
|
||||
break_target: bytecode::Label,
|
||||
},
|
||||
Loop,
|
||||
TryExcept {
|
||||
handler: bytecode::Label,
|
||||
},
|
||||
@@ -72,7 +70,7 @@ enum UnwindReason {
|
||||
|
||||
// NoWorries,
|
||||
/// We are unwinding blocks, since we hit break
|
||||
Break,
|
||||
Break { target: bytecode::Label },
|
||||
|
||||
/// We are unwinding blocks since we hit a continue statements.
|
||||
Continue { target: bytecode::Label },
|
||||
@@ -131,7 +129,7 @@ pub enum ExecutionResult {
|
||||
}
|
||||
|
||||
/// A valid execution result, or an exception
|
||||
pub type FrameResult = PyResult<Option<ExecutionResult>>;
|
||||
type FrameResult = PyResult<Option<ExecutionResult>>;
|
||||
|
||||
impl Frame {
|
||||
pub(crate) fn new(
|
||||
@@ -351,13 +349,16 @@ impl ExecutingFrame<'_> {
|
||||
flame_guard!(format!("Frame::run({})", self.code.obj_name));
|
||||
// Execute until return or exception:
|
||||
let instrs = &self.code.instructions;
|
||||
let mut arg_state = bytecode::OpArgState::default();
|
||||
loop {
|
||||
let idx = self.lasti() as usize;
|
||||
self.update_lasti(|i| *i += 1);
|
||||
let instr = &instrs[idx];
|
||||
let result = self.execute_instruction(instr, vm);
|
||||
let bytecode::CodeUnit { op, arg } = instrs[idx];
|
||||
let arg = arg_state.extend(arg);
|
||||
let mut do_extend_arg = false;
|
||||
let result = self.execute_instruction(op, arg, &mut do_extend_arg, vm);
|
||||
match result {
|
||||
Ok(None) => continue,
|
||||
Ok(None) => {}
|
||||
Ok(Some(value)) => {
|
||||
break Ok(value);
|
||||
}
|
||||
@@ -387,24 +388,25 @@ impl ExecutingFrame<'_> {
|
||||
}
|
||||
|
||||
match handle_exception(self, exception, idx, vm) {
|
||||
Ok(None) => continue,
|
||||
Ok(Some(result)) => {
|
||||
break Ok(result);
|
||||
}
|
||||
Err(exception) => {
|
||||
// TODO: append line number to traceback?
|
||||
// traceback.append();
|
||||
break Err(exception);
|
||||
}
|
||||
Ok(None) => {}
|
||||
Ok(Some(result)) => break Ok(result),
|
||||
// TODO: append line number to traceback?
|
||||
// traceback.append();
|
||||
Err(exception) => break Err(exception),
|
||||
}
|
||||
}
|
||||
}
|
||||
if !do_extend_arg {
|
||||
arg_state.reset()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn yield_from_target(&self) -> Option<&PyObject> {
|
||||
if let Some(bytecode::Instruction::YieldFrom) =
|
||||
self.code.instructions.get(self.lasti() as usize)
|
||||
if let Some(bytecode::CodeUnit {
|
||||
op: bytecode::Instruction::YieldFrom,
|
||||
..
|
||||
}) = self.code.instructions.get(self.lasti() as usize)
|
||||
{
|
||||
Some(self.last_value_ref())
|
||||
} else {
|
||||
@@ -478,7 +480,9 @@ impl ExecutingFrame<'_> {
|
||||
#[inline(always)]
|
||||
fn execute_instruction(
|
||||
&mut self,
|
||||
instruction: &bytecode::Instruction,
|
||||
instruction: bytecode::Instruction,
|
||||
arg: bytecode::OpArg,
|
||||
extend_arg: &mut bool,
|
||||
vm: &VirtualMachine,
|
||||
) -> FrameResult {
|
||||
vm.check_signals()?;
|
||||
@@ -505,16 +509,16 @@ impl ExecutingFrame<'_> {
|
||||
|
||||
match instruction {
|
||||
bytecode::Instruction::LoadConst { idx } => {
|
||||
self.push_value(self.code.constants[*idx as usize].clone().into());
|
||||
self.push_value(self.code.constants[idx.get(arg) as usize].clone().into());
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::ImportName { idx } => {
|
||||
self.import(vm, Some(self.code.names[*idx as usize].to_owned()))
|
||||
self.import(vm, Some(self.code.names[idx.get(arg) as usize].to_owned()))
|
||||
}
|
||||
bytecode::Instruction::ImportNameless => self.import(vm, None),
|
||||
bytecode::Instruction::ImportStar => self.import_star(vm),
|
||||
bytecode::Instruction::ImportFrom { idx } => {
|
||||
let obj = self.import_from(vm, *idx)?;
|
||||
let obj = self.import_from(vm, idx.get(arg))?;
|
||||
self.push_value(obj);
|
||||
Ok(None)
|
||||
}
|
||||
@@ -529,7 +533,7 @@ impl ExecutingFrame<'_> {
|
||||
format!("local variable '{varname}' referenced before assignment",),
|
||||
)
|
||||
}
|
||||
let idx = *idx as usize;
|
||||
let idx = idx.get(arg) as usize;
|
||||
let x = self.fastlocals.lock()[idx]
|
||||
.clone()
|
||||
.ok_or_else(|| reference_error(self.code.varnames[idx], vm))?;
|
||||
@@ -537,7 +541,7 @@ impl ExecutingFrame<'_> {
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::LoadNameAny(idx) => {
|
||||
let name = self.code.names[*idx as usize];
|
||||
let name = self.code.names[idx.get(arg) as usize];
|
||||
let result = self.locals.mapping().subscript(name, vm);
|
||||
match result {
|
||||
Ok(x) => self.push_value(x),
|
||||
@@ -549,13 +553,13 @@ impl ExecutingFrame<'_> {
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::LoadGlobal(idx) => {
|
||||
let name = &self.code.names[*idx as usize];
|
||||
let name = &self.code.names[idx.get(arg) as usize];
|
||||
let x = self.load_global_or_builtin(name, vm)?;
|
||||
self.push_value(x);
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::LoadDeref(i) => {
|
||||
let i = *i as usize;
|
||||
let i = i.get(arg) as usize;
|
||||
let x = self.cells_frees[i]
|
||||
.get()
|
||||
.ok_or_else(|| self.unbound_cell_exception(i, vm))?;
|
||||
@@ -563,7 +567,7 @@ impl ExecutingFrame<'_> {
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::LoadClassDeref(i) => {
|
||||
let i = *i as usize;
|
||||
let i = i.get(arg) as usize;
|
||||
let name = self.code.freevars[i - self.code.cellvars.len()];
|
||||
let value = self.locals.mapping().subscript(name, vm).ok();
|
||||
self.push_value(match value {
|
||||
@@ -576,11 +580,11 @@ impl ExecutingFrame<'_> {
|
||||
}
|
||||
bytecode::Instruction::StoreFast(idx) => {
|
||||
let value = self.pop_value();
|
||||
self.fastlocals.lock()[*idx as usize] = Some(value);
|
||||
self.fastlocals.lock()[idx.get(arg) as usize] = Some(value);
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::StoreLocal(idx) => {
|
||||
let name = self.code.names[*idx as usize];
|
||||
let name = self.code.names[idx.get(arg) as usize];
|
||||
let value = self.pop_value();
|
||||
self.locals.mapping().ass_subscript(name, Some(value), vm)?;
|
||||
Ok(None)
|
||||
@@ -588,20 +592,20 @@ impl ExecutingFrame<'_> {
|
||||
bytecode::Instruction::StoreGlobal(idx) => {
|
||||
let value = self.pop_value();
|
||||
self.globals
|
||||
.set_item(self.code.names[*idx as usize], value, vm)?;
|
||||
.set_item(self.code.names[idx.get(arg) as usize], value, vm)?;
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::StoreDeref(i) => {
|
||||
let value = self.pop_value();
|
||||
self.cells_frees[*i as usize].set(Some(value));
|
||||
self.cells_frees[i.get(arg) as usize].set(Some(value));
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::DeleteFast(idx) => {
|
||||
self.fastlocals.lock()[*idx as usize] = None;
|
||||
self.fastlocals.lock()[idx.get(arg) as usize] = None;
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::DeleteLocal(idx) => {
|
||||
let name = self.code.names[*idx as usize];
|
||||
let name = self.code.names[idx.get(arg) as usize];
|
||||
let res = self.locals.mapping().ass_subscript(name, None, vm);
|
||||
|
||||
match res {
|
||||
@@ -614,7 +618,7 @@ impl ExecutingFrame<'_> {
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::DeleteGlobal(idx) => {
|
||||
let name = self.code.names[*idx as usize];
|
||||
let name = self.code.names[idx.get(arg) as usize];
|
||||
match self.globals.del_item(name, vm) {
|
||||
Ok(()) => {}
|
||||
Err(e) if e.fast_isinstance(vm.ctx.exceptions.key_error) => {
|
||||
@@ -625,11 +629,11 @@ impl ExecutingFrame<'_> {
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::DeleteDeref(i) => {
|
||||
self.cells_frees[*i as usize].set(None);
|
||||
self.cells_frees[i.get(arg) as usize].set(None);
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::LoadClosure(i) => {
|
||||
let value = self.cells_frees[*i as usize].clone();
|
||||
let value = self.cells_frees[i.get(arg) as usize].clone();
|
||||
self.push_value(value.into());
|
||||
Ok(None)
|
||||
}
|
||||
@@ -662,7 +666,7 @@ impl ExecutingFrame<'_> {
|
||||
bytecode::Instruction::Rotate3 => self.execute_rotate(3),
|
||||
bytecode::Instruction::BuildString { size } => {
|
||||
let s = self
|
||||
.pop_multiple(*size as usize)
|
||||
.pop_multiple(size.get(arg) as usize)
|
||||
.as_slice()
|
||||
.iter()
|
||||
.map(|pyobj| pyobj.payload::<PyStr>().unwrap().as_ref())
|
||||
@@ -671,40 +675,54 @@ impl ExecutingFrame<'_> {
|
||||
self.push_value(str_obj.into());
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::BuildList { size, unpack } => {
|
||||
let elements = self.get_elements(vm, *size as usize, *unpack)?;
|
||||
bytecode::Instruction::BuildList { size } => {
|
||||
let elements = self.pop_multiple(size.get(arg) as usize).collect();
|
||||
let list_obj = vm.ctx.new_list(elements);
|
||||
self.push_value(list_obj.into());
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::BuildSet { size, unpack } => {
|
||||
bytecode::Instruction::BuildListUnpack { size } => {
|
||||
let elements = self.unpack_elements(vm, size.get(arg) as usize)?;
|
||||
let list_obj = vm.ctx.new_list(elements);
|
||||
self.push_value(list_obj.into());
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::BuildSet { size } => {
|
||||
let set = PySet::new_ref(&vm.ctx);
|
||||
{
|
||||
let elements = self.pop_multiple(*size as usize);
|
||||
if *unpack {
|
||||
for element in elements {
|
||||
vm.map_iterable_object(&element, |x| set.add(x, vm))??;
|
||||
}
|
||||
} else {
|
||||
for element in elements {
|
||||
set.add(element, vm)?;
|
||||
}
|
||||
for element in self.pop_multiple(size.get(arg) as usize) {
|
||||
set.add(element, vm)?;
|
||||
}
|
||||
}
|
||||
self.push_value(set.into());
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::BuildTuple { size, unpack } => {
|
||||
let elements = self.get_elements(vm, *size as usize, *unpack)?;
|
||||
bytecode::Instruction::BuildSetUnpack { size } => {
|
||||
let set = PySet::new_ref(&vm.ctx);
|
||||
{
|
||||
for element in self.pop_multiple(size.get(arg) as usize) {
|
||||
vm.map_iterable_object(&element, |x| set.add(x, vm))??;
|
||||
}
|
||||
}
|
||||
self.push_value(set.into());
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::BuildTuple { size } => {
|
||||
let elements = self.pop_multiple(size.get(arg) as usize).collect();
|
||||
let list_obj = vm.ctx.new_tuple(elements);
|
||||
self.push_value(list_obj.into());
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::BuildMap {
|
||||
size,
|
||||
unpack,
|
||||
for_call,
|
||||
} => self.execute_build_map(vm, *size, *unpack, *for_call),
|
||||
bytecode::Instruction::BuildTupleUnpack { size } => {
|
||||
let elements = self.unpack_elements(vm, size.get(arg) as usize)?;
|
||||
let list_obj = vm.ctx.new_tuple(elements);
|
||||
self.push_value(list_obj.into());
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::BuildMap { size } => self.execute_build_map(vm, size.get(arg)),
|
||||
bytecode::Instruction::BuildMapForCall { size } => {
|
||||
self.execute_build_map_for_call(vm, size.get(arg))
|
||||
}
|
||||
bytecode::Instruction::DictUpdate => {
|
||||
let other = self.pop_value();
|
||||
let dict = self
|
||||
@@ -714,10 +732,12 @@ impl ExecutingFrame<'_> {
|
||||
dict.merge_object(other, vm)?;
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::BuildSlice { step } => self.execute_build_slice(vm, *step),
|
||||
bytecode::Instruction::BuildSlice { step } => {
|
||||
self.execute_build_slice(vm, step.get(arg))
|
||||
}
|
||||
bytecode::Instruction::ListAppend { i } => {
|
||||
let item = self.pop_value();
|
||||
let obj = self.nth_value(*i);
|
||||
let obj = self.nth_value(i.get(arg));
|
||||
let list: &Py<PyList> = unsafe {
|
||||
// SAFETY: trust compiler
|
||||
obj.downcast_unchecked_ref()
|
||||
@@ -727,7 +747,7 @@ impl ExecutingFrame<'_> {
|
||||
}
|
||||
bytecode::Instruction::SetAdd { i } => {
|
||||
let item = self.pop_value();
|
||||
let obj = self.nth_value(*i);
|
||||
let obj = self.nth_value(i.get(arg));
|
||||
let set: &Py<PySet> = unsafe {
|
||||
// SAFETY: trust compiler
|
||||
obj.downcast_unchecked_ref()
|
||||
@@ -738,7 +758,7 @@ impl ExecutingFrame<'_> {
|
||||
bytecode::Instruction::MapAdd { i } => {
|
||||
let value = self.pop_value();
|
||||
let key = self.pop_value();
|
||||
let obj = self.nth_value(*i);
|
||||
let obj = self.nth_value(i.get(arg));
|
||||
let dict: &Py<PyDict> = unsafe {
|
||||
// SAFETY: trust compiler
|
||||
obj.downcast_unchecked_ref()
|
||||
@@ -746,16 +766,16 @@ impl ExecutingFrame<'_> {
|
||||
dict.set_item(&*key, value, vm)?;
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::BinaryOperation { op } => self.execute_binop(vm, *op),
|
||||
bytecode::Instruction::BinaryOperation { op } => self.execute_binop(vm, op.get(arg)),
|
||||
bytecode::Instruction::BinaryOperationInplace { op } => {
|
||||
self.execute_binop_inplace(vm, *op)
|
||||
self.execute_binop_inplace(vm, op.get(arg))
|
||||
}
|
||||
bytecode::Instruction::LoadAttr { idx } => self.load_attr(vm, *idx),
|
||||
bytecode::Instruction::StoreAttr { idx } => self.store_attr(vm, *idx),
|
||||
bytecode::Instruction::DeleteAttr { idx } => self.delete_attr(vm, *idx),
|
||||
bytecode::Instruction::UnaryOperation { ref op } => self.execute_unop(vm, op),
|
||||
bytecode::Instruction::TestOperation { ref op } => self.execute_test(vm, op),
|
||||
bytecode::Instruction::CompareOperation { op } => self.execute_compare(vm, *op),
|
||||
bytecode::Instruction::LoadAttr { idx } => self.load_attr(vm, idx.get(arg)),
|
||||
bytecode::Instruction::StoreAttr { idx } => self.store_attr(vm, idx.get(arg)),
|
||||
bytecode::Instruction::DeleteAttr { idx } => self.delete_attr(vm, idx.get(arg)),
|
||||
bytecode::Instruction::UnaryOperation { op } => self.execute_unop(vm, op.get(arg)),
|
||||
bytecode::Instruction::TestOperation { op } => self.execute_test(vm, op.get(arg)),
|
||||
bytecode::Instruction::CompareOperation { op } => self.execute_compare(vm, op.get(arg)),
|
||||
bytecode::Instruction::ReturnValue => {
|
||||
let value = self.pop_value();
|
||||
self.unwind_blocks(vm, UnwindReason::Returning { value })
|
||||
@@ -771,18 +791,20 @@ impl ExecutingFrame<'_> {
|
||||
}
|
||||
bytecode::Instruction::YieldFrom => self.execute_yield_from(vm),
|
||||
bytecode::Instruction::SetupAnnotation => self.setup_annotations(vm),
|
||||
bytecode::Instruction::SetupLoop { break_target } => {
|
||||
self.push_block(BlockType::Loop {
|
||||
break_target: *break_target,
|
||||
});
|
||||
bytecode::Instruction::SetupLoop => {
|
||||
self.push_block(BlockType::Loop);
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::SetupExcept { handler } => {
|
||||
self.push_block(BlockType::TryExcept { handler: *handler });
|
||||
self.push_block(BlockType::TryExcept {
|
||||
handler: handler.get(arg),
|
||||
});
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::SetupFinally { handler } => {
|
||||
self.push_block(BlockType::Finally { handler: *handler });
|
||||
self.push_block(BlockType::Finally {
|
||||
handler: handler.get(arg),
|
||||
});
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::EnterFinally => {
|
||||
@@ -819,7 +841,9 @@ impl ExecutingFrame<'_> {
|
||||
)?;
|
||||
let exit = context_manager.get_attr(identifier!(vm, __exit__), vm)?;
|
||||
self.push_value(exit);
|
||||
self.push_block(BlockType::Finally { handler: *end });
|
||||
self.push_block(BlockType::Finally {
|
||||
handler: end.get(arg),
|
||||
});
|
||||
self.push_value(enter_res);
|
||||
Ok(None)
|
||||
}
|
||||
@@ -835,7 +859,9 @@ impl ExecutingFrame<'_> {
|
||||
}
|
||||
bytecode::Instruction::SetupAsyncWith { end } => {
|
||||
let enter_res = self.pop_value();
|
||||
self.push_block(BlockType::Finally { handler: *end });
|
||||
self.push_block(BlockType::Finally {
|
||||
handler: end.get(arg),
|
||||
});
|
||||
self.push_value(enter_res);
|
||||
Ok(None)
|
||||
}
|
||||
@@ -938,23 +964,25 @@ impl ExecutingFrame<'_> {
|
||||
Err(exc.downcast().unwrap())
|
||||
}
|
||||
}
|
||||
bytecode::Instruction::ForIter { target } => self.execute_for_iter(vm, *target),
|
||||
bytecode::Instruction::MakeFunction(flags) => self.execute_make_function(vm, *flags),
|
||||
bytecode::Instruction::ForIter { target } => self.execute_for_iter(vm, target.get(arg)),
|
||||
bytecode::Instruction::MakeFunction(flags) => {
|
||||
self.execute_make_function(vm, flags.get(arg))
|
||||
}
|
||||
bytecode::Instruction::CallFunctionPositional { nargs } => {
|
||||
let args = self.collect_positional_args(*nargs);
|
||||
let args = self.collect_positional_args(nargs.get(arg));
|
||||
self.execute_call(args, vm)
|
||||
}
|
||||
bytecode::Instruction::CallFunctionKeyword { nargs } => {
|
||||
let args = self.collect_keyword_args(*nargs);
|
||||
let args = self.collect_keyword_args(nargs.get(arg));
|
||||
self.execute_call(args, vm)
|
||||
}
|
||||
bytecode::Instruction::CallFunctionEx { has_kwargs } => {
|
||||
let args = self.collect_ex_args(vm, *has_kwargs)?;
|
||||
let args = self.collect_ex_args(vm, has_kwargs.get(arg))?;
|
||||
self.execute_call(args, vm)
|
||||
}
|
||||
bytecode::Instruction::LoadMethod { idx } => {
|
||||
let obj = self.pop_value();
|
||||
let method_name = self.code.names[*idx as usize];
|
||||
let method_name = self.code.names[idx.get(arg) as usize];
|
||||
let method = PyMethod::get(obj, method_name.to_owned(), vm)?;
|
||||
let (target, is_method, func) = match method {
|
||||
PyMethod::Function { target, func } => (target, true, func),
|
||||
@@ -968,48 +996,61 @@ impl ExecutingFrame<'_> {
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::CallMethodPositional { nargs } => {
|
||||
let args = self.collect_positional_args(*nargs);
|
||||
let args = self.collect_positional_args(nargs.get(arg));
|
||||
self.execute_method_call(args, vm)
|
||||
}
|
||||
bytecode::Instruction::CallMethodKeyword { nargs } => {
|
||||
let args = self.collect_keyword_args(*nargs);
|
||||
let args = self.collect_keyword_args(nargs.get(arg));
|
||||
self.execute_method_call(args, vm)
|
||||
}
|
||||
bytecode::Instruction::CallMethodEx { has_kwargs } => {
|
||||
let args = self.collect_ex_args(vm, *has_kwargs)?;
|
||||
let args = self.collect_ex_args(vm, has_kwargs.get(arg))?;
|
||||
self.execute_method_call(args, vm)
|
||||
}
|
||||
bytecode::Instruction::Jump { target } => {
|
||||
self.jump(*target);
|
||||
self.jump(target.get(arg));
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::JumpIfTrue { target } => self.jump_if(vm, *target, true),
|
||||
bytecode::Instruction::JumpIfFalse { target } => self.jump_if(vm, *target, false),
|
||||
bytecode::Instruction::JumpIfTrue { target } => self.jump_if(vm, target.get(arg), true),
|
||||
bytecode::Instruction::JumpIfFalse { target } => {
|
||||
self.jump_if(vm, target.get(arg), false)
|
||||
}
|
||||
bytecode::Instruction::JumpIfTrueOrPop { target } => {
|
||||
self.jump_if_or_pop(vm, *target, true)
|
||||
self.jump_if_or_pop(vm, target.get(arg), true)
|
||||
}
|
||||
bytecode::Instruction::JumpIfFalseOrPop { target } => {
|
||||
self.jump_if_or_pop(vm, *target, false)
|
||||
self.jump_if_or_pop(vm, target.get(arg), false)
|
||||
}
|
||||
|
||||
bytecode::Instruction::Raise { kind } => self.execute_raise(vm, *kind),
|
||||
bytecode::Instruction::Raise { kind } => self.execute_raise(vm, kind.get(arg)),
|
||||
|
||||
bytecode::Instruction::Break { target: _ } => {
|
||||
self.unwind_blocks(vm, UnwindReason::Break)
|
||||
}
|
||||
bytecode::Instruction::Continue { target } => {
|
||||
self.unwind_blocks(vm, UnwindReason::Continue { target: *target })
|
||||
}
|
||||
bytecode::Instruction::Break { target } => self.unwind_blocks(
|
||||
vm,
|
||||
UnwindReason::Break {
|
||||
target: target.get(arg),
|
||||
},
|
||||
),
|
||||
bytecode::Instruction::Continue { target } => self.unwind_blocks(
|
||||
vm,
|
||||
UnwindReason::Continue {
|
||||
target: target.get(arg),
|
||||
},
|
||||
),
|
||||
bytecode::Instruction::PrintExpr => self.print_expr(vm),
|
||||
bytecode::Instruction::LoadBuildClass => {
|
||||
self.push_value(vm.builtins.get_attr(identifier!(vm, __build_class__), vm)?);
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::UnpackSequence { size } => self.unpack_sequence(*size, vm),
|
||||
bytecode::Instruction::UnpackEx { before, after } => {
|
||||
self.execute_unpack_ex(vm, *before, *after)
|
||||
bytecode::Instruction::UnpackSequence { size } => {
|
||||
self.unpack_sequence(size.get(arg), vm)
|
||||
}
|
||||
bytecode::Instruction::UnpackEx { args } => {
|
||||
let args = args.get(arg);
|
||||
self.execute_unpack_ex(vm, args.before, args.after)
|
||||
}
|
||||
bytecode::Instruction::FormatValue { conversion } => {
|
||||
self.format_value(conversion.get(arg), vm)
|
||||
}
|
||||
bytecode::Instruction::FormatValue { conversion } => self.format_value(*conversion, vm),
|
||||
bytecode::Instruction::PopException {} => {
|
||||
let block = self.pop_block();
|
||||
if let BlockType::ExceptHandler { prev_exc } = block.typ {
|
||||
@@ -1021,7 +1062,11 @@ impl ExecutingFrame<'_> {
|
||||
}
|
||||
bytecode::Instruction::Reverse { amount } => {
|
||||
let stack_len = self.state.stack.len();
|
||||
self.state.stack[stack_len - *amount as usize..stack_len].reverse();
|
||||
self.state.stack[stack_len - amount.get(arg) as usize..stack_len].reverse();
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::ExtendedArg => {
|
||||
*extend_arg = true;
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
@@ -1037,23 +1082,13 @@ impl ExecutingFrame<'_> {
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "flame-it", flame("Frame"))]
|
||||
fn get_elements(
|
||||
&mut self,
|
||||
vm: &VirtualMachine,
|
||||
size: usize,
|
||||
unpack: bool,
|
||||
) -> PyResult<Vec<PyObjectRef>> {
|
||||
let elements = self.pop_multiple(size);
|
||||
if unpack {
|
||||
let mut result = Vec::<PyObjectRef>::new();
|
||||
for element in elements {
|
||||
let items: Vec<_> = element.try_to_value(vm)?;
|
||||
result.extend(items);
|
||||
}
|
||||
Ok(result)
|
||||
} else {
|
||||
Ok(elements.collect())
|
||||
fn unpack_elements(&mut self, vm: &VirtualMachine, size: usize) -> PyResult<Vec<PyObjectRef>> {
|
||||
let mut result = Vec::<PyObjectRef>::new();
|
||||
for element in self.pop_multiple(size) {
|
||||
let items: Vec<_> = element.try_to_value(vm)?;
|
||||
result.extend(items);
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "flame-it", flame("Frame"))]
|
||||
@@ -1127,10 +1162,10 @@ impl ExecutingFrame<'_> {
|
||||
// First unwind all existing blocks on the block stack:
|
||||
while let Some(block) = self.current_block() {
|
||||
match block.typ {
|
||||
BlockType::Loop { break_target } => match reason {
|
||||
UnwindReason::Break => {
|
||||
BlockType::Loop => match reason {
|
||||
UnwindReason::Break { target } => {
|
||||
self.pop_block();
|
||||
self.jump(break_target);
|
||||
self.jump(target);
|
||||
return Ok(None);
|
||||
}
|
||||
UnwindReason::Continue { target } => {
|
||||
@@ -1215,38 +1250,34 @@ impl ExecutingFrame<'_> {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn execute_build_map(
|
||||
&mut self,
|
||||
vm: &VirtualMachine,
|
||||
size: u32,
|
||||
unpack: bool,
|
||||
for_call: bool,
|
||||
) -> FrameResult {
|
||||
fn execute_build_map(&mut self, vm: &VirtualMachine, size: u32) -> FrameResult {
|
||||
let size = size as usize;
|
||||
let map_obj = vm.ctx.new_dict();
|
||||
if unpack {
|
||||
for obj in self.pop_multiple(size) {
|
||||
// Take all key-value pairs from the dict:
|
||||
let dict: PyDictRef = obj.downcast().map_err(|obj| {
|
||||
vm.new_type_error(format!("'{}' object is not a mapping", obj.class().name()))
|
||||
})?;
|
||||
for (key, value) in dict {
|
||||
#[allow(clippy::collapsible_if)]
|
||||
if for_call {
|
||||
if map_obj.contains_key(&*key, vm) {
|
||||
let key_repr = &key.repr(vm)?;
|
||||
let msg = format!(
|
||||
"got multiple values for keyword argument {}",
|
||||
key_repr.as_str()
|
||||
);
|
||||
return Err(vm.new_type_error(msg));
|
||||
}
|
||||
}
|
||||
map_obj.set_item(&*key, value, vm)?;
|
||||
for (key, value) in self.pop_multiple(2 * size).tuples() {
|
||||
map_obj.set_item(&*key, value, vm)?;
|
||||
}
|
||||
|
||||
self.push_value(map_obj.into());
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn execute_build_map_for_call(&mut self, vm: &VirtualMachine, size: u32) -> FrameResult {
|
||||
let size = size as usize;
|
||||
let map_obj = vm.ctx.new_dict();
|
||||
for obj in self.pop_multiple(size) {
|
||||
// Take all key-value pairs from the dict:
|
||||
let dict: PyDictRef = obj.downcast().map_err(|obj| {
|
||||
vm.new_type_error(format!("'{}' object is not a mapping", obj.class().name()))
|
||||
})?;
|
||||
for (key, value) in dict {
|
||||
if map_obj.contains_key(&*key, vm) {
|
||||
let key_repr = &key.repr(vm)?;
|
||||
let msg = format!(
|
||||
"got multiple values for keyword argument {}",
|
||||
key_repr.as_str()
|
||||
);
|
||||
return Err(vm.new_type_error(msg));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (key, value) in self.pop_multiple(2 * size).tuples() {
|
||||
map_obj.set_item(&*key, value, vm)?;
|
||||
}
|
||||
}
|
||||
@@ -1632,9 +1663,9 @@ impl ExecutingFrame<'_> {
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "flame-it", flame("Frame"))]
|
||||
fn execute_unop(&mut self, vm: &VirtualMachine, op: &bytecode::UnaryOperator) -> FrameResult {
|
||||
fn execute_unop(&mut self, vm: &VirtualMachine, op: bytecode::UnaryOperator) -> FrameResult {
|
||||
let a = self.pop_value();
|
||||
let value = match *op {
|
||||
let value = match op {
|
||||
bytecode::UnaryOperator::Minus => vm._neg(&a)?,
|
||||
bytecode::UnaryOperator::Plus => vm._pos(&a)?,
|
||||
bytecode::UnaryOperator::Invert => vm._invert(&a)?,
|
||||
@@ -1759,10 +1790,10 @@ impl ExecutingFrame<'_> {
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "flame-it", flame("Frame"))]
|
||||
fn execute_test(&mut self, vm: &VirtualMachine, op: &bytecode::TestOperator) -> FrameResult {
|
||||
fn execute_test(&mut self, vm: &VirtualMachine, op: bytecode::TestOperator) -> FrameResult {
|
||||
let b = self.pop_value();
|
||||
let a = self.pop_value();
|
||||
let value = match *op {
|
||||
let value = match op {
|
||||
bytecode::TestOperator::Is => a.is(&b),
|
||||
bytecode::TestOperator::IsNot => !a.is(&b),
|
||||
bytecode::TestOperator::In => self._in(vm, a, b)?,
|
||||
|
||||
Reference in new issue
Block a user