Skip to content

Commit c8e6ca7

Browse files
authored
Merge pull request RustPython#1451 from sanxiyn/optimize-buildmap
Optimize BuildMap bytecode emission
2 parents 9c4c39a + e4ec430 commit c8e6ca7

File tree

3 files changed

+80
-46
lines changed

3 files changed

+80
-46
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

compiler/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ edition = "2018"
99

1010
[dependencies]
1111
indexmap = "1.0"
12+
itertools = "0.8.0"
1213
rustpython-bytecode = { path = "../bytecode", version = "0.1.1" }
1314
rustpython-parser = { path = "../parser", version = "0.1.1" }
1415
num-complex = { version = "0.2", features = ["serde"] }

compiler/src/compile.rs

Lines changed: 78 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use crate::peephole::PeepholeOptimizer;
1111
use crate::symboltable::{
1212
make_symbol_table, statements_to_symbol_table, Symbol, SymbolScope, SymbolTable,
1313
};
14+
use itertools::Itertools;
1415
use num_complex::Complex64;
1516
use rustpython_bytecode::bytecode::{self, CallType, CodeObject, Instruction, Label, Varargs};
1617
use rustpython_parser::{ast, parser};
@@ -1438,6 +1439,47 @@ impl<O: OutputStream> Compiler<O> {
14381439
Ok(())
14391440
}
14401441

1442+
fn compile_dict(
1443+
&mut self,
1444+
pairs: &[(Option<ast::Expression>, ast::Expression)],
1445+
) -> Result<(), CompileError> {
1446+
let mut size = 0;
1447+
let mut has_unpacking = false;
1448+
for (is_unpacking, subpairs) in &pairs.iter().group_by(|e| e.0.is_none()) {
1449+
if is_unpacking {
1450+
for (_, value) in subpairs {
1451+
self.compile_expression(value)?;
1452+
size += 1;
1453+
}
1454+
has_unpacking = true;
1455+
} else {
1456+
let mut subsize = 0;
1457+
for (key, value) in subpairs {
1458+
if let Some(key) = key {
1459+
self.compile_expression(key)?;
1460+
self.compile_expression(value)?;
1461+
subsize += 1;
1462+
}
1463+
}
1464+
self.emit(Instruction::BuildMap {
1465+
size: subsize,
1466+
unpack: false,
1467+
});
1468+
size += 1;
1469+
}
1470+
}
1471+
if size == 0 {
1472+
self.emit(Instruction::BuildMap {
1473+
size,
1474+
unpack: false,
1475+
});
1476+
}
1477+
if size > 1 || has_unpacking {
1478+
self.emit(Instruction::BuildMap { size, unpack: true });
1479+
}
1480+
Ok(())
1481+
}
1482+
14411483
fn compile_expression(&mut self, expression: &ast::Expression) -> Result<(), CompileError> {
14421484
trace!("Compiling {:?}", expression);
14431485
self.set_source_location(&expression.location);
@@ -1521,27 +1563,7 @@ impl<O: OutputStream> Compiler<O> {
15211563
});
15221564
}
15231565
Dict { elements } => {
1524-
let size = elements.len();
1525-
let has_double_star = elements.iter().any(|e| e.0.is_none());
1526-
for (key, value) in elements {
1527-
if let Some(key) = key {
1528-
self.compile_expression(key)?;
1529-
self.compile_expression(value)?;
1530-
if has_double_star {
1531-
self.emit(Instruction::BuildMap {
1532-
size: 1,
1533-
unpack: false,
1534-
});
1535-
}
1536-
} else {
1537-
// dict unpacking
1538-
self.compile_expression(value)?;
1539-
}
1540-
}
1541-
self.emit(Instruction::BuildMap {
1542-
size,
1543-
unpack: has_double_star,
1544-
});
1566+
self.compile_dict(elements)?;
15451567
}
15461568
Slice { elements } => {
15471569
let size = elements.len();
@@ -1658,6 +1680,40 @@ impl<O: OutputStream> Compiler<O> {
16581680
Ok(())
16591681
}
16601682

1683+
fn compile_keywords(&mut self, keywords: &[ast::Keyword]) -> Result<(), CompileError> {
1684+
let mut size = 0;
1685+
for (is_unpacking, subkeywords) in &keywords.iter().group_by(|e| e.name.is_none()) {
1686+
if is_unpacking {
1687+
for keyword in subkeywords {
1688+
self.compile_expression(&keyword.value)?;
1689+
size += 1;
1690+
}
1691+
} else {
1692+
let mut subsize = 0;
1693+
for keyword in subkeywords {
1694+
if let Some(name) = &keyword.name {
1695+
self.emit(Instruction::LoadConst {
1696+
value: bytecode::Constant::String {
1697+
value: name.to_string(),
1698+
},
1699+
});
1700+
self.compile_expression(&keyword.value)?;
1701+
subsize += 1;
1702+
}
1703+
}
1704+
self.emit(Instruction::BuildMap {
1705+
size: subsize,
1706+
unpack: false,
1707+
});
1708+
size += 1;
1709+
}
1710+
}
1711+
if size > 1 {
1712+
self.emit(Instruction::BuildMap { size, unpack: true });
1713+
}
1714+
Ok(())
1715+
}
1716+
16611717
fn compile_call(
16621718
&mut self,
16631719
function: &ast::Expression,
@@ -1680,31 +1736,7 @@ impl<O: OutputStream> Compiler<O> {
16801736

16811737
// Create an optional map with kw-args:
16821738
if !keywords.is_empty() {
1683-
for keyword in keywords {
1684-
if let Some(name) = &keyword.name {
1685-
self.emit(Instruction::LoadConst {
1686-
value: bytecode::Constant::String {
1687-
value: name.to_string(),
1688-
},
1689-
});
1690-
self.compile_expression(&keyword.value)?;
1691-
if has_double_star {
1692-
self.emit(Instruction::BuildMap {
1693-
size: 1,
1694-
unpack: false,
1695-
});
1696-
}
1697-
} else {
1698-
// This means **kwargs!
1699-
self.compile_expression(&keyword.value)?;
1700-
}
1701-
}
1702-
1703-
self.emit(Instruction::BuildMap {
1704-
size: keywords.len(),
1705-
unpack: has_double_star,
1706-
});
1707-
1739+
self.compile_keywords(keywords)?;
17081740
self.emit(Instruction::CallFunction {
17091741
typ: CallType::Ex(true),
17101742
});

0 commit comments

Comments
 (0)