Merge pull request #2294 from RustPython/coolreader18/pyobj-constants

Store PyObjectRef in CodeObject constants
This commit is contained in:
Jeong YunWon authored and GitHub committed 2020-11-03 00:03:30 +09:00
commit 697d6eddcd
26 files changed
+730 -731

No files matched your search

Generated
+94
View File
@@ -344,6 +344,20 @@ dependencies = [
"bitflags",
]
[[package]]
name = "console"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0b1aacfaffdbff75be81c15a399b4bedf78aaefe840e8af1d299ac2ade885d2"
dependencies = [
"encode_unicode",
"lazy_static 1.4.0",
"libc",
"terminal_size",
"termios",
"winapi",
]
[[package]]
name = "constant_time_eq"
version = "0.1.5"
@@ -562,6 +576,12 @@ version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499"
[[package]]
name = "difference"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
[[package]]
name = "digest"
version = "0.8.1"
@@ -627,6 +647,12 @@ dependencies = [
"strsim 0.9.3",
]
[[package]]
name = "dtoa"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "134951f4028bdadb9b84baf4232681efbf277da25144b9b0ad65df75946c422b"
[[package]]
name = "either"
version = "1.6.1"
@@ -642,6 +668,12 @@ dependencies = [
"log",
]
[[package]]
name = "encode_unicode"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
[[package]]
name = "env_logger"
version = "0.7.1"
@@ -853,6 +885,20 @@ dependencies = [
"hashbrown",
]
[[package]]
name = "insta"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7e7528a20113cf7ca90eddfc2439c608188b6eafc0613964da2bd140c92acec"
dependencies = [
"console",
"difference",
"lazy_static 1.4.0",
"serde",
"serde_json",
"serde_yaml",
]
[[package]]
name = "instant"
version = "0.1.7"
@@ -1021,6 +1067,12 @@ dependencies = [
"vcpkg",
]
[[package]]
name = "linked-hash-map"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a"
[[package]]
name = "lock_api"
version = "0.4.1"
@@ -1628,6 +1680,7 @@ version = "0.1.2"
dependencies = [
"bincode",
"bitflags",
"bstr",
"itertools",
"lz4-compression",
"num-bigint",
@@ -1660,6 +1713,7 @@ version = "0.1.2"
dependencies = [
"arrayvec",
"indexmap",
"insta",
"itertools",
"log",
"num-complex",
@@ -1929,6 +1983,18 @@ dependencies = [
"serde",
]
[[package]]
name = "serde_yaml"
version = "0.8.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae3e2dd40a7cdc18ca80db804b7f461a39bb721160a85c9a1fa30134bf3c02a5"
dependencies = [
"dtoa",
"linked-hash-map",
"serde",
"yaml-rust",
]
[[package]]
name = "sha-1"
version = "0.8.2"
@@ -2088,6 +2154,25 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "terminal_size"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a14cd9f8c72704232f0bfc8455c0e861f0ad4eb60cc9ec8a170e231414c1e13"
dependencies = [
"libc",
"winapi",
]
[[package]]
name = "termios"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "411c5bf740737c7918b8b1fe232dca4dc9f8e754b8ad5e20966814001ed0ac6b"
dependencies = [
"libc",
]
[[package]]
name = "textwrap"
version = "0.11.0"
@@ -2524,3 +2609,12 @@ checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69"
dependencies = [
"winapi",
]
[[package]]
name = "yaml-rust"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39f0c922f1a334134dc2f7a8b67dc5d25f0735263feec974345ff706bcf20b0d"
dependencies = [
"linked-hash-map",
]
+1
View File
@@ -16,3 +16,4 @@ num-bigint = { version = "0.3", features = ["serde"] }
num-complex = { version = "0.3", features = ["serde"] }
serde = { version = "1.0", features = ["derive"] }
itertools = "0.9"
bstr = "0.2"
+239 -83
View File
@@ -2,11 +2,12 @@
//! implements bytecode structure.
use bitflags::bitflags;
use bstr::ByteSlice;
use itertools::Itertools;
use num_bigint::BigInt;
use num_complex::Complex64;
use serde::{Deserialize, Serialize};
use std::collections::{HashMap, HashSet};
use std::collections::{BTreeMap, HashSet};
use std::fmt;
/// Sourcecode location.
@@ -30,13 +31,65 @@ impl Location {
}
}
pub trait Constant: Sized {
fn borrow_constant(&self) -> BorrowedConstant<Self>;
fn into_data(self) -> ConstantData {
self.borrow_constant().into_data()
}
fn map_constant<Bag: ConstantBag>(self, bag: &Bag) -> Bag::Constant {
bag.make_constant(self.into_data())
}
}
impl Constant for ConstantData {
fn borrow_constant(&self) -> BorrowedConstant<Self> {
use BorrowedConstant::*;
match self {
ConstantData::Integer { value } => Integer { value },
ConstantData::Float { value } => Float { value: *value },
ConstantData::Complex { value } => Complex { value: *value },
ConstantData::Boolean { value } => Boolean { value: *value },
ConstantData::Str { value } => Str { value },
ConstantData::Bytes { value } => Bytes { value },
ConstantData::Code { code } => Code { code },
ConstantData::Tuple { elements } => Tuple {
elements: Box::new(elements.iter().map(|e| e.borrow_constant())),
},
ConstantData::None => None,
ConstantData::Ellipsis => Ellipsis,
}
}
fn into_data(self) -> ConstantData {
self
}
}
pub trait ConstantBag: Sized {
type Constant: Constant;
fn make_constant(&self, constant: ConstantData) -> Self::Constant;
fn make_constant_borrowed<C: Constant>(&self, constant: BorrowedConstant<C>) -> Self::Constant {
self.make_constant(constant.into_data())
}
}
#[derive(Clone)]
pub struct BasicBag;
impl ConstantBag for BasicBag {
type Constant = ConstantData;
fn make_constant(&self, constant: ConstantData) -> Self::Constant {
constant
}
fn make_constant_borrowed<C: Constant>(&self, constant: BorrowedConstant<C>) -> Self::Constant {
constant.into_data()
}
}
/// Primary container of a single code object. Each python function has
/// a codeobject. Also a module has a codeobject.
#[derive(Clone, PartialEq, Serialize, Deserialize)]
pub struct CodeObject {
pub struct CodeObject<C: Constant = ConstantData> {
pub instructions: Vec<Instruction>,
/// Jump targets.
pub label_map: HashMap<Label, usize>,
pub label_map: BTreeMap<Label, usize>,
pub locations: Vec<Location>,
pub flags: CodeFlags,
pub posonlyarg_count: usize, // Number of positional-only arguments
@@ -47,6 +100,7 @@ pub struct CodeObject {
pub source_path: String,
pub first_line_number: usize,
pub obj_name: String, // Name of the object that created this code object
pub constants: Vec<C>,
}
bitflags! {
@@ -82,7 +136,7 @@ impl CodeFlags {
];
}
#[derive(Serialize, Debug, Deserialize, Clone, Copy, PartialEq, Eq, Hash)]
#[derive(Serialize, Debug, Deserialize, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
pub struct Label(usize);
impl Label {
@@ -151,7 +205,8 @@ pub enum Instruction {
name: String,
},
LoadConst {
value: Constant,
/// index into constants vec
idx: usize,
},
UnaryOperation {
op: UnaryOperator,
@@ -317,19 +372,89 @@ pub enum CallType {
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Constant {
pub enum ConstantData {
Integer { value: BigInt },
Float { value: f64 },
Complex { value: Complex64 },
Boolean { value: bool },
String { value: String },
Str { value: String },
Bytes { value: Vec<u8> },
Code { code: Box<CodeObject> },
Tuple { elements: Vec<Constant> },
Tuple { elements: Vec<ConstantData> },
None,
Ellipsis,
}
pub enum BorrowedConstant<'a, C: Constant> {
Integer { value: &'a BigInt },
Float { value: f64 },
Complex { value: Complex64 },
Boolean { value: bool },
Str { value: &'a str },
Bytes { value: &'a [u8] },
Code { code: &'a CodeObject<C> },
Tuple { elements: BorrowedTupleIter<'a, C> },
None,
Ellipsis,
}
type BorrowedTupleIter<'a, C> = Box<dyn Iterator<Item = BorrowedConstant<'a, C>> + 'a>;
impl<C: Constant> BorrowedConstant<'_, C> {
// takes `self` because we need to consume the iterator
pub fn fmt_display(self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
BorrowedConstant::Integer { value } => write!(f, "{}", value),
BorrowedConstant::Float { value } => write!(f, "{}", value),
BorrowedConstant::Complex { value } => write!(f, "{}", value),
BorrowedConstant::Boolean { value } => {
write!(f, "{}", if value { "True" } else { "False" })
}
BorrowedConstant::Str { value } => write!(f, "{:?}", value),
BorrowedConstant::Bytes { value } => write!(f, "b{:?}", value.as_bstr()),
BorrowedConstant::Code { code } => write!(f, "{:?}", code),
BorrowedConstant::Tuple { elements } => {
write!(f, "(")?;
let mut first = true;
for c in elements {
if first {
first = false
} else {
write!(f, ", ")?;
}
c.fmt_display(f)?;
}
write!(f, ")")
}
BorrowedConstant::None => write!(f, "None"),
BorrowedConstant::Ellipsis => write!(f, "..."),
}
}
pub fn into_data(self) -> ConstantData {
use ConstantData::*;
match self {
BorrowedConstant::Integer { value } => Integer {
value: value.clone(),
},
BorrowedConstant::Float { value } => Float { value },
BorrowedConstant::Complex { value } => Complex { value },
BorrowedConstant::Boolean { value } => Boolean { value },
BorrowedConstant::Str { value } => Str {
value: value.to_owned(),
},
BorrowedConstant::Bytes { value } => Bytes {
value: value.to_owned(),
},
BorrowedConstant::Code { code } => Code {
code: Box::new(code.map_clone_bag(&BasicBag)),
},
BorrowedConstant::Tuple { elements } => Tuple {
elements: elements.map(BorrowedConstant::into_data).collect(),
},
BorrowedConstant::None => None,
BorrowedConstant::Ellipsis => Ellipsis,
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum ComparisonOperator {
Greater,
@@ -378,7 +503,7 @@ pub enum BlockType {
}
*/
impl CodeObject {
impl<C: Constant> CodeObject<C> {
#[allow(clippy::too_many_arguments)]
pub fn new(
flags: CodeFlags,
@@ -390,10 +515,10 @@ impl CodeObject {
source_path: String,
first_line_number: usize,
obj_name: String,
) -> CodeObject {
) -> Self {
CodeObject {
instructions: Vec::new(),
label_map: HashMap::new(),
label_map: BTreeMap::new(),
locations: Vec::new(),
flags,
posonlyarg_count,
@@ -404,32 +529,10 @@ impl CodeObject {
source_path,
first_line_number,
obj_name,
constants: Vec::new(),
}
}
/// Load a code object from bytes
pub fn from_bytes(data: &[u8]) -> Result<Self, Box<dyn std::error::Error>> {
let data = lz4_compression::decompress::decompress(data)
.map_err(|e| format!("lz4 error: {:?}", e))?;
bincode::deserialize::<Self>(&data).map_err(|e| e.into())
}
/// Serialize this bytecode to bytes.
pub fn to_bytes(&self) -> Vec<u8> {
let data = bincode::serialize(&self).expect("Code object must be serializable");
lz4_compression::compress::compress(&data)
}
pub fn get_constants(&self) -> impl Iterator<Item = &Constant> {
self.instructions.iter().filter_map(|x| {
if let Instruction::LoadConst { value } = x {
Some(value)
} else {
None
}
})
}
pub fn varnames(&self) -> impl Iterator<Item = &str> + '_ {
self.arg_names
.iter()
@@ -472,32 +575,96 @@ impl CodeObject {
write!(f, " ")?;
}
write!(f, "{} {:5} ", arrow, offset)?;
instruction.fmt_dis(f, &self.label_map, expand_codeobjects, level)?;
instruction.fmt_dis(
f,
&self.label_map,
&self.constants,
expand_codeobjects,
level,
)?;
}
Ok(())
}
pub fn display_expand_codeobjects<'a>(&'a self) -> impl fmt::Display + 'a {
struct Display<'a>(&'a CodeObject);
impl fmt::Display for Display<'_> {
struct Display<'a, C: Constant>(&'a CodeObject<C>);
impl<C: Constant> fmt::Display for Display<'_, C> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.display_inner(f, true, 1)
}
}
Display(self)
}
pub fn map_bag<Bag: ConstantBag>(self, bag: &Bag) -> CodeObject<Bag::Constant> {
CodeObject {
constants: self
.constants
.into_iter()
.map(|x| x.map_constant(bag))
.collect(),
instructions: self.instructions,
label_map: self.label_map,
locations: self.locations,
flags: self.flags,
posonlyarg_count: self.posonlyarg_count,
arg_names: self.arg_names,
varargs_name: self.varargs_name,
kwonlyarg_names: self.kwonlyarg_names,
varkeywords_name: self.varkeywords_name,
source_path: self.source_path,
first_line_number: self.first_line_number,
obj_name: self.obj_name,
}
}
pub fn map_clone_bag<Bag: ConstantBag>(&self, bag: &Bag) -> CodeObject<Bag::Constant> {
CodeObject {
constants: self
.constants
.iter()
.map(|x| bag.make_constant_borrowed(x.borrow_constant()))
.collect(),
instructions: self.instructions.clone(),
label_map: self.label_map.clone(),
locations: self.locations.clone(),
flags: self.flags,
posonlyarg_count: self.posonlyarg_count,
arg_names: self.arg_names.clone(),
varargs_name: self.varargs_name.clone(),
kwonlyarg_names: self.kwonlyarg_names.clone(),
varkeywords_name: self.varkeywords_name.clone(),
source_path: self.source_path.clone(),
first_line_number: self.first_line_number,
obj_name: self.obj_name.clone(),
}
}
}
impl fmt::Display for CodeObject {
impl CodeObject<ConstantData> {
/// Load a code object from bytes
pub fn from_bytes(data: &[u8]) -> Result<Self, Box<dyn std::error::Error>> {
let data = lz4_compression::decompress::decompress(data)
.map_err(|e| format!("lz4 error: {:?}", e))?;
bincode::deserialize(&data).map_err(|e| e.into())
}
/// Serialize this bytecode to bytes.
pub fn to_bytes(&self) -> Vec<u8> {
let data = bincode::serialize(&self).expect("Code object must be serializable");
lz4_compression::compress::compress(&data)
}
}
impl<C: Constant> fmt::Display for CodeObject<C> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.display_inner(f, false, 1)?;
for constant in self.get_constants() {
match constant {
Constant::Code { code } => {
write!(f, "\nDisassembly of {}\n", constant)?;
code.fmt(f)?;
}
_ => continue,
for constant in &self.constants {
if let BorrowedConstant::Code { code } = constant.borrow_constant() {
write!(f, "\nDisassembly of {:?}\n", code)?;
code.fmt(f)?;
}
}
Ok(())
@@ -505,27 +672,28 @@ impl fmt::Display for CodeObject {
}
impl Instruction {
fn fmt_dis(
fn fmt_dis<C: Constant>(
&self,
f: &mut fmt::Formatter,
label_map: &HashMap<Label, usize>,
label_map: &BTreeMap<Label, usize>,
constants: &[C],
expand_codeobjects: bool,
level: usize,
) -> fmt::Result {
macro_rules! w {
($variant:ident) => {
write!(f, "{:20}\n", stringify!($variant))
writeln!(f, stringify!($variant))
};
($variant:ident, $var:expr) => {
write!(f, "{:20} ({})\n", stringify!($variant), $var)
writeln!(f, "{:20} ({})", stringify!($variant), $var)
};
($variant:ident, $var1:expr, $var2:expr) => {
write!(f, "{:20} ({}, {})\n", stringify!($variant), $var1, $var2)
writeln!(f, "{:20} ({}, {})", stringify!($variant), $var1, $var2)
};
($variant:ident, $var1:expr, $var2:expr, $var3:expr) => {
write!(
writeln!(
f,
"{:20} ({}, {}, {})\n",
"{:20} ({}, {}, {})",
stringify!($variant),
$var1,
$var2,
@@ -555,14 +723,21 @@ impl Instruction {
DeleteSubscript => w!(DeleteSubscript),
StoreAttr { name } => w!(StoreAttr, name),
DeleteAttr { name } => w!(DeleteAttr, name),
LoadConst { value } => match value {
Constant::Code { code } if expand_codeobjects => {
writeln!(f, "LoadConst ({:?}):", code)?;
code.display_inner(f, true, level + 1)?;
Ok(())
LoadConst { idx } => {
let value = &constants[*idx];
match value.borrow_constant() {
BorrowedConstant::Code { code } if expand_codeobjects => {
writeln!(f, "{:20} ({:?}):", "LoadConst", code)?;
code.display_inner(f, true, level + 1)?;
Ok(())
}
c => {
write!(f, "{:20} (", "LoadConst")?;
c.fmt_display(f)?;
writeln!(f, ")")
}
}
_ => w!(LoadConst, value),
},
}
UnaryOperation { op } => w!(UnaryOperation, format!("{:?}", op)),
BinaryOperation { op, inplace } => w!(BinaryOperation, format!("{:?}", op), inplace),
LoadAttr { name } => w!(LoadAttr, name),
@@ -625,32 +800,13 @@ impl Instruction {
}
}
impl fmt::Display for Constant {
impl fmt::Display for ConstantData {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Constant::Integer { value } => write!(f, "{}", value),
Constant::Float { value } => write!(f, "{}", value),
Constant::Complex { value } => write!(f, "{}", value),
Constant::Boolean { value } => write!(f, "{}", value),
Constant::String { value } => write!(f, "{:?}", value),
Constant::Bytes { value } => write!(f, "{:?}", value),
Constant::Code { code } => write!(f, "{:?}", code),
Constant::Tuple { elements } => write!(
f,
"({})",
elements
.iter()
.map(|e| format!("{}", e))
.collect::<Vec<_>>()
.join(", ")
),
Constant::None => write!(f, "None"),
Constant::Ellipsis => write!(f, "Ellipsis"),
}
self.borrow_constant().fmt_display(f)
}
}
impl fmt::Debug for CodeObject {
impl<C: Constant> fmt::Debug for CodeObject<C> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
@@ -661,7 +817,7 @@ impl fmt::Debug for CodeObject {
}
#[derive(Serialize, Deserialize)]
pub struct FrozenModule {
pub code: CodeObject,
pub struct FrozenModule<C: Constant = ConstantData> {
pub code: CodeObject<C>,
pub package: bool,
}
+3
View File
@@ -15,3 +15,6 @@ rustpython-parser = { path = "../parser", version = "0.1.1" }
num-complex = { version = "0.3", features = ["serde"] }
log = "0.4"
arrayvec = "0.5"
[dev-dependencies]
insta = "1.1"
+119 -263
View File
@@ -7,8 +7,6 @@
use crate::error::{CompileError, CompileErrorType};
pub use crate::mode::Mode;
use crate::output_stream::{CodeObjectStream, OutputStream};
use crate::peephole::PeepholeOptimizer;
use crate::symboltable::{
make_symbol_table, statements_to_symbol_table, Symbol, SymbolScope, SymbolTable,
};
@@ -17,13 +15,11 @@ use num_complex::Complex64;
use rustpython_bytecode::bytecode::{self, CallType, CodeObject, Instruction, Label};
use rustpython_parser::{ast, parser};
type BasicOutputStream = PeepholeOptimizer<CodeObjectStream>;
type CompileResult<T> = Result<T, CompileError>;
/// Main structure holding the state of compilation.
struct Compiler<O: OutputStream = BasicOutputStream> {
output_stack: Vec<O>,
struct Compiler {
output_stack: Vec<CodeObject>,
symbol_table_stack: Vec<SymbolTable>,
nxt_label: usize,
source_path: String,
@@ -143,7 +139,7 @@ pub fn compile_program_single(
})
}
impl<O: OutputStream> Compiler<O> {
impl Compiler {
fn new(opts: CompileOpts, source_path: String) -> Self {
Compiler {
output_stack: Vec::new(),
@@ -174,7 +170,7 @@ impl<O: OutputStream> Compiler<O> {
}
fn push_output(&mut self, code: CodeObject) {
self.output_stack.push(code.into());
self.output_stack.push(code);
}
fn push_new_code_object(&mut self, obj_name: String) {
@@ -193,7 +189,7 @@ impl<O: OutputStream> Compiler<O> {
}
fn pop_code_object(&mut self) -> CodeObject {
self.output_stack.pop().unwrap().into()
self.output_stack.pop().unwrap()
}
fn compile_program(
@@ -206,9 +202,7 @@ impl<O: OutputStream> Compiler<O> {
let (statements, doc) = get_doc(&program.statements);
if let Some(value) = doc {
self.emit(Instruction::LoadConst {
value: bytecode::Constant::String { value },
});
self.emit_constant(bytecode::ConstantData::Str { value });
self.emit(Instruction::StoreName {
name: "__doc__".to_owned(),
scope: bytecode::NameScope::Global,
@@ -219,9 +213,7 @@ impl<O: OutputStream> Compiler<O> {
assert_eq!(self.output_stack.len(), size_before);
// Emit None at end:
self.emit(Instruction::LoadConst {
value: bytecode::Constant::None,
});
self.emit_constant(bytecode::ConstantData::None);
self.emit(Instruction::ReturnValue);
Ok(())
}
@@ -255,9 +247,7 @@ impl<O: OutputStream> Compiler<O> {
}
if !emitted_return {
self.emit(Instruction::LoadConst {
value: bytecode::Constant::None,
});
self.emit_constant(bytecode::ConstantData::None);
self.emit(Instruction::ReturnValue);
}
@@ -453,9 +443,7 @@ impl<O: OutputStream> Compiler<O> {
if is_async {
self.emit(Instruction::BeforeAsyncWith);
self.emit(Instruction::GetAwaitable);
self.emit(Instruction::LoadConst {
value: bytecode::Constant::None,
});
self.emit_constant(bytecode::ConstantData::None);
self.emit(Instruction::YieldFrom);
self.emit(Instruction::SetupAsyncWith { end: end_label });
} else {
@@ -486,9 +474,7 @@ impl<O: OutputStream> Compiler<O> {
if is_async {
self.emit(Instruction::GetAwaitable);
self.emit(Instruction::LoadConst {
value: bytecode::Constant::None,
});
self.emit_constant(bytecode::ConstantData::None);
self.emit(Instruction::YieldFrom);
}
@@ -589,7 +575,10 @@ impl<O: OutputStream> Compiler<O> {
match value {
Some(v) => {
if self.ctx.func == FunctionContext::AsyncFunction
&& self.current_output().is_generator()
&& self
.current_code()
.flags
.contains(bytecode::CodeFlags::IS_GENERATOR)
{
return Err(self.error_loc(
CompileErrorType::AsyncReturnValue,
@@ -599,9 +588,7 @@ impl<O: OutputStream> Compiler<O> {
self.compile_expression(v)?;
}
None => {
self.emit(Instruction::LoadConst {
value: bytecode::Constant::None,
});
self.emit_constant(bytecode::ConstantData::None);
}
}
@@ -687,10 +674,8 @@ impl<O: OutputStream> Compiler<O> {
let mut num_kw_only_defaults = 0;
for (kw, default) in args.kwonlyargs.iter().zip(&args.kw_defaults) {
if let Some(default) = default {
self.emit(Instruction::LoadConst {
value: bytecode::Constant::String {
value: kw.arg.clone(),
},
self.emit_constant(bytecode::ConstantData::Str {
value: kw.arg.clone(),
});
self.compile_expression(default)?;
num_kw_only_defaults += 1;
@@ -912,9 +897,7 @@ impl<O: OutputStream> Compiler<O> {
// the last instruction is a ReturnValue already, we don't need to emit it
}
_ => {
self.emit(Instruction::LoadConst {
value: bytecode::Constant::None,
});
self.emit_constant(bytecode::ConstantData::None);
self.emit(Instruction::ReturnValue);
}
}
@@ -928,10 +911,8 @@ impl<O: OutputStream> Compiler<O> {
// Return annotation:
if let Some(annotation) = returns {
// key:
self.emit(Instruction::LoadConst {
value: bytecode::Constant::String {
value: "return".to_owned(),
},
self.emit_constant(bytecode::ConstantData::Str {
value: "return".to_owned(),
});
// value:
self.compile_expression(annotation)?;
@@ -940,10 +921,8 @@ impl<O: OutputStream> Compiler<O> {
let mut visit_arg_annotation = |arg: &ast::Parameter| -> CompileResult<()> {
if let Some(annotation) = &arg.annotation {
self.emit(Instruction::LoadConst {
value: bytecode::Constant::String {
value: arg.arg.to_owned(),
},
self.emit_constant(bytecode::ConstantData::Str {
value: arg.arg.to_owned(),
});
self.compile_expression(&annotation)?;
num_annotations += 1;
@@ -976,15 +955,11 @@ impl<O: OutputStream> Compiler<O> {
code.flags |= bytecode::CodeFlags::IS_COROUTINE;
}
self.emit(Instruction::LoadConst {
value: bytecode::Constant::Code {
code: Box::new(code),
},
self.emit_constant(bytecode::ConstantData::Code {
code: Box::new(code),
});
self.emit(Instruction::LoadConst {
value: bytecode::Constant::String {
value: qualified_name,
},
self.emit_constant(bytecode::ConstantData::Str {
value: qualified_name,
});
// Turn code object into function object:
@@ -1106,10 +1081,8 @@ impl<O: OutputStream> Compiler<O> {
name: "__module__".to_owned(),
scope: bytecode::NameScope::Free,
});
self.emit(Instruction::LoadConst {
value: bytecode::Constant::String {
value: qualified_name.clone(),
},
self.emit_constant(bytecode::ConstantData::Str {
value: qualified_name.clone(),
});
self.emit(Instruction::StoreName {
name: "__qualname__".to_owned(),
@@ -1125,33 +1098,25 @@ impl<O: OutputStream> Compiler<O> {
self.emit(Instruction::SetupAnnotation);
}
self.compile_statements(new_body)?;
self.emit(Instruction::LoadConst {
value: bytecode::Constant::None,
});
self.emit_constant(bytecode::ConstantData::None);
self.emit(Instruction::ReturnValue);
let mut code = self.pop_code_object();
code.flags &= !bytecode::CodeFlags::NEW_LOCALS;
code.flags.remove(bytecode::CodeFlags::NEW_LOCALS);
self.leave_scope();
self.emit(Instruction::LoadConst {
value: bytecode::Constant::Code {
code: Box::new(code),
},
self.emit_constant(bytecode::ConstantData::Code {
code: Box::new(code),
});
self.emit(Instruction::LoadConst {
value: bytecode::Constant::String {
value: name.to_owned(),
},
self.emit_constant(bytecode::ConstantData::Str {
value: name.to_owned(),
});
// Turn code object into function object:
self.emit(Instruction::MakeFunction);
self.emit(Instruction::LoadConst {
value: bytecode::Constant::String {
value: qualified_name,
},
self.emit_constant(bytecode::ConstantData::Str {
value: qualified_name,
});
for base in bases {
@@ -1162,7 +1127,7 @@ impl<O: OutputStream> Compiler<O> {
let mut kwarg_names = vec![];
for keyword in keywords {
if let Some(name) = &keyword.name {
kwarg_names.push(bytecode::Constant::String {
kwarg_names.push(bytecode::ConstantData::Str {
value: name.to_owned(),
});
} else {
@@ -1172,10 +1137,8 @@ impl<O: OutputStream> Compiler<O> {
self.compile_expression(&keyword.value)?;
}
self.emit(Instruction::LoadConst {
value: bytecode::Constant::Tuple {
elements: kwarg_names,
},
self.emit_constant(bytecode::ConstantData::Tuple {
elements: kwarg_names,
});
self.emit(Instruction::CallFunction {
typ: CallType::Keyword(2 + keywords.len() + bases.len()),
@@ -1199,11 +1162,9 @@ impl<O: OutputStream> Compiler<O> {
// Duplicate top of stack (the function or class object)
// Doc string value:
self.emit(Instruction::LoadConst {
value: match doc_str {
Some(doc) => bytecode::Constant::String { value: doc },
None => bytecode::Constant::None, // set docstring None if not declared
},
self.emit_constant(match doc_str {
Some(doc) => bytecode::ConstantData::Str { value: doc },
None => bytecode::ConstantData::None, // set docstring None if not declared
});
}
@@ -1273,9 +1234,7 @@ impl<O: OutputStream> Compiler<O> {
handler: check_asynciter_label,
});
self.emit(Instruction::GetANext);
self.emit(Instruction::LoadConst {
value: bytecode::Constant::None,
});
self.emit_constant(bytecode::ConstantData::None);
self.emit(Instruction::YieldFrom);
self.compile_store(target)?;
self.emit(Instruction::PopBlock);
@@ -1428,10 +1387,8 @@ impl<O: OutputStream> Compiler<O> {
name: String::from("__annotations__"),
scope: bytecode::NameScope::Local,
});
self.emit(Instruction::LoadConst {
value: bytecode::Constant::String {
value: name.to_owned(),
},
self.emit_constant(bytecode::ConstantData::Str {
value: name.to_owned(),
});
self.emit(Instruction::StoreSubscript);
} else {
@@ -1730,15 +1687,15 @@ impl<O: OutputStream> Compiler<O> {
}
Number { value } => {
let const_value = match value {
ast::Number::Integer { value } => bytecode::Constant::Integer {
ast::Number::Integer { value } => bytecode::ConstantData::Integer {
value: value.clone(),
},
ast::Number::Float { value } => bytecode::Constant::Float { value: *value },
ast::Number::Complex { real, imag } => bytecode::Constant::Complex {
ast::Number::Float { value } => bytecode::ConstantData::Float { value: *value },
ast::Number::Complex { real, imag } => bytecode::ConstantData::Complex {
value: Complex64::new(*real, *imag),
},
};
self.emit(Instruction::LoadConst { value: const_value });
self.emit_constant(const_value);
}
List { elements } => {
let size = elements.len();
@@ -1781,9 +1738,7 @@ impl<O: OutputStream> Compiler<O> {
self.mark_generator();
match value {
Some(expression) => self.compile_expression(expression)?,
Option::None => self.emit(Instruction::LoadConst {
value: bytecode::Constant::None,
}),
Option::None => self.emit_constant(bytecode::ConstantData::None),
};
self.emit(Instruction::YieldValue);
}
@@ -1793,9 +1748,7 @@ impl<O: OutputStream> Compiler<O> {
}
self.compile_expression(value)?;
self.emit(Instruction::GetAwaitable);
self.emit(Instruction::LoadConst {
value: bytecode::Constant::None,
});
self.emit_constant(bytecode::ConstantData::None);
self.emit(Instruction::YieldFrom);
}
YieldFrom { value } => {
@@ -1811,39 +1764,27 @@ impl<O: OutputStream> Compiler<O> {
self.mark_generator();
self.compile_expression(value)?;
self.emit(Instruction::GetIter);
self.emit(Instruction::LoadConst {
value: bytecode::Constant::None,
});
self.emit_constant(bytecode::ConstantData::None);
self.emit(Instruction::YieldFrom);
}
True => {
self.emit(Instruction::LoadConst {
value: bytecode::Constant::Boolean { value: true },
});
self.emit_constant(bytecode::ConstantData::Boolean { value: true });
}
False => {
self.emit(Instruction::LoadConst {
value: bytecode::Constant::Boolean { value: false },
});
self.emit_constant(bytecode::ConstantData::Boolean { value: false });
}
ast::ExpressionType::None => {
self.emit(Instruction::LoadConst {
value: bytecode::Constant::None,
});
self.emit_constant(bytecode::ConstantData::None);
}
Ellipsis => {
self.emit(Instruction::LoadConst {
value: bytecode::Constant::Ellipsis,
});
self.emit_constant(bytecode::ConstantData::Ellipsis);
}
String { value } => {
ast::ExpressionType::String { value } => {
self.compile_string(value)?;
}
Bytes { value } => {
self.emit(Instruction::LoadConst {
value: bytecode::Constant::Bytes {
value: value.clone(),
},
self.emit_constant(bytecode::ConstantData::Bytes {
value: value.clone(),
});
}
Identifier { name } => {
@@ -1862,14 +1803,10 @@ impl<O: OutputStream> Compiler<O> {
self.emit(Instruction::ReturnValue);
let code = self.pop_code_object();
self.leave_scope();
self.emit(Instruction::LoadConst {
value: bytecode::Constant::Code {
code: Box::new(code),
},
});
self.emit(Instruction::LoadConst {
value: bytecode::Constant::String { value: name },
self.emit_constant(bytecode::ConstantData::Code {
code: Box::new(code),
});
self.emit_constant(bytecode::ConstantData::Str { value: name });
// Turn code object into function object:
self.emit(Instruction::MakeFunction);
@@ -1916,10 +1853,8 @@ impl<O: OutputStream> Compiler<O> {
let mut subsize = 0;
for keyword in subkeywords {
if let Some(name) = &keyword.name {
self.emit(Instruction::LoadConst {
value: bytecode::Constant::String {
value: name.to_owned(),
},
self.emit_constant(bytecode::ConstantData::Str {
value: name.to_owned(),
});
self.compile_expression(&keyword.value)?;
subsize += 1;
@@ -1980,7 +1915,7 @@ impl<O: OutputStream> Compiler<O> {
let mut kwarg_names = vec![];
for keyword in keywords {
if let Some(name) = &keyword.name {
kwarg_names.push(bytecode::Constant::String {
kwarg_names.push(bytecode::ConstantData::Str {
value: name.to_owned(),
});
} else {
@@ -1990,10 +1925,8 @@ impl<O: OutputStream> Compiler<O> {
self.compile_expression(&keyword.value)?;
}
self.emit(Instruction::LoadConst {
value: bytecode::Constant::Tuple {
elements: kwarg_names,
},
self.emit_constant(bytecode::ConstantData::Tuple {
elements: kwarg_names,
});
self.emit(Instruction::CallFunction {
typ: CallType::Keyword(count),
@@ -2189,16 +2122,12 @@ impl<O: OutputStream> Compiler<O> {
self.leave_scope();
// List comprehension code:
self.emit(Instruction::LoadConst {
value: bytecode::Constant::Code {
code: Box::new(code),
},
self.emit_constant(bytecode::ConstantData::Code {
code: Box::new(code),
});
// List comprehension function name:
self.emit(Instruction::LoadConst {
value: bytecode::Constant::String { value: name },
});
self.emit_constant(bytecode::ConstantData::Str { value: name });
// Turn code object into function object:
self.emit(Instruction::MakeFunction);
@@ -2218,9 +2147,7 @@ impl<O: OutputStream> Compiler<O> {
fn compile_string(&mut self, string: &ast::StringGroup) -> CompileResult<()> {
if let Some(value) = try_get_constant_string(string) {
self.emit(Instruction::LoadConst {
value: bytecode::Constant::String { value },
});
self.emit_constant(bytecode::ConstantData::Str { value });
} else {
match string {
ast::StringGroup::Joined { values } => {
@@ -2230,10 +2157,8 @@ impl<O: OutputStream> Compiler<O> {
self.emit(Instruction::BuildString { size: values.len() })
}
ast::StringGroup::Constant { value } => {
self.emit(Instruction::LoadConst {
value: bytecode::Constant::String {
value: value.to_owned(),
},
self.emit_constant(bytecode::ConstantData::Str {
value: value.to_owned(),
});
}
ast::StringGroup::FormattedValue {
@@ -2243,10 +2168,8 @@ impl<O: OutputStream> Compiler<O> {
} => {
match spec {
Some(spec) => self.compile_string(spec)?,
None => self.emit(Instruction::LoadConst {
value: bytecode::Constant::String {
value: String::new(),
},
None => self.emit_constant(bytecode::ConstantData::Str {
value: String::new(),
}),
};
self.compile_expression(value)?;
@@ -2312,10 +2235,19 @@ impl<O: OutputStream> Compiler<O> {
fn emit(&mut self, instruction: Instruction) {
let location = compile_location(&self.current_source_location);
// TODO: insert source filename
self.current_output().emit(instruction, location);
let code = self.current_code();
code.instructions.push(instruction);
code.locations.push(location);
}
fn current_output(&mut self) -> &mut O {
fn emit_constant(&mut self, constant: bytecode::ConstantData) {
let code = self.current_code();
let idx = code.constants.len();
code.constants.push(constant);
self.emit(Instruction::LoadConst { idx })
}
fn current_code(&mut self) -> &mut CodeObject {
self.output_stack
.last_mut()
.expect("No OutputStream on stack")
@@ -2330,7 +2262,9 @@ impl<O: OutputStream> Compiler<O> {
// Assign current position the given label
fn set_label(&mut self, label: Label) {
self.current_output().set_label(label)
let code = self.current_code();
let pos = code.instructions.len();
code.label_map.insert(label, pos);
}
fn set_source_location(&mut self, location: ast::Location) {
@@ -2350,7 +2284,7 @@ impl<O: OutputStream> Compiler<O> {
}
fn mark_generator(&mut self) {
self.current_output().mark_generator();
self.current_code().flags |= bytecode::CodeFlags::IS_GENERATOR
}
}
@@ -2404,9 +2338,7 @@ fn compile_conversion_flag(conversion_flag: ast::ConversionFlag) -> bytecode::Co
mod tests {
use super::{CompileOpts, Compiler};
use crate::symboltable::make_symbol_table;
use rustpython_bytecode::bytecode::Constant::*;
use rustpython_bytecode::bytecode::Instruction::*;
use rustpython_bytecode::bytecode::{CodeObject, Label};
use rustpython_bytecode::bytecode::CodeObject;
use rustpython_parser::parser;
fn compile_exec(source: &str) -> CodeObject {
@@ -2419,119 +2351,43 @@ mod tests {
compiler.pop_code_object()
}
macro_rules! assert_dis_snapshot {
($value:expr) => {
insta::assert_snapshot!(
insta::internals::AutoName,
$value.display_expand_codeobjects().to_string(),
stringify!($value)
)
};
}
#[test]
fn test_if_ors() {
let code = compile_exec("if True or False or False:\n pass\n");
assert_eq!(
vec![
LoadConst {
value: Boolean { value: true }
},
JumpIfTrue {
target: Label::new(1)
},
LoadConst {
value: Boolean { value: false }
},
JumpIfTrue {
target: Label::new(1)
},
LoadConst {
value: Boolean { value: false }
},
JumpIfFalse {
target: Label::new(0)
},
LoadConst { value: None },
ReturnValue
],
code.instructions
);
assert_dis_snapshot!(compile_exec(
"\
if True or False or False:
pass
"
));
}
#[test]
fn test_if_ands() {
let code = compile_exec("if True and False and False:\n pass\n");
assert_eq!(
vec![
LoadConst {
value: Boolean { value: true }
},
JumpIfFalse {
target: Label::new(0)
},
LoadConst {
value: Boolean { value: false }
},
JumpIfFalse {
target: Label::new(0)
},
LoadConst {
value: Boolean { value: false }
},
JumpIfFalse {
target: Label::new(0)
},
LoadConst { value: None },
ReturnValue
],
code.instructions
);
assert_dis_snapshot!(compile_exec(
"\
if True and False and False:
pass
"
));
}
#[test]
fn test_if_mixed() {
let code = compile_exec("if (True and False) or (False and True):\n pass\n");
assert_eq!(
vec![
LoadConst {
value: Boolean { value: true }
},
JumpIfFalse {
target: Label::new(2)
},
LoadConst {
value: Boolean { value: false }
},
JumpIfTrue {
target: Label::new(1)
},
LoadConst {
value: Boolean { value: false }
},
JumpIfFalse {
target: Label::new(0)
},
LoadConst {
value: Boolean { value: true }
},
JumpIfFalse {
target: Label::new(0)
},
LoadConst { value: None },
ReturnValue
],
code.instructions
);
}
#[test]
fn test_constant_optimization() {
let code = compile_exec("1 + 2 + 3 + 4\n1.5 * 2.5");
assert_eq!(
code.instructions,
vec![
LoadConst {
value: Integer { value: 10.into() }
},
Pop,
LoadConst {
value: Float { value: 3.75 }
},
Pop,
LoadConst { value: None },
ReturnValue,
]
);
assert_dis_snapshot!(compile_exec(
"\
if (True and False) or (False and True):
pass
"
));
}
}
-2
View File
@@ -9,6 +9,4 @@ extern crate log;
pub mod compile;
pub mod error;
pub mod mode;
pub(crate) mod output_stream;
pub mod peephole;
pub mod symboltable;
-44
View File
@@ -1,44 +0,0 @@
use rustpython_bytecode::bytecode::{CodeFlags, CodeObject, Instruction, Label, Location};
pub trait OutputStream: From<CodeObject> + Into<CodeObject> {
/// Output an instruction
fn emit(&mut self, instruction: Instruction, location: Location);
/// Set a label on an instruction
fn set_label(&mut self, label: Label);
/// Mark the inner CodeObject as a generator
fn mark_generator(&mut self);
/// Check to see if the inner CodeObject is a generator
fn is_generator(&self) -> bool;
}
pub struct CodeObjectStream {
code: CodeObject,
}
impl From<CodeObject> for CodeObjectStream {
fn from(code: CodeObject) -> Self {
CodeObjectStream { code }
}
}
impl From<CodeObjectStream> for CodeObject {
fn from(stream: CodeObjectStream) -> Self {
stream.code
}
}
impl OutputStream for CodeObjectStream {
fn emit(&mut self, instruction: Instruction, location: Location) {
self.code.instructions.push(instruction);
self.code.locations.push(location);
}
fn set_label(&mut self, label: Label) {
let position = self.code.instructions.len();
self.code.label_map.insert(label, position);
}
fn mark_generator(&mut self) {
self.code.flags |= CodeFlags::IS_GENERATOR;
}
fn is_generator(&self) -> bool {
self.code.flags.contains(CodeFlags::IS_GENERATOR)
}
}
-132
View File
@@ -1,132 +0,0 @@
use crate::output_stream::OutputStream;
use arrayvec::ArrayVec;
use rustpython_bytecode::bytecode::{CodeObject, Instruction, Label, Location};
pub mod optimizations;
const PEEPHOLE_BUFFER_SIZE: usize = 20;
pub struct InstructionMetadata {
loc: Location,
labels: Vec<Label>,
}
impl From<Vec<InstructionMetadata>> for InstructionMetadata {
fn from(metas: Vec<Self>) -> Self {
debug_assert!(!metas.is_empty(), "`metas` must not be empty");
InstructionMetadata {
loc: metas[0].loc,
labels: metas
.into_iter()
.flat_map(|meta| meta.labels.into_iter())
.collect(),
}
}
}
impl From<Location> for InstructionMetadata {
fn from(loc: Location) -> Self {
InstructionMetadata {
loc,
labels: Vec::new(),
}
}
}
pub(crate) struct PeepholeOptimizer<O: OutputStream> {
inner: O,
buffer: ArrayVec<[(Instruction, InstructionMetadata); PEEPHOLE_BUFFER_SIZE]>,
}
impl<O: OutputStream> From<CodeObject> for PeepholeOptimizer<O> {
fn from(code: CodeObject) -> Self {
Self::new(code.into())
}
}
impl<O: OutputStream> From<PeepholeOptimizer<O>> for CodeObject {
fn from(mut peep: PeepholeOptimizer<O>) -> Self {
peep.flush();
peep.inner.into()
}
}
#[macro_export]
macro_rules! apply_optimizations {
($buf:expr, $($opt:ident),*$(,)?) => {{
$($crate::peephole::optimizations::$opt($buf);)*
}};
}
impl<O: OutputStream> PeepholeOptimizer<O> {
pub fn new(inner: O) -> Self {
PeepholeOptimizer {
inner,
buffer: ArrayVec::default(),
}
}
fn inner_emit(inner: &mut O, instruction: Instruction, meta: InstructionMetadata) {
inner.emit(instruction, meta.loc);
for label in meta.labels {
inner.set_label(label);
}
}
fn push(&mut self, instruction: Instruction, meta: InstructionMetadata) {
if self.buffer.is_full() {
let (instr, meta) = self.buffer.remove(0);
Self::inner_emit(&mut self.inner, instr, meta);
}
self.buffer.push((instruction, meta));
}
fn pop(&mut self) -> (Instruction, InstructionMetadata) {
self.buffer
.pop()
.expect("Failed to pop instruction from PeepholeOptimizer buffer")
}
fn flush(&mut self) {
for (instruction, meta) in self.buffer.drain(..) {
Self::inner_emit(&mut self.inner, instruction, meta);
}
}
fn optimize(&mut self) {
apply_optimizations!(self, operator /* , unpack */);
}
}
impl<O> OutputStream for PeepholeOptimizer<O>
where
O: OutputStream,
{
fn emit(&mut self, instruction: Instruction, loc: Location) {
self.push(instruction, loc.into());
self.optimize();
}
fn set_label(&mut self, label: Label) {
if let Some(instr) = self.buffer.last_mut() {
instr.1.labels.push(label)
}
}
fn mark_generator(&mut self) {
self.inner.mark_generator()
}
fn is_generator(&self) -> bool {
self.inner.is_generator()
}
}
impl<O: OutputStream> OptimizationBuffer for PeepholeOptimizer<O> {
fn emit(&mut self, instruction: Instruction, meta: InstructionMetadata) {
self.push(instruction, meta);
}
fn pop(&mut self) -> (Instruction, InstructionMetadata) {
self.pop()
}
}
pub trait OptimizationBuffer {
fn emit(&mut self, instruction: Instruction, meta: InstructionMetadata);
fn pop(&mut self) -> (Instruction, InstructionMetadata);
}
-99
View File
@@ -1,99 +0,0 @@
use rustpython_bytecode::bytecode::{self, Instruction};
use super::{InstructionMetadata, OptimizationBuffer};
macro_rules! metas {
[$($metas:expr),*$(,)?] => {
InstructionMetadata::from(vec![$($metas),*])
};
}
macro_rules! lc {
($name:ident {$($field:tt)*}) => {
Instruction::LoadConst {
value: bytecode::Constant::$name {$($field)*},
}
};
($name:ident, $($value:tt)*) => {
lc!($name { value: $($value)* })
};
}
macro_rules! emitconst {
($buf:expr, [$($metas:expr),*$(,)?], $($arg:tt)*) => {
$buf.emit(
lc!($($arg)*),
metas![$($metas),*],
)
};
}
pub fn operator(buf: &mut impl OptimizationBuffer) {
let (instruction, meta) = buf.pop();
if let Instruction::BinaryOperation { op, inplace } = instruction {
let (rhs, rhs_meta) = buf.pop();
let (lhs, lhs_meta) = buf.pop();
macro_rules! op {
($op:ident) => {
bytecode::BinaryOperator::$op
};
}
match (op, lhs, rhs) {
(op!(Add), lc!(Integer, lhs), lc!(Integer, rhs)) => {
emitconst!(buf, [lhs_meta, rhs_meta], Integer, lhs + rhs)
}
(op!(Subtract), lc!(Integer, lhs), lc!(Integer, rhs)) => {
emitconst!(buf, [lhs_meta, rhs_meta], Integer, lhs - rhs)
}
(op!(Add), lc!(Float, lhs), lc!(Float, rhs)) => {
emitconst!(buf, [lhs_meta, rhs_meta], Float, lhs + rhs)
}
(op!(Subtract), lc!(Float, lhs), lc!(Float, rhs)) => {
emitconst!(buf, [lhs_meta, rhs_meta], Float, lhs - rhs)
}
(op!(Multiply), lc!(Float, lhs), lc!(Float, rhs)) => {
emitconst!(buf, [lhs_meta, rhs_meta], Float, lhs * rhs)
}
(op!(Divide), lc!(Float, lhs), lc!(Float, rhs)) if rhs != 0.0 => {
emitconst!(buf, [lhs_meta, rhs_meta], Float, lhs / rhs)
}
(op!(Power), lc!(Float, lhs), lc!(Float, rhs)) => {
emitconst!(buf, [lhs_meta, rhs_meta], Float, lhs.powf(rhs))
}
(op!(Add), lc!(String, mut lhs), lc!(String, rhs)) => {
lhs.push_str(&rhs);
emitconst!(buf, [lhs_meta, rhs_meta], String, lhs);
}
(op, lhs, rhs) => {
buf.emit(lhs, lhs_meta);
buf.emit(rhs, rhs_meta);
buf.emit(Instruction::BinaryOperation { op, inplace }, meta);
}
}
} else {
buf.emit(instruction, meta)
}
}
// TODO: make a version of this that doesn't miscompile `a, b = (1, 2) if True else (3, 4)`
// pub fn unpack(buf: &mut impl OptimizationBuffer) {
// let (instruction, meta) = buf.pop();
// if let Instruction::UnpackSequence { size } = instruction {
// let (arg, arg_meta) = buf.pop();
// match arg {
// Instruction::BuildTuple {
// size: tup_size,
// unpack,
// } if !unpack && tup_size == size => {
// buf.emit(
// Instruction::Reverse { amount: size },
// vec![arg_meta, meta].into(),
// );
// }
// arg => {
// buf.emit(arg, arg_meta);
// buf.emit(instruction, meta);
// }
// }
// } else {
// buf.emit(instruction, meta)
// }
// }
@@ -0,0 +1,13 @@
---
source: compiler/src/compile.rs
expression: "compile_exec(\"\\\nif True and False and False:\n pass\n\")"
---
0 LoadConst (True)
1 JumpIfFalse (6)
2 LoadConst (False)
3 JumpIfFalse (6)
4 LoadConst (False)
5 JumpIfFalse (6)
>> 6 LoadConst (None)
7 ReturnValue
@@ -0,0 +1,15 @@
---
source: compiler/src/compile.rs
expression: "compile_exec(\"\\\nif (True and False) or (False and True):\n pass\n\")"
---
0 LoadConst (True)
1 JumpIfFalse (4)
2 LoadConst (False)
3 JumpIfTrue (8)
>> 4 LoadConst (False)
5 JumpIfFalse (8)
6 LoadConst (True)
7 JumpIfFalse (8)
>> 8 LoadConst (None)
9 ReturnValue
@@ -0,0 +1,13 @@
---
source: compiler/src/compile.rs
expression: "compile_exec(\"\\\nif True or False or False:\n pass\n\")"
---
0 LoadConst (True)
1 JumpIfTrue (6)
2 LoadConst (False)
3 JumpIfTrue (6)
4 LoadConst (False)
5 JumpIfFalse (6)
>> 6 LoadConst (None)
7 ReturnValue
+10 -26
View File
@@ -15,36 +15,17 @@ use vm::pyobject::ItemProtocol;
// the program you're embedding this into doesn't take longer to start up.
macro_rules! add_python_function {
( $scope:ident, $vm:ident, $src:literal $(,)? ) => {{
// this has to be in scope to turn a PyValue into a PyRef
// (a PyRef is a special reference that points to something in the VirtualMachine)
use vm::pyobject::PyValue;
// compile the code to bytecode
let code = vm::py_compile!(source = $src);
// convert the rustpython_bytecode::CodeObject to a PyCodeRef
let code = $vm.ctx.new_code_object(code);
// takes the first constant in the file that's a function
let def = code
.get_constants()
.find_map(|c| match c {
vm::bytecode::Constant::Code { code } => Some(code),
_ => None,
})
.expect("No functions found in the provided module!");
// inserts the first function found in the module into the provided scope.
$scope.globals.set_item(
def.obj_name.as_str(),
$vm.ctx.new_pyfunction(
vm::builtins::PyCode::new(*def.clone()).into_ref(&$vm),
$scope.clone(),
None,
None,
),
&$vm,
)
// run the python code in the scope to store the function
$vm.run_code_obj(code, $scope.clone())
}};
}
static ON: AtomicBool = AtomicBool::new(false);
static ON: AtomicBool = AtomicBool::new(true);
fn on(b: bool) {
ON.store(b, Ordering::Relaxed);
@@ -69,7 +50,10 @@ fn run(vm: &vm::VirtualMachine) -> vm::pyobject::PyResult<()> {
vm,
// a fun line to test this with is
// ''.join( l * fib(i) for i, l in enumerate('supercalifragilistic') )
r#"def fib(n): return n if n <= 1 else fib(n - 1) + fib(n - 2)"#
r#"\
def fib(n):
return n if n <= 1 else fib(n - 1) + fib(n - 2)
"#
)?;
while ON.load(Ordering::Relaxed) {
+22 -12
View File
@@ -1,8 +1,8 @@
use cranelift::prelude::*;
use num_traits::cast::ToPrimitive;
use rustpython_bytecode::bytecode::{
BinaryOperator, CodeObject, ComparisonOperator, Constant, Instruction, Label, NameScope,
UnaryOperator,
self, BinaryOperator, BorrowedConstant, CodeObject, ComparisonOperator, Instruction, Label,
NameScope, UnaryOperator,
};
use std::collections::HashMap;
@@ -105,7 +105,10 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> {
.or_insert_with(|| builder.create_block())
}
pub fn compile(&mut self, bytecode: &CodeObject) -> Result<(), JitCompileError> {
pub fn compile<C: bytecode::Constant>(
&mut self,
bytecode: &CodeObject<C>,
) -> Result<(), JitCompileError> {
let offset_to_label: HashMap<&usize, &Label> =
bytecode.label_map.iter().map(|(k, v)| (v, k)).collect();
@@ -128,15 +131,18 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> {
continue;
}
self.add_instruction(&instruction)?;
self.add_instruction(&instruction, &bytecode.constants)?;
}
Ok(())
}
fn load_const(&mut self, constant: &Constant) -> Result<(), JitCompileError> {
fn load_const<C: bytecode::Constant>(
&mut self,
constant: BorrowedConstant<C>,
) -> Result<(), JitCompileError> {
match constant {
Constant::Integer { value } => {
BorrowedConstant::Integer { value } => {
let val = self.builder.ins().iconst(
types::I64,
value.to_i64().ok_or(JitCompileError::NotSupported)?,
@@ -147,16 +153,16 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> {
});
Ok(())
}
Constant::Float { value } => {
let val = self.builder.ins().f64const(*value);
BorrowedConstant::Float { value } => {
let val = self.builder.ins().f64const(value);
self.stack.push(JitValue {
val,
ty: JitType::Float,
});
Ok(())
}
Constant::Boolean { value } => {
let val = self.builder.ins().iconst(types::I8, *value as i64);
BorrowedConstant::Boolean { value } => {
let val = self.builder.ins().iconst(types::I8, value as i64);
self.stack.push(JitValue {
val,
ty: JitType::Bool,
@@ -167,7 +173,11 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> {
}
}
fn add_instruction(&mut self, instruction: &Instruction) -> Result<(), JitCompileError> {
pub fn add_instruction<C: bytecode::Constant>(
&mut self,
instruction: &Instruction,
constants: &[C],
) -> Result<(), JitCompileError> {
match instruction {
Instruction::JumpIfFalse { target } => {
let cond = self.stack.pop().ok_or(JitCompileError::BadBytecode)?;
@@ -222,7 +232,7 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> {
let val = self.stack.pop().ok_or(JitCompileError::BadBytecode)?;
self.store_variable(name.clone(), val)
}
Instruction::LoadConst { value } => self.load_const(value),
Instruction::LoadConst { idx } => self.load_const(constants[*idx].borrow_constant()),
Instruction::ReturnValue => {
let val = self.stack.pop().ok_or(JitCompileError::BadBytecode)?;
if let Some(ref ty) = self.sig.ret {
+4 -4
View File
@@ -46,9 +46,9 @@ impl Jit {
}
}
fn build_function(
fn build_function<C: bytecode::Constant>(
&mut self,
bytecode: &bytecode::CodeObject,
bytecode: &bytecode::CodeObject<C>,
args: &[JitType],
) -> Result<(FuncId, JitSig), JitCompileError> {
for arg in args {
@@ -92,8 +92,8 @@ impl Jit {
}
}
pub fn compile(
bytecode: &bytecode::CodeObject,
pub fn compile<C: bytecode::Constant>(
bytecode: &bytecode::CodeObject<C>,
args: &[JitType],
) -> Result<CompiledCode, JitCompileError> {
let mut jit = Jit::new();
+13 -9
View File
@@ -1,6 +1,6 @@
use std::collections::HashMap;
use rustpython_bytecode::bytecode::{CodeObject, Constant, Instruction, NameScope};
use rustpython_bytecode::bytecode::{CodeObject, ConstantData, Instruction, NameScope};
use rustpython_jit::{CompiledCode, JitType};
#[derive(Debug, Clone)]
@@ -39,12 +39,12 @@ enum StackValue {
Function(Function),
}
impl From<Constant> for StackValue {
fn from(value: Constant) -> Self {
impl From<ConstantData> for StackValue {
fn from(value: ConstantData) -> Self {
match value {
Constant::String { value } => StackValue::String(value),
Constant::None => StackValue::None,
Constant::Code { code } => StackValue::Code(code),
ConstantData::Str { value } => StackValue::String(value),
ConstantData::None => StackValue::None,
ConstantData::Code { code } => StackValue::Code(code),
c => unimplemented!("constant {:?} isn't yet supported in py_function!", c),
}
}
@@ -65,15 +65,19 @@ impl StackMachine {
pub fn run(&mut self, code: CodeObject) {
for instruction in code.instructions {
if self.process_instruction(instruction) {
if self.process_instruction(instruction, &code.constants) {
break;
}
}
}
fn process_instruction(&mut self, instruction: Instruction) -> bool {
fn process_instruction(
&mut self,
instruction: Instruction,
constants: &[ConstantData],
) -> bool {
match instruction {
Instruction::LoadConst { value } => self.stack.push(value.into()),
Instruction::LoadConst { idx } => self.stack.push(constants[idx].clone().into()),
Instruction::LoadName {
name,
scope: NameScope::Free,
+102 -12
View File
@@ -6,26 +6,120 @@ use std::fmt;
use std::ops::Deref;
use super::pytype::PyTypeRef;
use crate::bytecode;
use crate::pyobject::{IdProtocol, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue};
use crate::vm::VirtualMachine;
use crate::bytecode::{self, BorrowedConstant, Constant, ConstantBag};
use crate::pyobject::{
BorrowValue, IdProtocol, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue,
StaticType, TypeProtocol,
};
use crate::VirtualMachine;
use num_traits::Zero;
#[derive(Clone)]
pub struct PyConstant(pub PyObjectRef);
// pub(crate) enum PyConstant {
// Integer { value: super::int::PyIntRef },
// Float { value: super::int::PyFloatRef },
// Complex { value: super::complex::PyComplexRef },
// Boolean { value: super::int::PyIntRef },
// Str { value: super::pystr::PyStrRef },
// Bytes { value: super::bytes::PyBytesRef },
// Code { code: PyCodeRef },
// Tuple { elements: super::tuple::PyTupleRef },
// None(PyObjectRef),
// Ellipsis(PyObjectRef),
// }
fn borrow_obj_constant(obj: &PyObjectRef) -> BorrowedConstant<PyConstant> {
match_class!(match obj {
ref i @ super::int::PyInt => {
let value = i.borrow_value();
if obj.class().is(super::pybool::PyBool::static_type()) {
BorrowedConstant::Boolean {
value: !value.is_zero(),
}
} else {
BorrowedConstant::Integer { value }
}
}
ref f @ super::float::PyFloat => BorrowedConstant::Float { value: f.to_f64() },
ref c @ super::complex::PyComplex => BorrowedConstant::Complex {
value: c.to_complex()
},
ref s @ super::pystr::PyStr => BorrowedConstant::Str {
value: s.borrow_value()
},
ref b @ super::bytes::PyBytes => BorrowedConstant::Bytes {
value: b.borrow_value()
},
ref c @ PyCode => {
BorrowedConstant::Code { code: &c.code }
}
ref t @ super::tuple::PyTuple => {
BorrowedConstant::Tuple {
elements: Box::new(t.borrow_value().iter().map(borrow_obj_constant)),
}
}
super::singletons::PyNone => BorrowedConstant::None,
super::slice::PyEllipsis => BorrowedConstant::Ellipsis,
_ => panic!("unexpected payload for constant python value"),
})
}
impl Constant for PyConstant {
fn borrow_constant(&self) -> BorrowedConstant<Self> {
borrow_obj_constant(&self.0)
}
fn map_constant<Bag: ConstantBag>(self, bag: &Bag) -> Bag::Constant {
bag.make_constant_borrowed(self.borrow_constant())
}
}
pub(crate) struct PyObjBag<'a>(pub &'a PyContext);
impl ConstantBag for PyObjBag<'_> {
type Constant = PyConstant;
fn make_constant(&self, constant: bytecode::ConstantData) -> Self::Constant {
PyConstant(self.0.unwrap_constant(constant))
}
fn make_constant_borrowed<C: Constant>(&self, constant: BorrowedConstant<C>) -> Self::Constant {
// TODO: check if the constant is a string and try interning it without cloning
self.make_constant(constant.into_data())
}
}
pub type PyCodeRef = PyRef<PyCode>;
pub type CodeObject = bytecode::CodeObject<PyConstant>;
pub type FrozenModule = bytecode::FrozenModule<PyConstant>;
pub trait IntoCodeObject {
fn into_codeobj(self, ctx: &PyContext) -> CodeObject;
}
impl IntoCodeObject for CodeObject {
fn into_codeobj(self, _ctx: &PyContext) -> CodeObject {
self
}
}
impl IntoCodeObject for bytecode::CodeObject {
fn into_codeobj(self, ctx: &PyContext) -> CodeObject {
ctx.map_codeobj(self)
}
}
#[pyclass(module = false, name = "code")]
pub struct PyCode {
pub code: bytecode::CodeObject,
pub code: CodeObject,
}
impl Deref for PyCode {
type Target = bytecode::CodeObject;
type Target = CodeObject;
fn deref(&self) -> &Self::Target {
&self.code
}
}
impl PyCode {
pub fn new(code: bytecode::CodeObject) -> PyCode {
pub fn new(code: CodeObject) -> PyCode {
PyCode { code }
}
}
@@ -48,7 +142,7 @@ impl PyCode {}
#[pyimpl]
impl PyCodeRef {
#[pyslot]
fn new(_cls: PyTypeRef, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
fn tp_new(_cls: PyTypeRef, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
Err(vm.new_type_error("Cannot directly create code object".to_owned()))
}
@@ -91,11 +185,7 @@ impl PyCodeRef {
#[pyproperty]
fn co_consts(self, vm: &VirtualMachine) -> PyObjectRef {
let consts = self
.code
.get_constants()
.map(|x| vm.ctx.unwrap_constant(x))
.collect();
let consts = self.code.constants.iter().map(|x| x.0.clone()).collect();
vm.ctx.new_tuple(consts)
}
+4
View File
@@ -56,6 +56,10 @@ fn try_complex(value: &PyObjectRef, vm: &VirtualMachine) -> PyResult<Option<Comp
#[pyimpl(flags(BASETYPE), with(Comparable, Hashable))]
impl PyComplex {
pub fn to_complex(&self) -> Complex64 {
self.value
}
#[pyproperty(name = "real")]
fn real(&self) -> f64 {
self.value.re
+2 -2
View File
@@ -1,7 +1,7 @@
#[cfg(feature = "jit")]
mod jitfunc;
use super::code::PyCodeRef;
use super::code::{CodeObject, PyCodeRef};
use super::dict::PyDictRef;
use super::pystr::PyStrRef;
use super::pytype::PyTypeRef;
@@ -63,7 +63,7 @@ impl PyFunction {
fn fill_locals_from_args(
&self,
code_object: &bytecode::CodeObject,
code_object: &CodeObject,
locals: &PyDictRef,
func_args: FuncArgs,
vm: &VirtualMachine,
+2 -3
View File
@@ -350,9 +350,8 @@ impl ExecutingFrame<'_> {
}
match instruction {
bytecode::Instruction::LoadConst { ref value } => {
let obj = vm.ctx.unwrap_constant(value);
self.push_value(obj);
bytecode::Instruction::LoadConst { idx } => {
self.push_value(self.code.constants[*idx].0.clone());
Ok(None)
}
bytecode::Instruction::Import {
+22 -4
View File
@@ -1,12 +1,30 @@
use crate::bytecode::FrozenModule;
use super::pyobject::PyContext;
use crate::builtins::code;
use crate::bytecode;
use std::collections::HashMap;
pub fn get_module_inits() -> HashMap<String, FrozenModule> {
pub fn map_frozen<'a>(
ctx: &'a PyContext,
i: impl IntoIterator<Item = (String, bytecode::FrozenModule)> + 'a,
) -> impl Iterator<Item = (String, code::FrozenModule)> + 'a {
i.into_iter()
.map(move |(k, bytecode::FrozenModule { code, package })| {
(
k,
code::FrozenModule {
code: ctx.map_codeobj(code),
package,
},
)
})
}
pub fn get_module_inits(ctx: &PyContext) -> HashMap<String, code::FrozenModule> {
let mut modules = HashMap::new();
macro_rules! ext_modules {
($($t:tt)*) => {
modules.extend(py_freeze!($($t)*));
modules.extend(map_frozen(ctx, py_freeze!($($t)*)));
};
}
@@ -30,7 +48,7 @@ pub fn get_module_inits() -> HashMap<String, FrozenModule> {
// if we're on freeze-stdlib, the core stdlib modules will be included anyway
#[cfg(feature = "freeze-stdlib")]
{
modules.extend(rustpython_pylib::frozen_stdlib());
modules.extend(map_frozen(ctx, rustpython_pylib::frozen_stdlib()));
}
modules
+2 -2
View File
@@ -3,9 +3,9 @@
*/
use rand::Rng;
use crate::builtins::code::CodeObject;
use crate::builtins::traceback::{PyTraceback, PyTracebackRef};
use crate::builtins::{code, list};
use crate::bytecode::CodeObject;
use crate::exceptions::PyBaseExceptionRef;
use crate::pyobject::{ItemProtocol, PyResult, PyValue, TryFromObject, TypeProtocol};
use crate::scope::Scope;
@@ -100,7 +100,7 @@ pub fn import_file(
) -> PyResult {
let code_obj = compile::compile(&content, compile::Mode::Exec, file_path, vm.compile_opts())
.map_err(|err| vm.new_syntax_error(&err))?;
import_codeobj(vm, module_name, code_obj, true)
import_codeobj(vm, module_name, vm.ctx.map_codeobj(code_obj), true)
}
pub fn import_codeobj(
+28 -18
View File
@@ -342,8 +342,12 @@ impl PyContext {
)
}
pub fn new_code_object(&self, code: bytecode::CodeObject) -> PyCodeRef {
PyRef::new_ref(code::PyCode::new(code), self.types.code_type.clone(), None)
pub fn new_code_object(&self, code: impl code::IntoCodeObject) -> PyCodeRef {
PyRef::new_ref(
code::PyCode::new(code.into_codeobj(self)),
self.types.code_type.clone(),
None,
)
}
pub fn new_pyfunction(
@@ -377,29 +381,31 @@ impl PyContext {
.into_ref()
}
pub fn unwrap_constant(&self, value: &bytecode::Constant) -> PyObjectRef {
match *value {
bytecode::Constant::Integer { ref value } => self.new_bigint(value),
bytecode::Constant::Float { ref value } => self.new_float(*value),
bytecode::Constant::Complex { ref value } => self.new_complex(*value),
bytecode::Constant::String { ref value } => self.new_str(value.clone()),
bytecode::Constant::Bytes { ref value } => self.new_bytes(value.clone()),
bytecode::Constant::Boolean { value } => self.new_bool(value),
bytecode::Constant::Code { ref code } => {
self.new_code_object(*code.clone()).into_object()
}
bytecode::Constant::Tuple { ref elements } => {
pub fn unwrap_constant(&self, constant: bytecode::ConstantData) -> PyObjectRef {
match constant {
bytecode::ConstantData::Integer { value } => self.new_int(value),
bytecode::ConstantData::Float { value } => self.new_float(value),
bytecode::ConstantData::Complex { value } => self.new_complex(value),
bytecode::ConstantData::Str { value } => self.new_str(value),
bytecode::ConstantData::Bytes { value } => self.new_bytes(value),
bytecode::ConstantData::Boolean { value } => self.new_bool(value),
bytecode::ConstantData::Code { code } => self.new_code_object(*code).into_object(),
bytecode::ConstantData::Tuple { elements } => {
let elements = elements
.iter()
.map(|value| self.unwrap_constant(value))
.into_iter()
.map(|constant| self.unwrap_constant(constant))
.collect();
self.new_tuple(elements)
}
bytecode::Constant::None => self.none(),
bytecode::Constant::Ellipsis => self.ellipsis(),
bytecode::ConstantData::None => self.none(),
bytecode::ConstantData::Ellipsis => self.ellipsis(),
}
}
pub fn map_codeobj(&self, code: bytecode::CodeObject) -> code::CodeObject {
code.map_bag(&code::PyObjBag(self))
}
pub fn add_tp_new_wrapper(&self, ty: &PyTypeRef) {
if !ty.attributes.read().contains_key("__new__") {
let new_wrapper =
@@ -1046,6 +1052,10 @@ impl<T> PyObject<T>
where
T: ?Sized + PyObjectPayload,
{
pub fn raw_payload(&self) -> &T {
&self.payload
}
pub fn dict(&self) -> Option<PyDictRef> {
self.dict.as_ref().map(|mu| mu.read().clone().into_pyref())
}
+4 -2
View File
@@ -12,7 +12,7 @@ mod decl {
#[pyfunction]
fn dumps(co: PyCodeRef) -> PyBytes {
PyBytes::from(co.code.to_bytes())
PyBytes::from(co.code.map_clone_bag(&bytecode::BasicBag).to_bytes())
}
#[pyfunction]
@@ -25,7 +25,9 @@ mod decl {
fn loads(code_bytes: PyBytesLike, vm: &VirtualMachine) -> PyResult<PyCode> {
let code = bytecode::CodeObject::from_bytes(&*code_bytes.borrow_value())
.map_err(|_| vm.new_value_error("Couldn't deserialize python bytecode".to_owned()))?;
Ok(PyCode { code })
Ok(PyCode {
code: vm.ctx.map_codeobj(code),
})
}
#[pyfunction]
+14 -11
View File
@@ -13,8 +13,7 @@ use arr_macro::arr;
use crossbeam_utils::atomic::AtomicCell;
use num_traits::{Signed, ToPrimitive};
use crate::builtins;
use crate::builtins::code::{PyCode, PyCodeRef};
use crate::builtins::code::{self, PyCode, PyCodeRef};
use crate::builtins::dict::PyDictRef;
use crate::builtins::int::{PyInt, PyIntRef};
use crate::builtins::list::PyList;
@@ -24,22 +23,17 @@ use crate::builtins::pybool;
use crate::builtins::pystr::{PyStr, PyStrRef};
use crate::builtins::pytype::PyTypeRef;
use crate::builtins::tuple::PyTuple;
use crate::bytecode;
use crate::common::{hash::HashSecret, lock::PyMutex, rc::PyRc};
use crate::exceptions::{self, PyBaseException, PyBaseExceptionRef};
use crate::frame::{ExecutionResult, Frame, FrameRef};
use crate::frozen;
use crate::function::{FuncArgs, IntoFuncArgs};
use crate::import;
use crate::iterator;
use crate::pyobject::{
BorrowValue, Either, IdProtocol, IntoPyObject, ItemProtocol, PyArithmaticValue, PyContext,
PyObject, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject, TryIntoRef, TypeProtocol,
};
use crate::scope::Scope;
use crate::slots::PyComparisonOp;
use crate::stdlib;
use crate::sysmodule;
use crate::{builtins, bytecode, frozen, import, iterator, stdlib, sysmodule};
#[cfg(feature = "rustpython-compiler")]
use rustpython_compiler::{
compile::{self, CompileOpts},
@@ -120,13 +114,22 @@ pub(crate) mod thread {
pub struct PyGlobalState {
pub settings: PySettings,
pub stdlib_inits: HashMap<String, stdlib::StdlibInitFunc>,
pub frozen: HashMap<String, bytecode::FrozenModule>,
pub frozen: HashMap<String, code::FrozenModule>,
pub stacksize: AtomicCell<usize>,
pub thread_count: AtomicCell<usize>,
pub hash_secret: HashSecret,
pub atexit_funcs: PyMutex<Vec<(PyObjectRef, FuncArgs)>>,
}
impl PyGlobalState {
pub fn add_frozen<I>(&mut self, ctx: &PyContext, frozen: I)
where
I: IntoIterator<Item = (String, bytecode::FrozenModule)>,
{
self.frozen.extend(frozen::map_frozen(ctx, frozen))
}
}
pub const NSIG: usize = 64;
#[derive(Copy, Clone, PartialEq, Eq)]
@@ -257,7 +260,7 @@ impl VirtualMachine {
let signal_handlers = RefCell::new(arr![ctx.none(); 64]);
let stdlib_inits = stdlib::get_module_inits();
let frozen = frozen::get_module_inits();
let frozen = frozen::get_module_inits(&ctx);
let hash_secret = match settings.hash_seed {
Some(seed) => HashSecret::new(seed),
@@ -1226,7 +1229,7 @@ impl VirtualMachine {
opts: CompileOpts,
) -> Result<PyCodeRef, CompileError> {
compile::compile(source, mode, source_path, opts)
.map(|codeobj| PyCode::new(codeobj).into_ref(self))
.map(|code| PyCode::new(self.ctx.map_codeobj(code)).into_ref(self))
.map_err(|mut compile_error| {
compile_error.update_statement_info(source.trim_end().to_owned());
compile_error
+4 -3
View File
@@ -280,7 +280,8 @@ pub fn setup_browser_module(vm: &mut VirtualMachine) {
state
.stdlib_inits
.insert("_browser".to_owned(), Box::new(make_module));
state
.frozen
.extend(py_freeze!(file = "src/browser.py", module_name = "browser",));
state.add_frozen(
&vm.ctx,
py_freeze!(file = "src/browser.py", module_name = "browser"),
);
}