mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
Merge pull request #2365 from RustPython/coolreader18/optimize-bytecode-format
Optimize the size of Instruction
This commit is contained in:
44
Cargo.lock
generated
44
Cargo.lock
generated
@@ -755,26 +755,6 @@ version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
|
||||
|
||||
[[package]]
|
||||
name = "fehler"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d5729fe49ba028cd550747b6e62cd3d841beccab5390aa398538c31a2d983635"
|
||||
dependencies = [
|
||||
"fehler-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fehler-macros"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ccb5acb1045ebbfa222e2c50679e392a71dd77030b78fb0189f2d9c5974400f9"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fixedbitset"
|
||||
version = "0.2.0"
|
||||
@@ -1129,16 +1109,13 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lz-fear"
|
||||
version = "0.1.1"
|
||||
name = "lz4_flex"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06aad1ce45e4ccf7a8d7d43e0c3ad38dc5d2255174a5f29a3c39d961fbc6181d"
|
||||
checksum = "2e7bea5a3a7bb3c040adc89eadadee33c3d39371b20dd980c952dd2642867b99"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"byteorder",
|
||||
"fehler",
|
||||
"thiserror",
|
||||
"twox-hash",
|
||||
"quick-error",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1769,7 +1746,7 @@ dependencies = [
|
||||
"bitflags",
|
||||
"bstr",
|
||||
"itertools",
|
||||
"lz-fear",
|
||||
"lz4_flex",
|
||||
"num-bigint",
|
||||
"num-complex",
|
||||
"serde",
|
||||
@@ -1814,6 +1791,7 @@ dependencies = [
|
||||
"itertools",
|
||||
"log",
|
||||
"num-complex",
|
||||
"num-traits",
|
||||
"rustpython-ast",
|
||||
"rustpython-bytecode",
|
||||
"rustpython-parser",
|
||||
@@ -2394,16 +2372,6 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "twox-hash"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04f8ab788026715fa63b31960869617cba39117e520eb415b0139543e325ab59"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.12.0"
|
||||
|
||||
@@ -11,7 +11,7 @@ license = "MIT"
|
||||
[dependencies]
|
||||
bincode = "1.1"
|
||||
bitflags = "1.1"
|
||||
lz-fear = "0.1"
|
||||
lz4_flex = "0.4"
|
||||
num-bigint = { version = "0.3", features = ["serde"] }
|
||||
num-complex = { version = "0.3", features = ["serde"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
|
||||
@@ -117,15 +117,12 @@ pub struct CodeObject<C: Constant = ConstantData> {
|
||||
bitflags! {
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct CodeFlags: u16 {
|
||||
const HAS_DEFAULTS = 0x01;
|
||||
const HAS_KW_ONLY_DEFAULTS = 0x02;
|
||||
const HAS_ANNOTATIONS = 0x04;
|
||||
const NEW_LOCALS = 0x08;
|
||||
const IS_GENERATOR = 0x10;
|
||||
const IS_COROUTINE = 0x20;
|
||||
const HAS_VARARGS = 0x40;
|
||||
const HAS_VARKEYWORDS = 0x80;
|
||||
const IS_OPTIMIZED = 0x0100;
|
||||
const NEW_LOCALS = 0x01;
|
||||
const IS_GENERATOR = 0x02;
|
||||
const IS_COROUTINE = 0x04;
|
||||
const HAS_VARARGS = 0x08;
|
||||
const HAS_VARKEYWORDS = 0x10;
|
||||
const IS_OPTIMIZED = 0x20;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,8 +142,8 @@ impl CodeFlags {
|
||||
#[derive(Serialize, Debug, Deserialize, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
|
||||
#[repr(transparent)]
|
||||
// XXX: if you add a new instruction that stores a Label, make sure to add it in
|
||||
// compile::CodeInfo::finalize_code and CodeObject::label_targets
|
||||
pub struct Label(pub usize);
|
||||
// Instruction::label_arg{,_mut}
|
||||
pub struct Label(pub u32);
|
||||
impl fmt::Display for Label {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.0.fmt(f)
|
||||
@@ -156,6 +153,8 @@ impl fmt::Display for Label {
|
||||
/// Transforms a value prior to formatting it.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum ConversionFlag {
|
||||
/// No conversion
|
||||
None,
|
||||
/// Converts by calling `str(<value>)`.
|
||||
Str,
|
||||
/// Converts by calling `ascii(<value>)`.
|
||||
@@ -164,16 +163,22 @@ pub enum ConversionFlag {
|
||||
Repr,
|
||||
}
|
||||
|
||||
pub type NameIdx = usize;
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum RaiseKind {
|
||||
Reraise,
|
||||
Raise,
|
||||
RaiseCause,
|
||||
}
|
||||
|
||||
pub type NameIdx = u32;
|
||||
|
||||
/// A Single bytecode instruction.
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Instruction {
|
||||
Import {
|
||||
name_idx: Option<NameIdx>,
|
||||
symbols_idx: Vec<NameIdx>,
|
||||
level: usize,
|
||||
ImportName {
|
||||
idx: NameIdx,
|
||||
},
|
||||
ImportNameless,
|
||||
ImportStar,
|
||||
ImportFrom {
|
||||
idx: NameIdx,
|
||||
@@ -203,14 +208,16 @@ pub enum Instruction {
|
||||
},
|
||||
LoadConst {
|
||||
/// index into constants vec
|
||||
idx: usize,
|
||||
idx: u32,
|
||||
},
|
||||
UnaryOperation {
|
||||
op: UnaryOperator,
|
||||
},
|
||||
BinaryOperation {
|
||||
op: BinaryOperator,
|
||||
inplace: bool,
|
||||
},
|
||||
BinaryOperationInplace {
|
||||
op: BinaryOperator,
|
||||
},
|
||||
LoadAttr {
|
||||
idx: NameIdx,
|
||||
@@ -220,11 +227,13 @@ pub enum Instruction {
|
||||
},
|
||||
Pop,
|
||||
Rotate {
|
||||
amount: usize,
|
||||
amount: u32,
|
||||
},
|
||||
Duplicate,
|
||||
GetIter,
|
||||
Continue,
|
||||
Continue {
|
||||
target: Label,
|
||||
},
|
||||
Break,
|
||||
Jump {
|
||||
target: Label,
|
||||
@@ -247,9 +256,15 @@ pub enum Instruction {
|
||||
JumpIfFalseOrPop {
|
||||
target: Label,
|
||||
},
|
||||
MakeFunction,
|
||||
CallFunction {
|
||||
typ: CallType,
|
||||
MakeFunction(MakeFunctionFlags),
|
||||
CallFunctionPositional {
|
||||
nargs: u32,
|
||||
},
|
||||
CallFunctionKeyword {
|
||||
nargs: u32,
|
||||
},
|
||||
CallFunctionEx {
|
||||
has_kwargs: bool,
|
||||
},
|
||||
ForIter {
|
||||
target: Label,
|
||||
@@ -259,7 +274,6 @@ pub enum Instruction {
|
||||
YieldFrom,
|
||||
SetupAnnotation,
|
||||
SetupLoop {
|
||||
start: Label,
|
||||
end: Label,
|
||||
},
|
||||
|
||||
@@ -292,56 +306,57 @@ pub enum Instruction {
|
||||
WithCleanupFinish,
|
||||
PopBlock,
|
||||
Raise {
|
||||
argc: usize,
|
||||
kind: RaiseKind,
|
||||
},
|
||||
BuildString {
|
||||
size: usize,
|
||||
size: u32,
|
||||
},
|
||||
BuildTuple {
|
||||
size: usize,
|
||||
unpack: bool,
|
||||
size: u32,
|
||||
},
|
||||
BuildList {
|
||||
size: usize,
|
||||
unpack: bool,
|
||||
size: u32,
|
||||
},
|
||||
BuildSet {
|
||||
size: usize,
|
||||
unpack: bool,
|
||||
size: u32,
|
||||
},
|
||||
BuildMap {
|
||||
size: usize,
|
||||
unpack: bool,
|
||||
for_call: bool,
|
||||
size: u32,
|
||||
},
|
||||
BuildSlice {
|
||||
size: usize,
|
||||
/// whether build a slice with a third step argument
|
||||
step: bool,
|
||||
},
|
||||
ListAppend {
|
||||
i: usize,
|
||||
i: u32,
|
||||
},
|
||||
SetAdd {
|
||||
i: usize,
|
||||
i: u32,
|
||||
},
|
||||
MapAdd {
|
||||
i: usize,
|
||||
i: u32,
|
||||
},
|
||||
|
||||
PrintExpr,
|
||||
LoadBuildClass,
|
||||
UnpackSequence {
|
||||
size: usize,
|
||||
size: u32,
|
||||
},
|
||||
UnpackEx {
|
||||
before: usize,
|
||||
after: usize,
|
||||
before: u8,
|
||||
after: u8,
|
||||
},
|
||||
FormatValue {
|
||||
conversion: Option<ConversionFlag>,
|
||||
conversion: ConversionFlag,
|
||||
},
|
||||
PopException,
|
||||
Reverse {
|
||||
amount: usize,
|
||||
amount: u32,
|
||||
},
|
||||
GetAwaitable,
|
||||
BeforeAsyncWith,
|
||||
@@ -355,17 +370,20 @@ pub enum Instruction {
|
||||
/// required to support named expressions of Python 3.8 in dict comprehension
|
||||
/// today (including Py3.9) only required in dict comprehension.
|
||||
MapAddRev {
|
||||
i: usize,
|
||||
i: u32,
|
||||
},
|
||||
}
|
||||
|
||||
use self::Instruction::*;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum CallType {
|
||||
Positional(usize),
|
||||
Keyword(usize),
|
||||
Ex(bool),
|
||||
bitflags! {
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct MakeFunctionFlags: u8 {
|
||||
const CLOSURE = 0x01;
|
||||
const ANNOTATIONS = 0x02;
|
||||
const KW_ONLY_DEFAULTS = 0x04;
|
||||
const DEFAULTS = 0x08;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
@@ -452,7 +470,7 @@ impl<C: Constant> BorrowedConstant<'_, C> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum ComparisonOperator {
|
||||
Greater,
|
||||
GreaterOrEqual,
|
||||
@@ -467,7 +485,7 @@ pub enum ComparisonOperator {
|
||||
ExceptionMatch,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum BinaryOperator {
|
||||
Power,
|
||||
Multiply,
|
||||
@@ -484,7 +502,7 @@ pub enum BinaryOperator {
|
||||
Or,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum UnaryOperator {
|
||||
Not,
|
||||
Invert,
|
||||
@@ -588,39 +606,8 @@ impl<C: Constant> CodeObject<C> {
|
||||
pub fn label_targets(&self) -> BTreeSet<Label> {
|
||||
let mut label_targets = BTreeSet::new();
|
||||
for instruction in &*self.instructions {
|
||||
match instruction {
|
||||
Jump { target: l }
|
||||
| JumpIfTrue { target: l }
|
||||
| JumpIfFalse { target: l }
|
||||
| JumpIfTrueOrPop { target: l }
|
||||
| JumpIfFalseOrPop { target: l }
|
||||
| ForIter { target: l }
|
||||
| SetupFinally { handler: l }
|
||||
| SetupExcept { handler: l }
|
||||
| SetupWith { end: l }
|
||||
| SetupAsyncWith { end: l } => {
|
||||
label_targets.insert(*l);
|
||||
}
|
||||
SetupLoop { start, end } => {
|
||||
label_targets.insert(*start);
|
||||
label_targets.insert(*end);
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
Import { .. } | ImportStar | ImportFrom { .. } | LoadFast(_) | LoadNameAny(_)
|
||||
| LoadGlobal(_) | LoadDeref(_) | LoadClassDeref(_) | StoreFast(_) | StoreLocal(_)
|
||||
| StoreGlobal(_) | StoreDeref(_) | DeleteFast(_) | DeleteLocal(_) | DeleteGlobal(_)
|
||||
| DeleteDeref(_) | LoadClosure(_) | Subscript | StoreSubscript | DeleteSubscript
|
||||
| StoreAttr { .. } | DeleteAttr { .. } | LoadConst { .. } | UnaryOperation { .. }
|
||||
| BinaryOperation { .. } | LoadAttr { .. } | CompareOperation { .. } | Pop
|
||||
| Rotate { .. } | Duplicate | GetIter | Continue | Break | MakeFunction
|
||||
| CallFunction { .. } | ReturnValue | YieldValue | YieldFrom | SetupAnnotation
|
||||
| EnterFinally | EndFinally | WithCleanupStart | WithCleanupFinish | PopBlock
|
||||
| Raise { .. } | BuildString { .. } | BuildTuple { .. } | BuildList { .. }
|
||||
| BuildSet { .. } | BuildMap { .. } | BuildSlice { .. } | ListAppend { .. }
|
||||
| SetAdd { .. } | MapAdd { .. } | PrintExpr | LoadBuildClass | UnpackSequence { .. }
|
||||
| UnpackEx { .. } | FormatValue { .. } | PopException | Reverse { .. }
|
||||
| GetAwaitable | BeforeAsyncWith | GetAIter | GetANext | MapAddRev { .. } => {}
|
||||
if let Some(l) = instruction.label_arg() {
|
||||
label_targets.insert(*l);
|
||||
}
|
||||
}
|
||||
label_targets
|
||||
@@ -635,7 +622,7 @@ impl<C: Constant> CodeObject<C> {
|
||||
let label_targets = self.label_targets();
|
||||
|
||||
for (offset, instruction) in self.instructions.iter().enumerate() {
|
||||
let arrow = if label_targets.contains(&Label(offset)) {
|
||||
let arrow = if label_targets.contains(&Label(offset as u32)) {
|
||||
">>"
|
||||
} else {
|
||||
" "
|
||||
@@ -736,18 +723,21 @@ impl<C: Constant> CodeObject<C> {
|
||||
impl CodeObject<ConstantData> {
|
||||
/// Load a code object from bytes
|
||||
pub fn from_bytes(data: &[u8]) -> Result<Self, Box<dyn std::error::Error>> {
|
||||
let reader = lz_fear::framed::LZ4FrameReader::new(data)?;
|
||||
Ok(bincode::deserialize_from(reader.into_read())?)
|
||||
// TODO: PR to lz4_flex to make it not panic
|
||||
if data.len() < 4 {
|
||||
return Err(
|
||||
std::io::Error::new(std::io::ErrorKind::UnexpectedEof, "bad bytecode").into(),
|
||||
);
|
||||
}
|
||||
let raw_bincode = lz4_flex::decompress_size_prepended(data)?;
|
||||
let data = bincode::deserialize(&raw_bincode)?;
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
/// Serialize this bytecode to bytes.
|
||||
pub fn to_bytes(&self) -> Vec<u8> {
|
||||
let data = bincode::serialize(&self).expect("CodeObject is not serializable");
|
||||
let mut out = Vec::new();
|
||||
lz_fear::framed::CompressionSettings::default()
|
||||
.compress_with_size_unchecked(data.as_slice(), &mut out, data.len() as u64)
|
||||
.unwrap();
|
||||
out
|
||||
lz4_flex::compress_prepend_size(&data)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -765,6 +755,46 @@ impl<C: Constant> fmt::Display for CodeObject<C> {
|
||||
}
|
||||
|
||||
impl Instruction {
|
||||
/// Gets the label stored inside this instruction, if it exists
|
||||
#[inline]
|
||||
pub fn label_arg(&self) -> Option<&Label> {
|
||||
match self {
|
||||
Jump { target: l }
|
||||
| JumpIfTrue { target: l }
|
||||
| JumpIfFalse { target: l }
|
||||
| JumpIfTrueOrPop { target: l }
|
||||
| JumpIfFalseOrPop { target: l }
|
||||
| ForIter { target: l }
|
||||
| SetupFinally { handler: l }
|
||||
| SetupExcept { handler: l }
|
||||
| SetupWith { end: l }
|
||||
| SetupAsyncWith { end: l }
|
||||
| SetupLoop { end: l }
|
||||
| Continue { target: l } => Some(l),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets a mutable reference to the label stored inside this instruction, if it exists
|
||||
#[inline]
|
||||
pub fn label_arg_mut(&mut self) -> Option<&mut Label> {
|
||||
match self {
|
||||
Jump { target: l }
|
||||
| JumpIfTrue { target: l }
|
||||
| JumpIfFalse { target: l }
|
||||
| JumpIfTrueOrPop { target: l }
|
||||
| JumpIfFalseOrPop { target: l }
|
||||
| ForIter { target: l }
|
||||
| SetupFinally { handler: l }
|
||||
| SetupExcept { handler: l }
|
||||
| SetupWith { end: l }
|
||||
| SetupAsyncWith { end: l }
|
||||
| SetupLoop { end: l }
|
||||
| Continue { target: l } => Some(l),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn fmt_dis<C: Constant>(
|
||||
&self,
|
||||
@@ -799,53 +829,41 @@ impl Instruction {
|
||||
};
|
||||
}
|
||||
|
||||
let cellname = |i: usize| {
|
||||
let varname = |i: u32| varnames[i as usize].as_ref();
|
||||
let name = |i: u32| names[i as usize].as_ref();
|
||||
let cellname = |i: u32| {
|
||||
cellvars
|
||||
.get(i)
|
||||
.unwrap_or_else(|| &freevars[i - cellvars.len()])
|
||||
.get(i as usize)
|
||||
.unwrap_or_else(|| &freevars[i as usize - cellvars.len()])
|
||||
.as_ref()
|
||||
};
|
||||
|
||||
match self {
|
||||
Import {
|
||||
name_idx,
|
||||
symbols_idx,
|
||||
level,
|
||||
} => w!(
|
||||
Import,
|
||||
format!("{:?}", name_idx.map(|idx| names[idx].as_ref())),
|
||||
format!(
|
||||
"({:?})",
|
||||
symbols_idx
|
||||
.iter()
|
||||
.map(|&idx| names[idx].as_ref())
|
||||
.format(", ")
|
||||
),
|
||||
level
|
||||
),
|
||||
ImportName { idx } => w!(ImportName, name(*idx)),
|
||||
ImportNameless => w!(ImportNameless),
|
||||
ImportStar => w!(ImportStar),
|
||||
ImportFrom { idx } => w!(ImportFrom, names[*idx].as_ref()),
|
||||
LoadFast(idx) => w!(LoadFast, *idx, varnames[*idx].as_ref()),
|
||||
LoadNameAny(idx) => w!(LoadNameAny, *idx, names[*idx].as_ref()),
|
||||
LoadGlobal(idx) => w!(LoadGlobal, *idx, names[*idx].as_ref()),
|
||||
ImportFrom { idx } => w!(ImportFrom, name(*idx)),
|
||||
LoadFast(idx) => w!(LoadFast, *idx, varname(*idx)),
|
||||
LoadNameAny(idx) => w!(LoadNameAny, *idx, name(*idx)),
|
||||
LoadGlobal(idx) => w!(LoadGlobal, *idx, name(*idx)),
|
||||
LoadDeref(idx) => w!(LoadDeref, *idx, cellname(*idx)),
|
||||
LoadClassDeref(idx) => w!(LoadClassDeref, *idx, cellname(*idx)),
|
||||
StoreFast(idx) => w!(StoreFast, *idx, varnames[*idx].as_ref()),
|
||||
StoreLocal(idx) => w!(StoreLocal, *idx, names[*idx].as_ref()),
|
||||
StoreGlobal(idx) => w!(StoreGlobal, *idx, names[*idx].as_ref()),
|
||||
StoreFast(idx) => w!(StoreFast, *idx, varname(*idx)),
|
||||
StoreLocal(idx) => w!(StoreLocal, *idx, name(*idx)),
|
||||
StoreGlobal(idx) => w!(StoreGlobal, *idx, name(*idx)),
|
||||
StoreDeref(idx) => w!(StoreDeref, *idx, cellname(*idx)),
|
||||
DeleteFast(idx) => w!(DeleteFast, *idx, varnames[*idx].as_ref()),
|
||||
DeleteLocal(idx) => w!(DeleteLocal, *idx, names[*idx].as_ref()),
|
||||
DeleteGlobal(idx) => w!(DeleteGlobal, *idx, names[*idx].as_ref()),
|
||||
DeleteFast(idx) => w!(DeleteFast, *idx, varname(*idx)),
|
||||
DeleteLocal(idx) => w!(DeleteLocal, *idx, name(*idx)),
|
||||
DeleteGlobal(idx) => w!(DeleteGlobal, *idx, name(*idx)),
|
||||
DeleteDeref(idx) => w!(DeleteDeref, *idx, cellname(*idx)),
|
||||
LoadClosure(i) => w!(LoadClosure, *i, cellname(*i)),
|
||||
Subscript => w!(Subscript),
|
||||
StoreSubscript => w!(StoreSubscript),
|
||||
DeleteSubscript => w!(DeleteSubscript),
|
||||
StoreAttr { idx } => w!(StoreAttr, names[*idx].as_ref()),
|
||||
DeleteAttr { idx } => w!(DeleteAttr, names[*idx].as_ref()),
|
||||
StoreAttr { idx } => w!(StoreAttr, name(*idx)),
|
||||
DeleteAttr { idx } => w!(DeleteAttr, name(*idx)),
|
||||
LoadConst { idx } => {
|
||||
let value = &constants[*idx];
|
||||
let value = &constants[*idx as usize];
|
||||
match value.borrow_constant() {
|
||||
BorrowedConstant::Code { code } if expand_codeobjects => {
|
||||
writeln!(f, "{:20} ({:?}):", "LoadConst", code)?;
|
||||
@@ -859,29 +877,34 @@ impl Instruction {
|
||||
}
|
||||
}
|
||||
}
|
||||
UnaryOperation { op } => w!(UnaryOperation, format!("{:?}", op)),
|
||||
BinaryOperation { op, inplace } => w!(BinaryOperation, format!("{:?}", op), inplace),
|
||||
LoadAttr { idx } => w!(LoadAttr, names[*idx].as_ref()),
|
||||
CompareOperation { op } => w!(CompareOperation, format!("{:?}", op)),
|
||||
UnaryOperation { op } => w!(UnaryOperation, format_args!("{:?}", op)),
|
||||
BinaryOperation { op } => w!(BinaryOperation, format_args!("{:?}", op)),
|
||||
BinaryOperationInplace { op } => {
|
||||
w!(BinaryOperationInplace, format_args!("{:?}", op))
|
||||
}
|
||||
LoadAttr { idx } => w!(LoadAttr, name(*idx)),
|
||||
CompareOperation { op } => w!(CompareOperation, format_args!("{:?}", op)),
|
||||
Pop => w!(Pop),
|
||||
Rotate { amount } => w!(Rotate, amount),
|
||||
Duplicate => w!(Duplicate),
|
||||
GetIter => w!(GetIter),
|
||||
Continue => w!(Continue),
|
||||
Continue { target } => w!(Continue, target),
|
||||
Break => w!(Break),
|
||||
Jump { target } => w!(Jump, target),
|
||||
JumpIfTrue { target } => w!(JumpIfTrue, target),
|
||||
JumpIfFalse { target } => w!(JumpIfFalse, target),
|
||||
JumpIfTrueOrPop { target } => w!(JumpIfTrueOrPop, target),
|
||||
JumpIfFalseOrPop { target } => w!(JumpIfFalseOrPop, target),
|
||||
MakeFunction => w!(MakeFunction),
|
||||
CallFunction { typ } => w!(CallFunction, format!("{:?}", typ)),
|
||||
MakeFunction(flags) => w!(MakeFunction, format_args!("{:?}", flags)),
|
||||
CallFunctionPositional { nargs } => w!(CallFunctionPositional, nargs),
|
||||
CallFunctionKeyword { nargs } => w!(CallFunctionKeyword, nargs),
|
||||
CallFunctionEx { has_kwargs } => w!(CallFunctionEx, has_kwargs),
|
||||
ForIter { target } => w!(ForIter, target),
|
||||
ReturnValue => w!(ReturnValue),
|
||||
YieldValue => w!(YieldValue),
|
||||
YieldFrom => w!(YieldFrom),
|
||||
SetupAnnotation => w!(SetupAnnotation),
|
||||
SetupLoop { start, end } => w!(SetupLoop, start, end),
|
||||
SetupLoop { end } => w!(SetupLoop, end),
|
||||
SetupExcept { handler } => w!(SetupExcept, handler),
|
||||
SetupFinally { handler } => w!(SetupFinally, handler),
|
||||
EnterFinally => w!(EnterFinally),
|
||||
@@ -892,7 +915,7 @@ impl Instruction {
|
||||
BeforeAsyncWith => w!(BeforeAsyncWith),
|
||||
SetupAsyncWith { end } => w!(SetupAsyncWith, end),
|
||||
PopBlock => w!(PopBlock),
|
||||
Raise { argc } => w!(Raise, argc),
|
||||
Raise { kind } => w!(Raise, format_args!("{:?}", kind)),
|
||||
BuildString { size } => w!(BuildString, size),
|
||||
BuildTuple { size, unpack } => w!(BuildTuple, size, unpack),
|
||||
BuildList { size, unpack } => w!(BuildList, size, unpack),
|
||||
@@ -902,7 +925,7 @@ impl Instruction {
|
||||
unpack,
|
||||
for_call,
|
||||
} => w!(BuildMap, size, unpack, for_call),
|
||||
BuildSlice { size } => w!(BuildSlice, size),
|
||||
BuildSlice { step } => w!(BuildSlice, step),
|
||||
ListAppend { i } => w!(ListAppend, i),
|
||||
SetAdd { i } => w!(SetAdd, i),
|
||||
MapAddRev { i } => w!(MapAddRev, i),
|
||||
@@ -910,7 +933,7 @@ impl Instruction {
|
||||
LoadBuildClass => w!(LoadBuildClass),
|
||||
UnpackSequence { size } => w!(UnpackSequence, size),
|
||||
UnpackEx { before, after } => w!(UnpackEx, before, after),
|
||||
FormatValue { .. } => w!(FormatValue), // TODO: write conversion
|
||||
FormatValue { conversion } => w!(FormatValue, format_args!("{:?}", conversion)),
|
||||
PopException => w!(PopException),
|
||||
Reverse { amount } => w!(Reverse, amount),
|
||||
GetAwaitable => w!(GetAwaitable),
|
||||
|
||||
@@ -13,6 +13,7 @@ itertools = "0.9"
|
||||
rustpython-bytecode = { path = "../bytecode", version = "0.1.1" }
|
||||
rustpython-ast = { path = "../ast" }
|
||||
num-complex = { version = "0.3", features = ["serde"] }
|
||||
num-traits = "0.2"
|
||||
log = "0.4"
|
||||
arrayvec = "0.5"
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -37,6 +37,7 @@ pub enum CompileErrorType {
|
||||
InvalidFuturePlacement,
|
||||
InvalidFutureFeature(String),
|
||||
FunctionImportStar,
|
||||
TooManyStarUnpack,
|
||||
}
|
||||
|
||||
impl fmt::Display for CompileErrorType {
|
||||
@@ -70,6 +71,9 @@ impl fmt::Display for CompileErrorType {
|
||||
CompileErrorType::FunctionImportStar => {
|
||||
write!(f, "import * only allowed at module level")
|
||||
}
|
||||
CompileErrorType::TooManyStarUnpack => {
|
||||
write!(f, "too many expressions in star-unpacking assignment")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//! Compile a Python AST or source code into bytecode consumable by RustPython or
|
||||
//! (eventually) CPython.
|
||||
//! Compile a Python AST or source code into bytecode consumable by RustPython.
|
||||
#![doc(html_logo_url = "https://raw.githubusercontent.com/RustPython/RustPython/master/logo.png")]
|
||||
#![doc(html_root_url = "https://docs.rs/rustpython-compiler/")]
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> {
|
||||
let params = compiler.builder.func.dfg.block_params(entry_block).to_vec();
|
||||
for (i, (ty, val)) in arg_types.iter().zip(params).enumerate() {
|
||||
compiler
|
||||
.store_variable(i, JitValue::new(val, ty.clone()))
|
||||
.store_variable(i as u32, JitValue::new(val, ty.clone()))
|
||||
.unwrap();
|
||||
}
|
||||
compiler
|
||||
@@ -66,8 +66,8 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> {
|
||||
val: JitValue,
|
||||
) -> Result<(), JitCompileError> {
|
||||
let builder = &mut self.builder;
|
||||
let local = self.variables[idx].get_or_insert_with(|| {
|
||||
let var = Variable::new(idx);
|
||||
let local = self.variables[idx as usize].get_or_insert_with(|| {
|
||||
let var = Variable::new(idx as usize);
|
||||
let local = Local {
|
||||
var,
|
||||
ty: val.ty.clone(),
|
||||
@@ -119,7 +119,7 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> {
|
||||
let label_targets = bytecode.label_targets();
|
||||
|
||||
for (offset, instruction) in bytecode.instructions.iter().enumerate() {
|
||||
let label = Label(offset);
|
||||
let label = Label(offset as u32);
|
||||
if label_targets.contains(&label) {
|
||||
let block = self.get_or_create_block(label);
|
||||
|
||||
@@ -219,7 +219,7 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> {
|
||||
Ok(())
|
||||
}
|
||||
Instruction::LoadFast(idx) => {
|
||||
let local = self.variables[*idx]
|
||||
let local = self.variables[*idx as usize]
|
||||
.as_ref()
|
||||
.ok_or(JitCompileError::BadBytecode)?;
|
||||
self.stack.push(JitValue {
|
||||
@@ -232,7 +232,9 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> {
|
||||
let val = self.stack.pop().ok_or(JitCompileError::BadBytecode)?;
|
||||
self.store_variable(*idx, val)
|
||||
}
|
||||
Instruction::LoadConst { idx } => self.load_const(constants[*idx].borrow_constant()),
|
||||
Instruction::LoadConst { idx } => {
|
||||
self.load_const(constants[*idx as usize].borrow_constant())
|
||||
}
|
||||
Instruction::ReturnValue => {
|
||||
let val = self.stack.pop().ok_or(JitCompileError::BadBytecode)?;
|
||||
if let Some(ref ty) = self.sig.ret {
|
||||
@@ -320,7 +322,7 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> {
|
||||
_ => Err(JitCompileError::NotSupported),
|
||||
}
|
||||
}
|
||||
Instruction::BinaryOperation { op, .. } => {
|
||||
Instruction::BinaryOperation { op } | Instruction::BinaryOperationInplace { op } => {
|
||||
// the rhs is popped off first
|
||||
let b = self.stack.pop().ok_or(JitCompileError::BadBytecode)?;
|
||||
let a = self.stack.pop().ok_or(JitCompileError::BadBytecode)?;
|
||||
|
||||
@@ -78,13 +78,15 @@ impl StackMachine {
|
||||
names: &[String],
|
||||
) -> bool {
|
||||
match instruction {
|
||||
Instruction::LoadConst { idx } => self.stack.push(constants[idx].clone().into()),
|
||||
Instruction::LoadNameAny(idx) => {
|
||||
self.stack.push(StackValue::String(names[idx].clone()))
|
||||
Instruction::LoadConst { idx } => {
|
||||
self.stack.push(constants[idx as usize].clone().into())
|
||||
}
|
||||
Instruction::LoadNameAny(idx) => self
|
||||
.stack
|
||||
.push(StackValue::String(names[idx as usize].clone())),
|
||||
Instruction::StoreLocal(idx) => {
|
||||
self.locals
|
||||
.insert(names[idx].clone(), self.stack.pop().unwrap());
|
||||
.insert(names[idx as usize].clone(), self.stack.pop().unwrap());
|
||||
}
|
||||
Instruction::StoreAttr { .. } => {
|
||||
// Do nothing except throw away the stack values
|
||||
@@ -104,7 +106,7 @@ impl StackMachine {
|
||||
}
|
||||
self.stack.push(StackValue::Map(map));
|
||||
}
|
||||
Instruction::MakeFunction => {
|
||||
Instruction::MakeFunction(_flags) => {
|
||||
let name = if let Some(StackValue::String(name)) = self.stack.pop() {
|
||||
name
|
||||
} else {
|
||||
@@ -134,7 +136,7 @@ impl StackMachine {
|
||||
let mut values = Vec::new();
|
||||
|
||||
// Pop all values from stack:
|
||||
values.extend(self.stack.drain(self.stack.len() - amount..));
|
||||
values.extend(self.stack.drain(self.stack.len() - amount as usize..));
|
||||
|
||||
// Push top of stack back first:
|
||||
self.stack.push(values.pop().unwrap());
|
||||
|
||||
@@ -510,7 +510,7 @@ fn run_rustpython(vm: &VirtualMachine, matches: &ArgMatches) -> PyResult<()> {
|
||||
vm.get_attribute(vm.sys_module.clone(), "modules")?
|
||||
.set_item("__main__", main_module, vm)?;
|
||||
|
||||
let site_result = vm.import("site", &[], 0);
|
||||
let site_result = vm.import("site", None, 0);
|
||||
|
||||
if site_result.is_err() {
|
||||
warn!(
|
||||
@@ -559,7 +559,7 @@ fn run_command(vm: &VirtualMachine, scope: Scope, source: String) -> PyResult<()
|
||||
|
||||
fn run_module(vm: &VirtualMachine, module: &str) -> PyResult<()> {
|
||||
debug!("Running module {}", module);
|
||||
let runpy = vm.import("runpy", &[], 0)?;
|
||||
let runpy = vm.import("runpy", None, 0)?;
|
||||
let run_module_as_main = vm.get_attribute(runpy, "_run_module_as_main")?;
|
||||
vm.invoke(&run_module_as_main, (module,))?;
|
||||
Ok(())
|
||||
|
||||
@@ -73,7 +73,7 @@ impl FrameRef {
|
||||
}
|
||||
|
||||
#[pyproperty]
|
||||
fn f_lasti(self) -> usize {
|
||||
fn f_lasti(self) -> u32 {
|
||||
self.lasti()
|
||||
}
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ impl PyModule {
|
||||
|
||||
#[pymethod(magic)]
|
||||
fn repr(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult {
|
||||
let importlib = vm.import("_frozen_importlib", &[], 0)?;
|
||||
let importlib = vm.import("_frozen_importlib", None, 0)?;
|
||||
let module_repr = vm.get_attribute(importlib, "_module_repr")?;
|
||||
vm.invoke(&module_repr, (zelf,))
|
||||
}
|
||||
|
||||
@@ -314,11 +314,11 @@ pub fn init(context: &PyContext) {
|
||||
|
||||
fn common_reduce(obj: PyObjectRef, proto: usize, vm: &VirtualMachine) -> PyResult {
|
||||
if proto >= 2 {
|
||||
let reducelib = vm.import("__reducelib", &[], 0)?;
|
||||
let reducelib = vm.import("__reducelib", None, 0)?;
|
||||
let reduce_2 = vm.get_attribute(reducelib, "reduce_2")?;
|
||||
vm.invoke(&reduce_2, (obj,))
|
||||
} else {
|
||||
let copyreg = vm.import("copyreg", &[], 0)?;
|
||||
let copyreg = vm.import("copyreg", None, 0)?;
|
||||
let reduce_ex = vm.get_attribute(copyreg, "_reduce_ex")?;
|
||||
vm.invoke(&reduce_ex, (obj, proto))
|
||||
}
|
||||
|
||||
@@ -95,12 +95,14 @@ impl fmt::Display for PyStr {
|
||||
}
|
||||
|
||||
impl TryIntoRef<PyStr> for String {
|
||||
#[inline]
|
||||
fn try_into_ref(self, vm: &VirtualMachine) -> PyResult<PyRef<PyStr>> {
|
||||
Ok(PyStr::from(self).into_ref(vm))
|
||||
}
|
||||
}
|
||||
|
||||
impl TryIntoRef<PyStr> for &str {
|
||||
#[inline]
|
||||
fn try_into_ref(self, vm: &VirtualMachine) -> PyResult<PyRef<PyStr>> {
|
||||
Ok(PyStr::from(self).into_ref(vm))
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ use crate::vm::VirtualMachine;
|
||||
pub struct PyTraceback {
|
||||
pub next: Option<PyTracebackRef>, // TODO: Make mutable
|
||||
pub frame: FrameRef,
|
||||
pub lasti: usize,
|
||||
pub lasti: u32,
|
||||
pub lineno: usize,
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ impl PyValue for PyTraceback {
|
||||
|
||||
#[pyimpl]
|
||||
impl PyTraceback {
|
||||
pub fn new(next: Option<PyRef<Self>>, frame: FrameRef, lasti: usize, lineno: usize) -> Self {
|
||||
pub fn new(next: Option<PyRef<Self>>, frame: FrameRef, lasti: u32, lineno: usize) -> Self {
|
||||
PyTraceback {
|
||||
next,
|
||||
frame,
|
||||
@@ -37,7 +37,7 @@ impl PyTraceback {
|
||||
}
|
||||
|
||||
#[pyproperty(name = "tb_lasti")]
|
||||
fn lasti(&self) -> usize {
|
||||
fn lasti(&self) -> u32 {
|
||||
self.lasti
|
||||
}
|
||||
|
||||
|
||||
@@ -317,6 +317,7 @@ impl<T: TransmuteFromObject> TryFromObject for PyTupleTyped<T> {
|
||||
|
||||
impl<'a, T: TransmuteFromObject + 'a> BorrowValue<'a> for PyTupleTyped<T> {
|
||||
type Borrowed = &'a [T];
|
||||
#[inline]
|
||||
fn borrow_value(&'a self) -> Self::Borrowed {
|
||||
unsafe { &*(self.tuple.borrow_value() as *const [PyObjectRef] as *const [T]) }
|
||||
}
|
||||
@@ -327,3 +328,17 @@ impl<T: TransmuteFromObject + fmt::Debug> fmt::Debug for PyTupleTyped<T> {
|
||||
self.borrow_value().fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransmuteFromObject> From<PyTupleTyped<T>> for PyTupleRef {
|
||||
#[inline]
|
||||
fn from(tup: PyTupleTyped<T>) -> Self {
|
||||
tup.tuple
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TransmuteFromObject> IntoPyObject for PyTupleTyped<T> {
|
||||
#[inline]
|
||||
fn into_pyobject(self, _vm: &VirtualMachine) -> PyObjectRef {
|
||||
self.tuple.into_object()
|
||||
}
|
||||
}
|
||||
|
||||
436
vm/src/frame.rs
436
vm/src/frame.rs
@@ -1,5 +1,5 @@
|
||||
use std::fmt;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::sync::atomic::{AtomicU32, Ordering};
|
||||
|
||||
use indexmap::IndexMap;
|
||||
use itertools::Itertools;
|
||||
@@ -42,7 +42,6 @@ struct Block {
|
||||
#[derive(Clone, Debug)]
|
||||
enum BlockType {
|
||||
Loop {
|
||||
start: bytecode::Label,
|
||||
end: bytecode::Label,
|
||||
},
|
||||
TryExcept {
|
||||
@@ -77,7 +76,7 @@ enum UnwindReason {
|
||||
Break,
|
||||
|
||||
/// We are unwinding blocks since we hit a continue statements.
|
||||
Continue,
|
||||
Continue { target: bytecode::Label },
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -100,7 +99,7 @@ pub struct Frame {
|
||||
pub builtins: PyDictRef,
|
||||
|
||||
/// index of last instruction ran
|
||||
pub lasti: AtomicUsize,
|
||||
pub lasti: AtomicU32,
|
||||
/// tracer function for this frame (usually is None)
|
||||
pub trace: PyMutex<PyObjectRef>,
|
||||
state: PyMutex<FrameState>,
|
||||
@@ -187,7 +186,7 @@ impl Frame {
|
||||
globals: scope.globals,
|
||||
builtins,
|
||||
code,
|
||||
lasti: AtomicUsize::new(0),
|
||||
lasti: AtomicU32::new(0),
|
||||
state: PyMutex::new(FrameState {
|
||||
stack: Vec::new(),
|
||||
blocks: Vec::new(),
|
||||
@@ -284,14 +283,14 @@ impl FrameRef {
|
||||
}
|
||||
|
||||
pub fn current_location(&self) -> bytecode::Location {
|
||||
self.code.locations[self.lasti.load(Ordering::Relaxed) - 1]
|
||||
self.code.locations[self.lasti.load(Ordering::Relaxed) as usize - 1]
|
||||
}
|
||||
|
||||
pub fn yield_from_target(&self) -> Option<PyObjectRef> {
|
||||
self.with_exec(|exec| exec.yield_from_target())
|
||||
}
|
||||
|
||||
pub fn lasti(&self) -> usize {
|
||||
pub fn lasti(&self) -> u32 {
|
||||
self.lasti.load(Ordering::Relaxed)
|
||||
}
|
||||
}
|
||||
@@ -306,7 +305,7 @@ struct ExecutingFrame<'a> {
|
||||
globals: &'a PyDictRef,
|
||||
builtins: &'a PyDictRef,
|
||||
object: &'a FrameRef,
|
||||
lasti: &'a AtomicUsize,
|
||||
lasti: &'a AtomicU32,
|
||||
state: &'a mut FrameState,
|
||||
}
|
||||
|
||||
@@ -326,8 +325,7 @@ impl ExecutingFrame<'_> {
|
||||
flame_guard!(format!("Frame::run({})", self.code.obj_name));
|
||||
// Execute until return or exception:
|
||||
loop {
|
||||
let idx = self.lasti.fetch_add(1, Ordering::Relaxed);
|
||||
let loc = self.code.locations[idx];
|
||||
let idx = self.lasti.fetch_add(1, Ordering::Relaxed) as usize;
|
||||
let instr = &self.code.instructions[idx];
|
||||
let result = self.execute_instruction(instr, vm);
|
||||
match result {
|
||||
@@ -341,6 +339,8 @@ impl ExecutingFrame<'_> {
|
||||
// 2. Add new entry with current execution position (filename, lineno, code_object) to traceback.
|
||||
// 3. Unwind block stack till appropriate handler is found.
|
||||
|
||||
let loc = self.code.locations[idx];
|
||||
|
||||
let next = exception.traceback();
|
||||
|
||||
let new_traceback =
|
||||
@@ -365,7 +365,9 @@ impl ExecutingFrame<'_> {
|
||||
}
|
||||
|
||||
fn yield_from_target(&self) -> Option<PyObjectRef> {
|
||||
if let Some(bytecode::Instruction::YieldFrom) = self.code.instructions.get(self.lasti()) {
|
||||
if let Some(bytecode::Instruction::YieldFrom) =
|
||||
self.code.instructions.get(self.lasti() as usize)
|
||||
{
|
||||
Some(self.last_value())
|
||||
} else {
|
||||
None
|
||||
@@ -442,23 +444,23 @@ impl ExecutingFrame<'_> {
|
||||
|
||||
match instruction {
|
||||
bytecode::Instruction::LoadConst { idx } => {
|
||||
self.push_value(self.code.constants[*idx].0.clone());
|
||||
self.push_value(self.code.constants[*idx as usize].0.clone());
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::Import {
|
||||
name_idx,
|
||||
symbols_idx,
|
||||
level,
|
||||
} => self.import(vm, *name_idx, symbols_idx, *level),
|
||||
bytecode::Instruction::ImportName { idx } => {
|
||||
self.import(vm, Some(self.code.names[*idx as usize].clone()))
|
||||
}
|
||||
bytecode::Instruction::ImportNameless => self.import(vm, None),
|
||||
bytecode::Instruction::ImportStar => self.import_star(vm),
|
||||
bytecode::Instruction::ImportFrom { idx } => self.import_from(vm, *idx),
|
||||
bytecode::Instruction::LoadFast(idx) => {
|
||||
let x = self.fastlocals.lock()[*idx].clone().ok_or_else(|| {
|
||||
let idx = *idx as usize;
|
||||
let x = self.fastlocals.lock()[idx].clone().ok_or_else(|| {
|
||||
vm.new_exception_msg(
|
||||
vm.ctx.exceptions.unbound_local_error.clone(),
|
||||
format!(
|
||||
"local variable '{}' referenced before assignment",
|
||||
self.code.varnames[*idx]
|
||||
self.code.varnames[idx]
|
||||
),
|
||||
)
|
||||
})?;
|
||||
@@ -466,7 +468,7 @@ impl ExecutingFrame<'_> {
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::LoadNameAny(idx) => {
|
||||
let name = &self.code.names[*idx];
|
||||
let name = &self.code.names[*idx as usize];
|
||||
let x = self.locals.get_item_option(name.clone(), vm)?;
|
||||
let x = match x {
|
||||
Some(x) => x,
|
||||
@@ -476,13 +478,13 @@ impl ExecutingFrame<'_> {
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::LoadGlobal(idx) => {
|
||||
let name = &self.code.names[*idx];
|
||||
let name = &self.code.names[*idx as usize];
|
||||
let x = self.load_global_or_builtin(name, vm)?;
|
||||
self.push_value(x);
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::LoadDeref(i) => {
|
||||
let i = *i;
|
||||
let i = *i as usize;
|
||||
let x = self.cells_frees[i]
|
||||
.get()
|
||||
.ok_or_else(|| self.unbound_cell_exception(i, vm))?;
|
||||
@@ -490,7 +492,7 @@ impl ExecutingFrame<'_> {
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::LoadClassDeref(i) => {
|
||||
let i = *i;
|
||||
let i = *i as usize;
|
||||
let name = self.code.freevars[i - self.code.cellvars.len()].clone();
|
||||
let value = if let Some(value) = self.locals.get_item_option(name, vm)? {
|
||||
value
|
||||
@@ -504,32 +506,32 @@ impl ExecutingFrame<'_> {
|
||||
}
|
||||
bytecode::Instruction::StoreFast(idx) => {
|
||||
let value = self.pop_value();
|
||||
self.fastlocals.lock()[*idx] = Some(value);
|
||||
self.fastlocals.lock()[*idx as usize] = Some(value);
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::StoreLocal(idx) => {
|
||||
let value = self.pop_value();
|
||||
self.locals
|
||||
.set_item(self.code.names[*idx].clone(), value, vm)?;
|
||||
.set_item(self.code.names[*idx as usize].clone(), value, vm)?;
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::StoreGlobal(idx) => {
|
||||
let value = self.pop_value();
|
||||
self.globals
|
||||
.set_item(self.code.names[*idx].clone(), value, vm)?;
|
||||
.set_item(self.code.names[*idx as usize].clone(), value, vm)?;
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::StoreDeref(i) => {
|
||||
let value = self.pop_value();
|
||||
self.cells_frees[*i].set(Some(value));
|
||||
self.cells_frees[*i as usize].set(Some(value));
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::DeleteFast(idx) => {
|
||||
self.fastlocals.lock()[*idx] = None;
|
||||
self.fastlocals.lock()[*idx as usize] = None;
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::DeleteLocal(idx) => {
|
||||
let name = &self.code.names[*idx];
|
||||
let name = &self.code.names[*idx as usize];
|
||||
match self.locals.del_item(name.clone(), vm) {
|
||||
Ok(()) => {}
|
||||
Err(e) if e.isinstance(&vm.ctx.exceptions.key_error) => {
|
||||
@@ -540,7 +542,7 @@ impl ExecutingFrame<'_> {
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::DeleteGlobal(idx) => {
|
||||
let name = &self.code.names[*idx];
|
||||
let name = &self.code.names[*idx as usize];
|
||||
match self.globals.del_item(name.clone(), vm) {
|
||||
Ok(()) => {}
|
||||
Err(e) if e.isinstance(&vm.ctx.exceptions.key_error) => {
|
||||
@@ -551,11 +553,11 @@ impl ExecutingFrame<'_> {
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::DeleteDeref(i) => {
|
||||
self.cells_frees[*i].set(None);
|
||||
self.cells_frees[*i as usize].set(None);
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::LoadClosure(i) => {
|
||||
let value = self.cells_frees[*i].clone();
|
||||
let value = self.cells_frees[*i as usize].clone();
|
||||
self.push_value(value.into_object());
|
||||
Ok(None)
|
||||
}
|
||||
@@ -577,31 +579,40 @@ impl ExecutingFrame<'_> {
|
||||
bytecode::Instruction::Rotate { amount } => self.execute_rotate(*amount),
|
||||
bytecode::Instruction::BuildString { size } => {
|
||||
let s = self
|
||||
.pop_multiple(*size)
|
||||
.into_iter()
|
||||
.map(|pyobj| pystr::clone_value(&pyobj))
|
||||
.pop_multiple(*size as usize)
|
||||
.as_slice()
|
||||
.iter()
|
||||
.map(|pyobj| pystr::borrow_value(&pyobj))
|
||||
.collect::<String>();
|
||||
let str_obj = vm.ctx.new_str(s);
|
||||
self.push_value(str_obj);
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::BuildList { size, unpack } => {
|
||||
let elements = self.get_elements(vm, *size, *unpack)?;
|
||||
let elements = self.get_elements(vm, *size as usize, *unpack)?;
|
||||
let list_obj = vm.ctx.new_list(elements);
|
||||
self.push_value(list_obj);
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::BuildSet { size, unpack } => {
|
||||
let elements = self.get_elements(vm, *size, *unpack)?;
|
||||
let set = vm.ctx.new_set();
|
||||
for item in elements {
|
||||
set.add(item, vm)?;
|
||||
{
|
||||
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)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
self.push_value(set.into_object());
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::BuildTuple { size, unpack } => {
|
||||
let elements = self.get_elements(vm, *size, *unpack)?;
|
||||
let elements = self.get_elements(vm, *size as usize, *unpack)?;
|
||||
let list_obj = vm.ctx.new_tuple(elements);
|
||||
self.push_value(list_obj);
|
||||
Ok(None)
|
||||
@@ -611,7 +622,7 @@ impl ExecutingFrame<'_> {
|
||||
unpack,
|
||||
for_call,
|
||||
} => self.execute_build_map(vm, *size, *unpack, *for_call),
|
||||
bytecode::Instruction::BuildSlice { size } => self.execute_build_slice(vm, *size),
|
||||
bytecode::Instruction::BuildSlice { step } => self.execute_build_slice(vm, *step),
|
||||
bytecode::Instruction::ListAppend { i } => {
|
||||
let list_obj = self.nth_value(*i);
|
||||
let item = self.pop_value();
|
||||
@@ -639,8 +650,9 @@ impl ExecutingFrame<'_> {
|
||||
PyDictRef::try_from_object(vm, dict_obj)?.set_item(key, value, vm)?;
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::BinaryOperation { ref op, inplace } => {
|
||||
self.execute_binop(vm, op, *inplace)
|
||||
bytecode::Instruction::BinaryOperation { op } => self.execute_binop(vm, *op),
|
||||
bytecode::Instruction::BinaryOperationInplace { op } => {
|
||||
self.execute_binop_inplace(vm, *op)
|
||||
}
|
||||
bytecode::Instruction::LoadAttr { idx } => self.load_attr(vm, *idx),
|
||||
bytecode::Instruction::StoreAttr { idx } => self.store_attr(vm, *idx),
|
||||
@@ -668,11 +680,8 @@ impl ExecutingFrame<'_> {
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::SetupLoop { start, end } => {
|
||||
self.push_block(BlockType::Loop {
|
||||
start: *start,
|
||||
end: *end,
|
||||
});
|
||||
bytecode::Instruction::SetupLoop { end } => {
|
||||
self.push_block(BlockType::Loop { end: *end });
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::SetupExcept { handler } => {
|
||||
@@ -812,8 +821,16 @@ impl ExecutingFrame<'_> {
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::ForIter { target } => self.execute_for_iter(vm, *target),
|
||||
bytecode::Instruction::MakeFunction => self.execute_make_function(vm),
|
||||
bytecode::Instruction::CallFunction { typ } => self.execute_call_function(vm, typ),
|
||||
bytecode::Instruction::MakeFunction(flags) => self.execute_make_function(vm, *flags),
|
||||
bytecode::Instruction::CallFunctionPositional { nargs } => {
|
||||
self.execute_call_function_positional(vm, *nargs)
|
||||
}
|
||||
bytecode::Instruction::CallFunctionKeyword { nargs } => {
|
||||
self.execute_call_function_keyword(vm, *nargs)
|
||||
}
|
||||
bytecode::Instruction::CallFunctionEx { has_kwargs } => {
|
||||
self.execute_call_function_ex(vm, *has_kwargs)
|
||||
}
|
||||
bytecode::Instruction::Jump { target } => {
|
||||
self.jump(*target);
|
||||
Ok(None)
|
||||
@@ -858,10 +875,12 @@ impl ExecutingFrame<'_> {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
bytecode::Instruction::Raise { argc } => self.execute_raise(vm, *argc),
|
||||
bytecode::Instruction::Raise { kind } => self.execute_raise(vm, *kind),
|
||||
|
||||
bytecode::Instruction::Break => self.unwind_blocks(vm, UnwindReason::Break),
|
||||
bytecode::Instruction::Continue => self.unwind_blocks(vm, UnwindReason::Continue),
|
||||
bytecode::Instruction::Continue { target } => {
|
||||
self.unwind_blocks(vm, UnwindReason::Continue { target: *target })
|
||||
}
|
||||
bytecode::Instruction::PrintExpr => {
|
||||
let expr = self.pop_value();
|
||||
|
||||
@@ -888,7 +907,7 @@ impl ExecutingFrame<'_> {
|
||||
e
|
||||
}
|
||||
})?;
|
||||
let msg = match elements.len().cmp(size) {
|
||||
let msg = match elements.len().cmp(&(*size as usize)) {
|
||||
std::cmp::Ordering::Equal => {
|
||||
for element in elements.into_iter().rev() {
|
||||
self.push_value(element);
|
||||
@@ -914,12 +933,13 @@ impl ExecutingFrame<'_> {
|
||||
self.execute_unpack_ex(vm, *before, *after)
|
||||
}
|
||||
bytecode::Instruction::FormatValue { conversion } => {
|
||||
use bytecode::ConversionFlag::*;
|
||||
use bytecode::ConversionFlag;
|
||||
let value = self.pop_value();
|
||||
let value = match conversion {
|
||||
Some(Str) => vm.to_str(&self.pop_value())?.into_object(),
|
||||
Some(Repr) => vm.to_repr(&self.pop_value())?.into_object(),
|
||||
Some(Ascii) => vm.ctx.new_str(builtins::ascii(self.pop_value(), vm)?),
|
||||
None => self.pop_value(),
|
||||
ConversionFlag::Str => vm.to_str(&value)?.into_object(),
|
||||
ConversionFlag::Repr => vm.to_repr(&value)?.into_object(),
|
||||
ConversionFlag::Ascii => vm.ctx.new_str(builtins::ascii(value, vm)?),
|
||||
ConversionFlag::None => value,
|
||||
};
|
||||
|
||||
let spec = self.pop_value();
|
||||
@@ -938,7 +958,7 @@ impl ExecutingFrame<'_> {
|
||||
}
|
||||
bytecode::Instruction::Reverse { amount } => {
|
||||
let stack_len = self.state.stack.len();
|
||||
self.state.stack[stack_len - amount..stack_len].reverse();
|
||||
self.state.stack[stack_len - *amount as usize..stack_len].reverse();
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
@@ -966,27 +986,17 @@ impl ExecutingFrame<'_> {
|
||||
}
|
||||
Ok(result)
|
||||
} else {
|
||||
Ok(elements)
|
||||
Ok(elements.collect())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "flame-it", flame("Frame"))]
|
||||
fn import(
|
||||
&mut self,
|
||||
vm: &VirtualMachine,
|
||||
module: Option<bytecode::NameIdx>,
|
||||
symbols: &[bytecode::NameIdx],
|
||||
level: usize,
|
||||
) -> FrameResult {
|
||||
let module = match module {
|
||||
Some(idx) => self.code.names[idx].borrow_value(),
|
||||
None => "",
|
||||
};
|
||||
let from_list = symbols
|
||||
.iter()
|
||||
.map(|&idx| self.code.names[idx].clone())
|
||||
.collect::<Vec<_>>();
|
||||
let module = vm.import(&module, &from_list, level)?;
|
||||
fn import(&mut self, vm: &VirtualMachine, module: Option<PyStrRef>) -> FrameResult {
|
||||
let module = module.unwrap_or_else(|| PyStr::from("").into_ref(vm));
|
||||
let from_list = <Option<PyTupleTyped<PyStrRef>>>::try_from_object(vm, self.pop_value())?;
|
||||
let level = usize::try_from_object(vm, self.pop_value())?;
|
||||
|
||||
let module = vm.import(module, from_list, level)?;
|
||||
|
||||
self.push_value(module);
|
||||
Ok(None)
|
||||
@@ -995,7 +1005,7 @@ impl ExecutingFrame<'_> {
|
||||
#[cfg_attr(feature = "flame-it", flame("Frame"))]
|
||||
fn import_from(&mut self, vm: &VirtualMachine, idx: bytecode::NameIdx) -> FrameResult {
|
||||
let module = self.last_value();
|
||||
let name = &self.code.names[idx];
|
||||
let name = &self.code.names[idx as usize];
|
||||
// Load attribute, and transform any error into import error.
|
||||
let obj = vm.get_attribute(module, name.clone()).map_err(|_| {
|
||||
vm.new_import_error(format!("cannot import name '{}'", name), name.clone())
|
||||
@@ -1040,14 +1050,14 @@ impl ExecutingFrame<'_> {
|
||||
// First unwind all existing blocks on the block stack:
|
||||
while let Some(block) = self.current_block() {
|
||||
match block.typ {
|
||||
BlockType::Loop { start, end } => match &reason {
|
||||
BlockType::Loop { end } => match &reason {
|
||||
UnwindReason::Break => {
|
||||
self.pop_block();
|
||||
self.jump(end);
|
||||
return Ok(None);
|
||||
}
|
||||
UnwindReason::Continue => {
|
||||
self.jump(start);
|
||||
UnwindReason::Continue { target } => {
|
||||
self.jump(*target);
|
||||
return Ok(None);
|
||||
}
|
||||
_ => {
|
||||
@@ -1094,13 +1104,13 @@ impl ExecutingFrame<'_> {
|
||||
match reason {
|
||||
UnwindReason::Raising { exception } => Err(exception),
|
||||
UnwindReason::Returning { value } => Ok(Some(ExecutionResult::Return(value))),
|
||||
UnwindReason::Break | UnwindReason::Continue => {
|
||||
UnwindReason::Break | UnwindReason::Continue { .. } => {
|
||||
panic!("Internal error: break or continue must occur within a loop block.")
|
||||
} // UnwindReason::NoWorries => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
fn execute_rotate(&mut self, amount: usize) -> FrameResult {
|
||||
fn execute_rotate(&mut self, amount: u32) -> FrameResult {
|
||||
// Shuffles top of stack amount down
|
||||
if amount < 2 {
|
||||
panic!("Can only rotate two or more values");
|
||||
@@ -1150,10 +1160,11 @@ impl ExecutingFrame<'_> {
|
||||
fn execute_build_map(
|
||||
&mut self,
|
||||
vm: &VirtualMachine,
|
||||
size: usize,
|
||||
size: u32,
|
||||
unpack: bool,
|
||||
for_call: bool,
|
||||
) -> FrameResult {
|
||||
let size = size as usize;
|
||||
let map_obj = vm.ctx.new_dict();
|
||||
if unpack {
|
||||
for obj in self.pop_multiple(size) {
|
||||
@@ -1176,7 +1187,7 @@ impl ExecutingFrame<'_> {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (key, value) in self.pop_multiple(2 * size).into_iter().tuples() {
|
||||
for (key, value) in self.pop_multiple(2 * size).tuples() {
|
||||
map_obj.set_item(key, value, vm).unwrap();
|
||||
}
|
||||
}
|
||||
@@ -1185,14 +1196,8 @@ impl ExecutingFrame<'_> {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn execute_build_slice(&mut self, vm: &VirtualMachine, size: usize) -> FrameResult {
|
||||
assert!(size == 2 || size == 3);
|
||||
|
||||
let step = if size == 3 {
|
||||
Some(self.pop_value())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
fn execute_build_slice(&mut self, vm: &VirtualMachine, step: bool) -> FrameResult {
|
||||
let step = if step { Some(self.pop_value()) } else { None };
|
||||
let stop = self.pop_value();
|
||||
let start = self.pop_value();
|
||||
|
||||
@@ -1206,68 +1211,67 @@ impl ExecutingFrame<'_> {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn execute_call_function(
|
||||
&mut self,
|
||||
vm: &VirtualMachine,
|
||||
typ: &bytecode::CallType,
|
||||
) -> FrameResult {
|
||||
let args = match typ {
|
||||
bytecode::CallType::Positional(count) => {
|
||||
let args: Vec<PyObjectRef> = self.pop_multiple(*count);
|
||||
FuncArgs {
|
||||
args,
|
||||
kwargs: IndexMap::new(),
|
||||
}
|
||||
}
|
||||
bytecode::CallType::Keyword(count) => {
|
||||
let kwarg_names = self.pop_value();
|
||||
let args: Vec<PyObjectRef> = self.pop_multiple(*count);
|
||||
|
||||
let kwarg_names = vm
|
||||
.extract_elements(&kwarg_names)?
|
||||
.iter()
|
||||
.map(|pyobj| pystr::clone_value(pyobj))
|
||||
.collect();
|
||||
FuncArgs::with_kwargs_names(args, kwarg_names)
|
||||
}
|
||||
bytecode::CallType::Ex(has_kwargs) => {
|
||||
let kwargs = if *has_kwargs {
|
||||
let kw_dict: PyDictRef = self.pop_value().downcast().map_err(|_| {
|
||||
// TODO: check collections.abc.Mapping
|
||||
vm.new_type_error("Kwargs must be a dict.".to_owned())
|
||||
})?;
|
||||
let mut kwargs = IndexMap::new();
|
||||
for (key, value) in kw_dict.into_iter() {
|
||||
let key = key.payload_if_subclass::<pystr::PyStr>(vm).ok_or_else(|| {
|
||||
vm.new_type_error("keywords must be strings".to_owned())
|
||||
})?;
|
||||
kwargs.insert(key.borrow_value().to_owned(), value);
|
||||
}
|
||||
kwargs
|
||||
} else {
|
||||
IndexMap::new()
|
||||
};
|
||||
let args = self.pop_value();
|
||||
let args = vm.extract_elements(&args)?;
|
||||
FuncArgs { args, kwargs }
|
||||
}
|
||||
fn execute_call_function_positional(&mut self, vm: &VirtualMachine, nargs: u32) -> FrameResult {
|
||||
let args = FuncArgs {
|
||||
args: self.pop_multiple(nargs as usize).collect(),
|
||||
kwargs: IndexMap::new(),
|
||||
};
|
||||
|
||||
// Call function:
|
||||
// eprintln!(
|
||||
// "calling from {} {:?}",
|
||||
// self.code.obj_name,
|
||||
// self.code.locations[self.lasti.load(Ordering::Relaxed)]
|
||||
// );
|
||||
let func_ref = self.pop_value();
|
||||
let value = vm.invoke(&func_ref, args)?;
|
||||
self.push_value(value);
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn execute_raise(&mut self, vm: &VirtualMachine, argc: usize) -> FrameResult {
|
||||
let cause = match argc {
|
||||
2 => {
|
||||
fn execute_call_function_keyword(&mut self, vm: &VirtualMachine, nargs: u32) -> FrameResult {
|
||||
let kwarg_names = self
|
||||
.pop_value()
|
||||
.downcast::<PyTuple>()
|
||||
.expect("kwarg names should be tuple of strings");
|
||||
let args = self.pop_multiple(nargs as usize);
|
||||
|
||||
let kwarg_names = kwarg_names
|
||||
.borrow_value()
|
||||
.iter()
|
||||
.map(|pyobj| pystr::clone_value(pyobj));
|
||||
let args = FuncArgs::with_kwargs_names(args, kwarg_names);
|
||||
|
||||
let func_ref = self.pop_value();
|
||||
let value = vm.invoke(&func_ref, args)?;
|
||||
self.push_value(value);
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn execute_call_function_ex(&mut self, vm: &VirtualMachine, has_kwargs: bool) -> FrameResult {
|
||||
let kwargs = if has_kwargs {
|
||||
let kw_dict: PyDictRef = self.pop_value().downcast().map_err(|_| {
|
||||
// TODO: check collections.abc.Mapping
|
||||
vm.new_type_error("Kwargs must be a dict.".to_owned())
|
||||
})?;
|
||||
let mut kwargs = IndexMap::new();
|
||||
for (key, value) in kw_dict.into_iter() {
|
||||
let key = key
|
||||
.payload_if_subclass::<pystr::PyStr>(vm)
|
||||
.ok_or_else(|| vm.new_type_error("keywords must be strings".to_owned()))?;
|
||||
kwargs.insert(key.borrow_value().to_owned(), value);
|
||||
}
|
||||
kwargs
|
||||
} else {
|
||||
IndexMap::new()
|
||||
};
|
||||
let args = self.pop_value();
|
||||
let args = vm.extract_elements(&args)?;
|
||||
let args = FuncArgs { args, kwargs };
|
||||
|
||||
let func_ref = self.pop_value();
|
||||
let value = vm.invoke(&func_ref, args)?;
|
||||
self.push_value(value);
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn execute_raise(&mut self, vm: &VirtualMachine, kind: bytecode::RaiseKind) -> FrameResult {
|
||||
let cause = match kind {
|
||||
bytecode::RaiseKind::RaiseCause => {
|
||||
let val = self.pop_value();
|
||||
Some(if vm.is_none(&val) {
|
||||
// if the cause arg is none, we clear the cause
|
||||
@@ -1278,19 +1282,19 @@ impl ExecutingFrame<'_> {
|
||||
})
|
||||
}
|
||||
// if there's no cause arg, we keep the cause as is
|
||||
_ => None,
|
||||
bytecode::RaiseKind::Raise | bytecode::RaiseKind::Reraise => None,
|
||||
};
|
||||
let exception = match argc {
|
||||
0 => vm
|
||||
let exception = match kind {
|
||||
bytecode::RaiseKind::RaiseCause | bytecode::RaiseKind::Raise => {
|
||||
ExceptionCtor::try_from_object(vm, self.pop_value())?.instantiate(vm)?
|
||||
}
|
||||
bytecode::RaiseKind::Reraise => vm
|
||||
.current_exception()
|
||||
.ok_or_else(|| vm.new_runtime_error("No active exception to reraise".to_owned()))?,
|
||||
1 | 2 => ExceptionCtor::try_from_object(vm, self.pop_value())?.instantiate(vm)?,
|
||||
3 => panic!("Not implemented!"),
|
||||
_ => panic!("Invalid parameter for RAISE_VARARGS, must be between 0 to 3"),
|
||||
};
|
||||
let context = match argc {
|
||||
0 => None, // We have already got the exception,
|
||||
_ => vm.current_exception(),
|
||||
let context = match kind {
|
||||
bytecode::RaiseKind::RaiseCause | bytecode::RaiseKind::Raise => vm.current_exception(),
|
||||
bytecode::RaiseKind::Reraise => None, // We have already got the current exception
|
||||
};
|
||||
info!(
|
||||
"Exception raised: {:?} with cause: {:?} and context: {:?}",
|
||||
@@ -1343,12 +1347,8 @@ impl ExecutingFrame<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
fn execute_unpack_ex(
|
||||
&mut self,
|
||||
vm: &VirtualMachine,
|
||||
before: usize,
|
||||
after: usize,
|
||||
) -> FrameResult {
|
||||
fn execute_unpack_ex(&mut self, vm: &VirtualMachine, before: u8, after: u8) -> FrameResult {
|
||||
let (before, after) = (before as usize, after as usize);
|
||||
let value = self.pop_value();
|
||||
let elements = vm.extract_elements::<PyObjectRef>(&value)?;
|
||||
let min_expected = before + after;
|
||||
@@ -1412,7 +1412,11 @@ impl ExecutingFrame<'_> {
|
||||
}
|
||||
}
|
||||
}
|
||||
fn execute_make_function(&mut self, vm: &VirtualMachine) -> FrameResult {
|
||||
fn execute_make_function(
|
||||
&mut self,
|
||||
vm: &VirtualMachine,
|
||||
flags: bytecode::MakeFunctionFlags,
|
||||
) -> FrameResult {
|
||||
let qualified_name = self
|
||||
.pop_value()
|
||||
.downcast::<PyStr>()
|
||||
@@ -1422,21 +1426,19 @@ impl ExecutingFrame<'_> {
|
||||
.downcast()
|
||||
.expect("Second to top value on the stack must be a code object");
|
||||
|
||||
let flags = code_obj.flags;
|
||||
|
||||
let closure = if code_obj.freevars.is_empty() {
|
||||
None
|
||||
} else {
|
||||
let closure = if flags.contains(bytecode::MakeFunctionFlags::CLOSURE) {
|
||||
Some(PyTupleTyped::try_from_object(vm, self.pop_value()).unwrap())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let annotations = if flags.contains(bytecode::CodeFlags::HAS_ANNOTATIONS) {
|
||||
let annotations = if flags.contains(bytecode::MakeFunctionFlags::ANNOTATIONS) {
|
||||
self.pop_value()
|
||||
} else {
|
||||
vm.ctx.new_dict().into_object()
|
||||
};
|
||||
|
||||
let kw_only_defaults = if flags.contains(bytecode::CodeFlags::HAS_KW_ONLY_DEFAULTS) {
|
||||
let kw_only_defaults = if flags.contains(bytecode::MakeFunctionFlags::KW_ONLY_DEFAULTS) {
|
||||
Some(
|
||||
self.pop_value()
|
||||
.downcast::<PyDict>()
|
||||
@@ -1446,7 +1448,7 @@ impl ExecutingFrame<'_> {
|
||||
None
|
||||
};
|
||||
|
||||
let defaults = if flags.contains(bytecode::CodeFlags::HAS_DEFAULTS) {
|
||||
let defaults = if flags.contains(bytecode::MakeFunctionFlags::DEFAULTS) {
|
||||
Some(
|
||||
self.pop_value()
|
||||
.downcast::<PyTuple>()
|
||||
@@ -1486,47 +1488,50 @@ impl ExecutingFrame<'_> {
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "flame-it", flame("Frame"))]
|
||||
fn execute_binop(
|
||||
fn execute_binop(&mut self, vm: &VirtualMachine, op: bytecode::BinaryOperator) -> FrameResult {
|
||||
let b_ref = &self.pop_value();
|
||||
let a_ref = &self.pop_value();
|
||||
let value = match op {
|
||||
bytecode::BinaryOperator::Subtract => vm._sub(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Add => vm._add(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Multiply => vm._mul(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::MatrixMultiply => vm._matmul(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Power => vm._pow(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Divide => vm._truediv(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::FloorDivide => vm._floordiv(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Modulo => vm._mod(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Lshift => vm._lshift(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Rshift => vm._rshift(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Xor => vm._xor(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Or => vm._or(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::And => vm._and(a_ref, b_ref),
|
||||
}?;
|
||||
|
||||
self.push_value(value);
|
||||
Ok(None)
|
||||
}
|
||||
fn execute_binop_inplace(
|
||||
&mut self,
|
||||
vm: &VirtualMachine,
|
||||
op: &bytecode::BinaryOperator,
|
||||
inplace: bool,
|
||||
op: bytecode::BinaryOperator,
|
||||
) -> FrameResult {
|
||||
let b_ref = &self.pop_value();
|
||||
let a_ref = &self.pop_value();
|
||||
let value = if inplace {
|
||||
match *op {
|
||||
bytecode::BinaryOperator::Subtract => vm._isub(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Add => vm._iadd(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Multiply => vm._imul(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::MatrixMultiply => vm._imatmul(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Power => vm._ipow(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Divide => vm._itruediv(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::FloorDivide => vm._ifloordiv(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Modulo => vm._imod(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Lshift => vm._ilshift(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Rshift => vm._irshift(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Xor => vm._ixor(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Or => vm._ior(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::And => vm._iand(a_ref, b_ref),
|
||||
}?
|
||||
} else {
|
||||
match *op {
|
||||
bytecode::BinaryOperator::Subtract => vm._sub(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Add => vm._add(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Multiply => vm._mul(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::MatrixMultiply => vm._matmul(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Power => vm._pow(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Divide => vm._truediv(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::FloorDivide => vm._floordiv(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Modulo => vm._mod(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Lshift => vm._lshift(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Rshift => vm._rshift(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Xor => vm._xor(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Or => vm._or(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::And => vm._and(a_ref, b_ref),
|
||||
}?
|
||||
};
|
||||
let value = match op {
|
||||
bytecode::BinaryOperator::Subtract => vm._isub(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Add => vm._iadd(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Multiply => vm._imul(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::MatrixMultiply => vm._imatmul(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Power => vm._ipow(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Divide => vm._itruediv(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::FloorDivide => vm._ifloordiv(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Modulo => vm._imod(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Lshift => vm._ilshift(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Rshift => vm._irshift(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Xor => vm._ixor(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Or => vm._ior(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::And => vm._iand(a_ref, b_ref),
|
||||
}?;
|
||||
|
||||
self.push_value(value);
|
||||
Ok(None)
|
||||
@@ -1610,7 +1615,7 @@ impl ExecutingFrame<'_> {
|
||||
}
|
||||
|
||||
fn load_attr(&mut self, vm: &VirtualMachine, attr: bytecode::NameIdx) -> FrameResult {
|
||||
let attr_name = self.code.names[attr].clone();
|
||||
let attr_name = self.code.names[attr as usize].clone();
|
||||
let parent = self.pop_value();
|
||||
let obj = vm.get_attribute(parent, attr_name)?;
|
||||
self.push_value(obj);
|
||||
@@ -1618,7 +1623,7 @@ impl ExecutingFrame<'_> {
|
||||
}
|
||||
|
||||
fn store_attr(&mut self, vm: &VirtualMachine, attr: bytecode::NameIdx) -> FrameResult {
|
||||
let attr_name = self.code.names[attr].clone();
|
||||
let attr_name = self.code.names[attr as usize].clone();
|
||||
let parent = self.pop_value();
|
||||
let value = self.pop_value();
|
||||
vm.set_attr(&parent, attr_name, value)?;
|
||||
@@ -1626,13 +1631,13 @@ impl ExecutingFrame<'_> {
|
||||
}
|
||||
|
||||
fn delete_attr(&mut self, vm: &VirtualMachine, attr: bytecode::NameIdx) -> FrameResult {
|
||||
let attr_name = self.code.names[attr].clone().into_object();
|
||||
let attr_name = self.code.names[attr as usize].clone().into_object();
|
||||
let parent = self.pop_value();
|
||||
vm.del_attr(&parent, attr_name)?;
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn lasti(&self) -> usize {
|
||||
fn lasti(&self) -> u32 {
|
||||
// it's okay to make this Relaxed, because we know that we only
|
||||
// mutate lasti if the mutex is held, and any other thread that
|
||||
// wants to guarantee the value of this will use a Lock anyway
|
||||
@@ -1667,20 +1672,17 @@ impl ExecutingFrame<'_> {
|
||||
.expect("Tried to pop value but there was nothing on the stack")
|
||||
}
|
||||
|
||||
fn pop_multiple(&mut self, count: usize) -> Vec<PyObjectRef> {
|
||||
fn pop_multiple(&mut self, count: usize) -> std::vec::Drain<PyObjectRef> {
|
||||
let stack_len = self.state.stack.len();
|
||||
self.state
|
||||
.stack
|
||||
.drain(stack_len - count..stack_len)
|
||||
.collect()
|
||||
self.state.stack.drain(stack_len - count..stack_len)
|
||||
}
|
||||
|
||||
fn last_value(&self) -> PyObjectRef {
|
||||
self.state.stack.last().unwrap().clone()
|
||||
}
|
||||
|
||||
fn nth_value(&self, depth: usize) -> PyObjectRef {
|
||||
self.state.stack[self.state.stack.len() - depth - 1].clone()
|
||||
fn nth_value(&self, depth: u32) -> PyObjectRef {
|
||||
self.state.stack[self.state.stack.len() - depth as usize - 1].clone()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ use crate::pyobject::{
|
||||
};
|
||||
use crate::vm::VirtualMachine;
|
||||
use indexmap::IndexMap;
|
||||
use itertools::Itertools;
|
||||
use result_like::impl_option_like;
|
||||
use std::collections::HashMap;
|
||||
use std::marker::PhantomData;
|
||||
@@ -98,15 +99,24 @@ impl FuncArgs {
|
||||
Self { args, kwargs }
|
||||
}
|
||||
|
||||
pub fn with_kwargs_names(mut args: Vec<PyObjectRef>, kwarg_names: Vec<String>) -> Self {
|
||||
pub fn with_kwargs_names<A, KW>(mut args: A, kwarg_names: KW) -> Self
|
||||
where
|
||||
A: ExactSizeIterator<Item = PyObjectRef>,
|
||||
KW: ExactSizeIterator<Item = String>,
|
||||
{
|
||||
// last `kwarg_names.len()` elements of args in order of appearance in the call signature
|
||||
let kwarg_values = args.drain((args.len() - kwarg_names.len())..);
|
||||
let total_argc = args.len();
|
||||
let kwargc = kwarg_names.len();
|
||||
let posargc = total_argc - kwargc;
|
||||
|
||||
let mut kwargs = IndexMap::new();
|
||||
for (name, value) in kwarg_names.iter().zip(kwarg_values) {
|
||||
kwargs.insert(name.clone(), value);
|
||||
let posargs = args.by_ref().take(posargc).collect();
|
||||
|
||||
let kwargs = kwarg_names.zip_eq(args).collect::<IndexMap<_, _>>();
|
||||
|
||||
FuncArgs {
|
||||
args: posargs,
|
||||
kwargs,
|
||||
}
|
||||
FuncArgs { args, kwargs }
|
||||
}
|
||||
|
||||
pub fn prepend_arg(&mut self, item: PyObjectRef) {
|
||||
|
||||
@@ -36,7 +36,7 @@ pub(crate) fn init_importlib(
|
||||
let install_external = vm.get_attribute(importlib, "_install_external_importers")?;
|
||||
vm.invoke(&install_external, ())?;
|
||||
// Set pyc magic number to commit hash. Should be changed when bytecode will be more stable.
|
||||
let importlib_external = vm.import("_frozen_importlib_external", &[], 0)?;
|
||||
let importlib_external = vm.import("_frozen_importlib_external", None, 0)?;
|
||||
let mut magic = get_git_revision().into_bytes();
|
||||
magic.truncate(4);
|
||||
if magic.len() != 4 {
|
||||
@@ -44,7 +44,7 @@ pub(crate) fn init_importlib(
|
||||
}
|
||||
vm.set_attr(&importlib_external, "MAGIC_NUMBER", vm.ctx.new_bytes(magic))?;
|
||||
let zipimport_res = (|| -> PyResult<()> {
|
||||
let zipimport = vm.import("zipimport", &[], 0)?;
|
||||
let zipimport = vm.import("zipimport", None, 0)?;
|
||||
let zipimporter = vm.get_attribute(zipimport, "zipimporter")?;
|
||||
let path_hooks = vm.get_attribute(vm.sys_module.clone(), "path_hooks")?;
|
||||
let path_hooks = list::PyListRef::try_from_object(vm, path_hooks)?;
|
||||
|
||||
@@ -763,6 +763,7 @@ pub trait TryIntoRef<T: PyObjectPayload> {
|
||||
}
|
||||
|
||||
impl<T: PyObjectPayload> TryIntoRef<T> for PyRef<T> {
|
||||
#[inline]
|
||||
fn try_into_ref(self, _vm: &VirtualMachine) -> PyResult<PyRef<T>> {
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
@@ -317,7 +317,7 @@ impl Drop for PyObjectRef {
|
||||
Ok(v) => println!("{}", v.to_string()),
|
||||
Err(_) => println!("{}", del_method.class().name),
|
||||
}
|
||||
let tb_module = vm.import("traceback", &[], 0).unwrap();
|
||||
let tb_module = vm.import("traceback", None, 0).unwrap();
|
||||
// TODO: set exc traceback
|
||||
let print_stack = vm.get_attribute(tb_module, "print_stack").unwrap();
|
||||
vm.invoke(&print_stack, ()).unwrap();
|
||||
|
||||
42
vm/src/vm.rs
42
vm/src/vm.rs
@@ -22,7 +22,7 @@ use crate::builtins::object;
|
||||
use crate::builtins::pybool;
|
||||
use crate::builtins::pystr::{PyStr, PyStrRef};
|
||||
use crate::builtins::pytype::PyTypeRef;
|
||||
use crate::builtins::tuple::PyTuple;
|
||||
use crate::builtins::tuple::{PyTuple, PyTupleTyped};
|
||||
use crate::common::{hash::HashSecret, lock::PyMutex, rc::PyRc};
|
||||
#[cfg(feature = "rustpython-compiler")]
|
||||
use crate::compile::{self, CompileError, CompileErrorType, CompileOpts};
|
||||
@@ -511,7 +511,7 @@ impl VirtualMachine {
|
||||
|
||||
pub fn try_class(&self, module: &str, class: &str) -> PyResult<PyTypeRef> {
|
||||
let class = self
|
||||
.get_attribute(self.import(module, &[], 0)?, class)?
|
||||
.get_attribute(self.import(module, None, 0)?, class)?
|
||||
.downcast()
|
||||
.expect("not a class");
|
||||
Ok(class)
|
||||
@@ -519,7 +519,7 @@ impl VirtualMachine {
|
||||
|
||||
pub fn class(&self, module: &str, class: &str) -> PyTypeRef {
|
||||
let module = self
|
||||
.import(module, &[], 0)
|
||||
.import(module, None, 0)
|
||||
.unwrap_or_else(|_| panic!("unable to import {}", module));
|
||||
let class = self
|
||||
.get_attribute(module.clone(), class)
|
||||
@@ -844,16 +844,35 @@ impl VirtualMachine {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn import(&self, module: &str, from_list: &[PyStrRef], level: usize) -> PyResult {
|
||||
#[inline]
|
||||
pub fn import(
|
||||
&self,
|
||||
module: impl TryIntoRef<PyStr>,
|
||||
from_list: Option<PyTupleTyped<PyStrRef>>,
|
||||
level: usize,
|
||||
) -> PyResult {
|
||||
self._import_inner(module.try_into_ref(self)?, from_list, level)
|
||||
}
|
||||
|
||||
fn _import_inner(
|
||||
&self,
|
||||
module: PyStrRef,
|
||||
from_list: Option<PyTupleTyped<PyStrRef>>,
|
||||
level: usize,
|
||||
) -> PyResult {
|
||||
// if the import inputs seem weird, e.g a package import or something, rather than just
|
||||
// a straight `import ident`
|
||||
let weird = module.contains('.') || level != 0 || !from_list.is_empty();
|
||||
let weird = module.borrow_value().contains('.')
|
||||
|| level != 0
|
||||
|| from_list
|
||||
.as_ref()
|
||||
.map_or(false, |x| !x.borrow_value().is_empty());
|
||||
|
||||
let cached_module = if weird {
|
||||
None
|
||||
} else {
|
||||
let sys_modules = self.get_attribute(self.sys_module.clone(), "modules")?;
|
||||
sys_modules.get_item(module, self).ok()
|
||||
sys_modules.get_item(module.clone(), self).ok()
|
||||
};
|
||||
|
||||
match cached_module {
|
||||
@@ -871,7 +890,7 @@ impl VirtualMachine {
|
||||
let import_func = self
|
||||
.get_attribute(self.builtins.clone(), "__import__")
|
||||
.map_err(|_| {
|
||||
self.new_import_error("__import__ not found".to_owned(), module)
|
||||
self.new_import_error("__import__ not found".to_owned(), module.clone())
|
||||
})?;
|
||||
|
||||
let (locals, globals) = if let Some(frame) = self.current_frame() {
|
||||
@@ -879,9 +898,10 @@ impl VirtualMachine {
|
||||
} else {
|
||||
(None, None)
|
||||
};
|
||||
let from_list = self
|
||||
.ctx
|
||||
.new_tuple(from_list.iter().map(|x| x.as_object().clone()).collect());
|
||||
let from_list = match from_list {
|
||||
Some(tup) => tup.into_pyobject(self),
|
||||
None => self.ctx.new_tuple(vec![]),
|
||||
};
|
||||
self.invoke(&import_func, (module, globals, locals, from_list, level))
|
||||
.map_err(|exc| import::remove_importlib_frames(self, &exc))
|
||||
}
|
||||
@@ -1287,7 +1307,7 @@ impl VirtualMachine {
|
||||
encoding: Option<PyStrRef>,
|
||||
errors: Option<PyStrRef>,
|
||||
) -> PyResult {
|
||||
let codecsmodule = self.import("_codecs", &[], 0)?;
|
||||
let codecsmodule = self.import("_codecs", None, 0)?;
|
||||
let func = self.get_attribute(codecsmodule, func)?;
|
||||
let mut args = vec![obj, encoding.into_pyobject(self)];
|
||||
if let Some(errors) = errors {
|
||||
|
||||
Reference in New Issue
Block a user