Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions bytecode/src/bytecode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,13 @@ bitflags! {
const HAS_DEFAULTS = 0x01;
const HAS_KW_ONLY_DEFAULTS = 0x02;
const HAS_ANNOTATIONS = 0x04;
const NEW_LOCALS = 0x08;
}
}

impl Default for FunctionOpArg {
fn default() -> Self {
Self::NEW_LOCALS
}
}

Expand Down
17 changes: 13 additions & 4 deletions compiler/src/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -672,7 +672,7 @@ impl<O: OutputStream> Compiler<O> {
));
self.enter_scope();

let mut flags = bytecode::FunctionOpArg::empty();
let mut flags = bytecode::FunctionOpArg::default();
if have_defaults {
flags |= bytecode::FunctionOpArg::HAS_DEFAULTS;
}
Expand Down Expand Up @@ -955,12 +955,21 @@ impl<O: OutputStream> Compiler<O> {

self.emit(Instruction::LoadName {
name: "__name__".to_string(),
scope: bytecode::NameScope::Free,
scope: bytecode::NameScope::Global,
});
self.emit(Instruction::StoreName {
name: "__module__".to_string(),
scope: bytecode::NameScope::Free,
});
self.emit(Instruction::LoadConst {
value: bytecode::Constant::String {
value: qualified_name.clone(),
},
});
self.emit(Instruction::StoreName {
name: "__qualname__".to_string(),
scope: bytecode::NameScope::Free,
});
self.compile_statements(new_body)?;
self.emit(Instruction::LoadConst {
value: bytecode::Constant::None,
Expand All @@ -983,7 +992,7 @@ impl<O: OutputStream> Compiler<O> {

// Turn code object into function object:
self.emit(Instruction::MakeFunction {
flags: bytecode::FunctionOpArg::empty(),
flags: bytecode::FunctionOpArg::default() & !bytecode::FunctionOpArg::NEW_LOCALS,
});

self.emit(Instruction::LoadConst {
Expand Down Expand Up @@ -1920,7 +1929,7 @@ impl<O: OutputStream> Compiler<O> {

// Turn code object into function object:
self.emit(Instruction::MakeFunction {
flags: bytecode::FunctionOpArg::empty(),
flags: bytecode::FunctionOpArg::default(),
});

// Evaluate iterated item:
Expand Down
2 changes: 2 additions & 0 deletions compiler/src/symboltable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,8 @@ impl SymbolTableBuilder {
decorator_list,
} => {
self.enter_scope(name, SymbolTableType::Class, statement.location.row());
self.register_name("__module__", SymbolUsage::Assigned)?;
self.register_name("__qualname__", SymbolUsage::Assigned)?;
self.scan_statements(body)?;
self.leave_scope();
self.scan_expressions(bases, &ExpressionContext::Load)?;
Expand Down
12 changes: 8 additions & 4 deletions vm/src/builtins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use crate::obj::objbool::{self, IntoPyBool};
use crate::obj::objbytes::PyBytesRef;
use crate::obj::objcode::PyCodeRef;
use crate::obj::objdict::PyDictRef;
use crate::obj::objfunction::PyFunctionRef;
use crate::obj::objint::{self, PyIntRef};
use crate::obj::objiter;
use crate::obj::objstr::{PyString, PyStringRef};
Expand Down Expand Up @@ -832,6 +833,7 @@ pub fn make_module(vm: &VirtualMachine, module: PyObjectRef) {
"exit" => ctx.new_rustfunc(builtin_exit),
"quit" => ctx.new_rustfunc(builtin_exit),
"__import__" => ctx.new_rustfunc(builtin_import),
"__build_class__" => ctx.new_rustfunc(builtin_build_class_),

// Constants
"NotImplemented" => ctx.not_implemented(),
Expand Down Expand Up @@ -888,7 +890,7 @@ pub fn make_module(vm: &VirtualMachine, module: PyObjectRef) {
}

pub fn builtin_build_class_(
function: PyObjectRef,
function: PyFunctionRef,
qualified_name: PyStringRef,
bases: Args<PyClassRef>,
mut kwargs: KwArgs,
Expand Down Expand Up @@ -925,10 +927,12 @@ pub fn builtin_build_class_(

let cells = vm.ctx.new_dict();

vm.invoke_with_locals(&function, cells.clone(), namespace.clone())?;
let scope = function
.scope
.new_child_scope_with_locals(cells.clone())
.new_child_scope_with_locals(namespace.clone());

namespace.set_item("__name__", name_obj.clone(), vm)?;
namespace.set_item("__qualname__", qualified_name.into_object(), vm)?;
vm.invoke_python_function_with_scope(&function, vec![].into(), &scope)?;

let class = vm.call_method(
metaclass.as_object(),
Expand Down
13 changes: 8 additions & 5 deletions vm/src/frame.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use std::cell::RefCell;
use std::fmt;

use crate::builtins;
use crate::bytecode;
use crate::function::PyFuncArgs;
use crate::obj::objbool;
Expand Down Expand Up @@ -460,7 +459,7 @@ impl Frame {
Ok(None)
}
bytecode::Instruction::LoadBuildClass => {
self.push_value(vm.ctx.new_rustfunc(builtins::builtin_build_class_));
self.push_value(vm.get_attribute(vm.builtins.clone(), "__build_class__")?);
Ok(None)
}
bytecode::Instruction::UnpackSequence { size } => {
Expand Down Expand Up @@ -1054,9 +1053,13 @@ impl Frame {
// pop argc arguments
// argument: name, args, globals
let scope = self.scope.clone();
let func_obj = vm
.ctx
.new_function(code_obj, scope, defaults, kw_only_defaults);
let func_obj = vm.ctx.new_function(
code_obj,
scope,
defaults,
kw_only_defaults,
flags.contains(bytecode::FunctionOpArg::NEW_LOCALS),
);

let name = qualified_name.as_str().split('.').next_back().unwrap();
vm.set_attr(&func_obj, "__name__", vm.new_str(name.to_string()))?;
Expand Down
3 changes: 3 additions & 0 deletions vm/src/obj/objfunction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub struct PyFunction {
pub scope: Scope,
pub defaults: Option<PyTupleRef>,
pub kw_only_defaults: Option<PyDictRef>,
pub new_locals: bool,
}

impl PyFunction {
Expand All @@ -24,12 +25,14 @@ impl PyFunction {
scope: Scope,
defaults: Option<PyTupleRef>,
kw_only_defaults: Option<PyDictRef>,
new_locals: bool,
) -> Self {
PyFunction {
code,
scope,
defaults,
kw_only_defaults,
new_locals,
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion vm/src/pyobject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -478,9 +478,10 @@ impl PyContext {
scope: Scope,
defaults: Option<PyTupleRef>,
kw_only_defaults: Option<PyDictRef>,
new_locals: bool,
) -> PyObjectRef {
PyObject::new(
PyFunction::new(code_obj, scope, defaults, kw_only_defaults),
PyFunction::new(code_obj, scope, defaults, kw_only_defaults, new_locals),
self.function_type(),
Some(self.new_dict()),
)
Expand Down
54 changes: 19 additions & 35 deletions vm/src/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -570,15 +570,9 @@ impl VirtualMachine {
fn _invoke(&self, func_ref: &PyObjectRef, args: PyFuncArgs) -> PyResult {
vm_trace!("Invoke: {:?} {:?}", func_ref, args);

if let Some(PyFunction {
ref code,
ref scope,
ref defaults,
ref kw_only_defaults,
}) = func_ref.payload()
{
if let Some(py_func) = func_ref.payload() {
self.trace_event(TraceEvent::Call)?;
let res = self.invoke_python_function(code, scope, defaults, kw_only_defaults, args);
let res = self.invoke_python_function(py_func, args);
self.trace_event(TraceEvent::Return)?;
res
} else if let Some(PyMethod {
Expand Down Expand Up @@ -634,21 +628,30 @@ impl VirtualMachine {
Ok(())
}

fn invoke_python_function(
pub fn invoke_python_function(&self, func: &PyFunction, func_args: PyFuncArgs) -> PyResult {
self.invoke_python_function_with_scope(func, func_args, &func.scope)
}

pub fn invoke_python_function_with_scope(
&self,
code: &PyCodeRef,
scope: &Scope,
defaults: &Option<PyTupleRef>,
kw_only_defaults: &Option<PyDictRef>,
func: &PyFunction,
func_args: PyFuncArgs,
scope: &Scope,
) -> PyResult {
let scope = scope.new_child_scope(&self.ctx);
let code = &func.code;

let scope = if func.new_locals {
scope.new_child_scope(&self.ctx)
} else {
scope.clone()
};

self.fill_locals_from_args(
&code.code,
&scope.get_locals(),
func_args,
defaults,
kw_only_defaults,
&func.defaults,
&func.kw_only_defaults,
)?;

// Construct frame:
Expand All @@ -662,25 +665,6 @@ impl VirtualMachine {
}
}

pub fn invoke_with_locals(
&self,
function: &PyObjectRef,
cells: PyDictRef,
locals: PyDictRef,
) -> PyResult {
if let Some(PyFunction { code, scope, .. }) = &function.payload() {
let scope = scope
.new_child_scope_with_locals(cells)
.new_child_scope_with_locals(locals);
let frame = Frame::new(code.clone(), scope).into_ref(self);
return self.run_frame_full(frame);
}
panic!(
"invoke_with_locals: expected python function, got: {:?}",
*function
);
}

fn fill_locals_from_args(
&self,
code_object: &bytecode::CodeObject,
Expand Down