Skip to content

Commit e87144e

Browse files
committed
Add flags to the MakeFunction instruction
1 parent 98c3df2 commit e87144e

File tree

4 files changed

+89
-64
lines changed

4 files changed

+89
-64
lines changed

bytecode/src/bytecode.rs

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -117,15 +117,12 @@ pub struct CodeObject<C: Constant = ConstantData> {
117117
bitflags! {
118118
#[derive(Serialize, Deserialize)]
119119
pub struct CodeFlags: u16 {
120-
const HAS_DEFAULTS = 0x01;
121-
const HAS_KW_ONLY_DEFAULTS = 0x02;
122-
const HAS_ANNOTATIONS = 0x04;
123-
const NEW_LOCALS = 0x08;
124-
const IS_GENERATOR = 0x10;
125-
const IS_COROUTINE = 0x20;
126-
const HAS_VARARGS = 0x40;
127-
const HAS_VARKEYWORDS = 0x80;
128-
const IS_OPTIMIZED = 0x0100;
120+
const NEW_LOCALS = 0x01;
121+
const IS_GENERATOR = 0x02;
122+
const IS_COROUTINE = 0x04;
123+
const HAS_VARARGS = 0x08;
124+
const HAS_VARKEYWORDS = 0x10;
125+
const IS_OPTIMIZED = 0x20;
129126
}
130127
}
131128

@@ -250,7 +247,7 @@ pub enum Instruction {
250247
JumpIfFalseOrPop {
251248
target: Label,
252249
},
253-
MakeFunction,
250+
MakeFunction(MakeFunctionFlags),
254251
CallFunctionPositional {
255252
nargs: usize,
256253
},
@@ -369,6 +366,16 @@ pub enum Instruction {
369366

370367
use self::Instruction::*;
371368

369+
bitflags! {
370+
#[derive(Serialize, Deserialize)]
371+
pub struct MakeFunctionFlags: u8 {
372+
const CLOSURE = 0x01;
373+
const ANNOTATIONS = 0x02;
374+
const KW_ONLY_DEFAULTS = 0x04;
375+
const DEFAULTS = 0x08;
376+
}
377+
}
378+
372379
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
373380
pub enum ConstantData {
374381
Integer { value: BigInt },
@@ -876,7 +883,7 @@ impl Instruction {
876883
JumpIfFalse { target } => w!(JumpIfFalse, target),
877884
JumpIfTrueOrPop { target } => w!(JumpIfTrueOrPop, target),
878885
JumpIfFalseOrPop { target } => w!(JumpIfFalseOrPop, target),
879-
MakeFunction => w!(MakeFunction),
886+
MakeFunction(flags) => w!(MakeFunction, format_args!("{:?}", flags)),
880887
CallFunctionPositional { nargs } => w!(CallFunctionPositional, nargs),
881888
CallFunctionKeyword { nargs } => w!(CallFunctionKeyword, nargs),
882889
CallFunctionEx { has_kwargs } => w!(CallFunctionEx, has_kwargs),

compiler/src/compile.rs

Lines changed: 58 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -827,7 +827,11 @@ impl Compiler {
827827
Ok(())
828828
}
829829

830-
fn enter_function(&mut self, name: &str, args: &ast::Parameters) -> CompileResult<()> {
830+
fn enter_function(
831+
&mut self,
832+
name: &str,
833+
args: &ast::Parameters,
834+
) -> CompileResult<bytecode::MakeFunctionFlags> {
831835
let have_defaults = !args.defaults.is_empty();
832836
if have_defaults {
833837
// Construct a tuple:
@@ -859,17 +863,17 @@ impl Compiler {
859863
});
860864
}
861865

862-
let mut flags = bytecode::CodeFlags::NEW_LOCALS | bytecode::CodeFlags::IS_OPTIMIZED;
866+
let mut funcflags = bytecode::MakeFunctionFlags::empty();
863867
if have_defaults {
864-
flags |= bytecode::CodeFlags::HAS_DEFAULTS;
868+
funcflags |= bytecode::MakeFunctionFlags::DEFAULTS;
865869
}
866870
if num_kw_only_defaults > 0 {
867-
flags |= bytecode::CodeFlags::HAS_KW_ONLY_DEFAULTS;
871+
funcflags |= bytecode::MakeFunctionFlags::KW_ONLY_DEFAULTS;
868872
}
869873

870874
let line_number = self.get_source_line_number();
871875
self.push_output(CodeObject::new(
872-
flags,
876+
bytecode::CodeFlags::NEW_LOCALS | bytecode::CodeFlags::IS_OPTIMIZED,
873877
args.posonlyargs_count,
874878
args.args.len(),
875879
args.kwonlyargs.len(),
@@ -896,7 +900,7 @@ impl Compiler {
896900
compile_varargs(&args.vararg, bytecode::CodeFlags::HAS_VARARGS);
897901
compile_varargs(&args.kwarg, bytecode::CodeFlags::HAS_VARKEYWORDS);
898902

899-
Ok(())
903+
Ok(funcflags)
900904
}
901905

902906
fn prepare_decorators(&mut self, decorator_list: &[ast::Expression]) -> CompileResult<()> {
@@ -1037,7 +1041,7 @@ impl Compiler {
10371041
// Create bytecode for this function:
10381042

10391043
self.prepare_decorators(decorator_list)?;
1040-
self.enter_function(name, args)?;
1044+
let mut funcflags = self.enter_function(name, args)?;
10411045

10421046
// remember to restore self.ctx.in_loop to the original after the function is compiled
10431047
let prev_ctx = self.ctx;
@@ -1113,7 +1117,7 @@ impl Compiler {
11131117
}
11141118

11151119
if num_annotations > 0 {
1116-
code.flags |= bytecode::CodeFlags::HAS_ANNOTATIONS;
1120+
funcflags |= bytecode::MakeFunctionFlags::ANNOTATIONS;
11171121
self.emit(Instruction::BuildMap {
11181122
size: num_annotations,
11191123
unpack: false,
@@ -1125,7 +1129,9 @@ impl Compiler {
11251129
code.flags |= bytecode::CodeFlags::IS_COROUTINE;
11261130
}
11271131

1128-
self.build_closure(&code);
1132+
if self.build_closure(&code) {
1133+
funcflags |= bytecode::MakeFunctionFlags::CLOSURE;
1134+
}
11291135

11301136
self.emit_constant(ConstantData::Code {
11311137
code: Box::new(code),
@@ -1135,7 +1141,7 @@ impl Compiler {
11351141
});
11361142

11371143
// Turn code object into function object:
1138-
self.emit(Instruction::MakeFunction);
1144+
self.emit(Instruction::MakeFunction(funcflags));
11391145

11401146
self.emit(Instruction::Duplicate);
11411147
self.load_docstring(doc_str);
@@ -1150,32 +1156,34 @@ impl Compiler {
11501156
Ok(())
11511157
}
11521158

1153-
fn build_closure(&mut self, code: &CodeObject) {
1154-
if !code.freevars.is_empty() {
1155-
for var in &*code.freevars {
1156-
let table = self.symbol_table_stack.last().unwrap();
1157-
let symbol = table.lookup(var).unwrap();
1158-
let parent_code = self.code_stack.last().unwrap();
1159-
let vars = match symbol.scope {
1160-
SymbolScope::Free => &parent_code.freevar_cache,
1161-
SymbolScope::Cell => &parent_code.cellvar_cache,
1162-
_ if symbol.is_free_class => &parent_code.freevar_cache,
1163-
x => unreachable!(
1164-
"var {} in a {:?} should be free or cell but it's {:?}",
1165-
var, table.typ, x
1166-
),
1167-
};
1168-
let mut idx = vars.get_index_of(var).unwrap();
1169-
if let SymbolScope::Free = symbol.scope {
1170-
idx += parent_code.cellvar_cache.len();
1171-
}
1172-
self.emit(Instruction::LoadClosure(idx))
1159+
fn build_closure(&mut self, code: &CodeObject) -> bool {
1160+
if code.freevars.is_empty() {
1161+
return false;
1162+
}
1163+
for var in &*code.freevars {
1164+
let table = self.symbol_table_stack.last().unwrap();
1165+
let symbol = table.lookup(var).unwrap();
1166+
let parent_code = self.code_stack.last().unwrap();
1167+
let vars = match symbol.scope {
1168+
SymbolScope::Free => &parent_code.freevar_cache,
1169+
SymbolScope::Cell => &parent_code.cellvar_cache,
1170+
_ if symbol.is_free_class => &parent_code.freevar_cache,
1171+
x => unreachable!(
1172+
"var {} in a {:?} should be free or cell but it's {:?}",
1173+
var, table.typ, x
1174+
),
1175+
};
1176+
let mut idx = vars.get_index_of(var).unwrap();
1177+
if let SymbolScope::Free = symbol.scope {
1178+
idx += parent_code.cellvar_cache.len();
11731179
}
1174-
self.emit(Instruction::BuildTuple {
1175-
size: code.freevars.len(),
1176-
unpack: false,
1177-
})
1180+
self.emit(Instruction::LoadClosure(idx))
11781181
}
1182+
self.emit(Instruction::BuildTuple {
1183+
size: code.freevars.len(),
1184+
unpack: false,
1185+
});
1186+
true
11791187
}
11801188

11811189
fn find_ann(&self, body: &[ast::Statement]) -> bool {
@@ -1312,7 +1320,11 @@ impl Compiler {
13121320
self.current_qualified_path = old_qualified_path;
13131321
self.ctx = prev_ctx;
13141322

1315-
self.build_closure(&code);
1323+
let mut funcflags = bytecode::MakeFunctionFlags::empty();
1324+
1325+
if self.build_closure(&code) {
1326+
funcflags |= bytecode::MakeFunctionFlags::CLOSURE;
1327+
}
13161328

13171329
self.emit_constant(ConstantData::Code {
13181330
code: Box::new(code),
@@ -1322,7 +1334,7 @@ impl Compiler {
13221334
});
13231335

13241336
// Turn code object into function object:
1325-
self.emit(Instruction::MakeFunction);
1337+
self.emit(Instruction::MakeFunction(funcflags));
13261338

13271339
self.emit_constant(ConstantData::Str {
13281340
value: qualified_name,
@@ -2006,17 +2018,19 @@ impl Compiler {
20062018
};
20072019

20082020
let name = "<lambda>".to_owned();
2009-
self.enter_function(&name, args)?;
2021+
let mut funcflags = self.enter_function(&name, args)?;
20102022
self.compile_expression(body)?;
20112023
self.emit(Instruction::ReturnValue);
20122024
let code = self.pop_code_object();
2013-
self.build_closure(&code);
2025+
if self.build_closure(&code) {
2026+
funcflags |= bytecode::MakeFunctionFlags::CLOSURE;
2027+
}
20142028
self.emit_constant(ConstantData::Code {
20152029
code: Box::new(code),
20162030
});
20172031
self.emit_constant(ConstantData::Str { value: name });
20182032
// Turn code object into function object:
2019-
self.emit(Instruction::MakeFunction);
2033+
self.emit(Instruction::MakeFunction(funcflags));
20202034

20212035
self.ctx = prev_ctx;
20222036
}
@@ -2320,7 +2334,10 @@ impl Compiler {
23202334

23212335
self.ctx = prev_ctx;
23222336

2323-
self.build_closure(&code);
2337+
let mut funcflags = bytecode::MakeFunctionFlags::empty();
2338+
if self.build_closure(&code) {
2339+
funcflags |= bytecode::MakeFunctionFlags::CLOSURE;
2340+
}
23242341

23252342
// List comprehension code:
23262343
self.emit_constant(ConstantData::Code {
@@ -2331,7 +2348,7 @@ impl Compiler {
23312348
self.emit_constant(ConstantData::Str { value: name });
23322349

23332350
// Turn code object into function object:
2334-
self.emit(Instruction::MakeFunction);
2351+
self.emit(Instruction::MakeFunction(funcflags));
23352352

23362353
// Evaluate iterated item:
23372354
self.compile_expression(&generators[0].iter)?;

compiler/src/lib.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
//! Compile a Python AST or source code into bytecode consumable by RustPython or
2-
//! (eventually) CPython.
1+
//! Compile a Python AST or source code into bytecode consumable by RustPython.
32
#![doc(html_logo_url = "https://raw.githubusercontent.com/RustPython/RustPython/master/logo.png")]
43
#![doc(html_root_url = "https://docs.rs/rustpython-compiler/")]
54

vm/src/frame.rs

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -818,7 +818,7 @@ impl ExecutingFrame<'_> {
818818
Ok(None)
819819
}
820820
bytecode::Instruction::ForIter { target } => self.execute_for_iter(vm, *target),
821-
bytecode::Instruction::MakeFunction => self.execute_make_function(vm),
821+
bytecode::Instruction::MakeFunction(flags) => self.execute_make_function(vm, *flags),
822822
bytecode::Instruction::CallFunctionPositional { nargs } => {
823823
self.execute_call_function_positional(vm, *nargs)
824824
}
@@ -1417,7 +1417,11 @@ impl ExecutingFrame<'_> {
14171417
}
14181418
}
14191419
}
1420-
fn execute_make_function(&mut self, vm: &VirtualMachine) -> FrameResult {
1420+
fn execute_make_function(
1421+
&mut self,
1422+
vm: &VirtualMachine,
1423+
flags: bytecode::MakeFunctionFlags,
1424+
) -> FrameResult {
14211425
let qualified_name = self
14221426
.pop_value()
14231427
.downcast::<PyStr>()
@@ -1427,21 +1431,19 @@ impl ExecutingFrame<'_> {
14271431
.downcast()
14281432
.expect("Second to top value on the stack must be a code object");
14291433

1430-
let flags = code_obj.flags;
1431-
1432-
let closure = if code_obj.freevars.is_empty() {
1433-
None
1434-
} else {
1434+
let closure = if flags.contains(bytecode::MakeFunctionFlags::CLOSURE) {
14351435
Some(PyTupleTyped::try_from_object(vm, self.pop_value()).unwrap())
1436+
} else {
1437+
None
14361438
};
14371439

1438-
let annotations = if flags.contains(bytecode::CodeFlags::HAS_ANNOTATIONS) {
1440+
let annotations = if flags.contains(bytecode::MakeFunctionFlags::ANNOTATIONS) {
14391441
self.pop_value()
14401442
} else {
14411443
vm.ctx.new_dict().into_object()
14421444
};
14431445

1444-
let kw_only_defaults = if flags.contains(bytecode::CodeFlags::HAS_KW_ONLY_DEFAULTS) {
1446+
let kw_only_defaults = if flags.contains(bytecode::MakeFunctionFlags::KW_ONLY_DEFAULTS) {
14451447
Some(
14461448
self.pop_value()
14471449
.downcast::<PyDict>()
@@ -1451,7 +1453,7 @@ impl ExecutingFrame<'_> {
14511453
None
14521454
};
14531455

1454-
let defaults = if flags.contains(bytecode::CodeFlags::HAS_DEFAULTS) {
1456+
let defaults = if flags.contains(bytecode::MakeFunctionFlags::DEFAULTS) {
14551457
Some(
14561458
self.pop_value()
14571459
.downcast::<PyTuple>()

0 commit comments

Comments
 (0)