From f69c79bdc7f12e54589c9762398c607c4aede3ab Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Sat, 27 Apr 2019 16:39:41 +0900 Subject: [PATCH 1/2] Add __builtins__ to globals() --- src/main.rs | 1 + tests/snippets/builtins_module.py | 16 ++++++++++++++++ vm/src/frame.rs | 5 +++++ wasm/lib/src/vm_class.rs | 1 + 4 files changed, 23 insertions(+) create mode 100644 tests/snippets/builtins_module.py diff --git a/src/main.rs b/src/main.rs index 72bb16139..e8dd48008 100644 --- a/src/main.rs +++ b/src/main.rs @@ -218,6 +218,7 @@ fn run_shell(vm: &VirtualMachine) -> PyResult { crate_version!() ); let vars = vm.ctx.new_scope(); + vars.init_builtins(vm)?; // Read a single line: let mut input = String::new(); diff --git a/tests/snippets/builtins_module.py b/tests/snippets/builtins_module.py new file mode 100644 index 000000000..b9feffd0a --- /dev/null +++ b/tests/snippets/builtins_module.py @@ -0,0 +1,16 @@ +from testutils import assertRaises + +assert '__builtins__' in globals() +# assert type(__builtins__).__name__ == 'module' +with assertRaises(AttributeError): + __builtins__.__builtins__ + +__builtins__.x = 'new' +assert x == 'new' + +# __builtins__ is deletable but names are alive +del __builtins__ +with assertRaises(NameError): + __builtins__ + +assert print diff --git a/vm/src/frame.rs b/vm/src/frame.rs index 50c317c37..847487306 100644 --- a/vm/src/frame.rs +++ b/vm/src/frame.rs @@ -119,6 +119,11 @@ impl Scope { pub fn child_scope(&self, ctx: &PyContext) -> Scope { self.child_scope_with_locals(ctx.new_dict()) } + + pub fn init_builtins(&self, vm: &VirtualMachine) -> PyResult<()> { + let globals = self.globals.clone(); + globals.set_item("__builtins__", vm.builtins.clone(), vm).and(Ok(())) + } } pub trait NameProtocol { diff --git a/wasm/lib/src/vm_class.rs b/wasm/lib/src/vm_class.rs index 2c330e6ee..64957e331 100644 --- a/wasm/lib/src/vm_class.rs +++ b/wasm/lib/src/vm_class.rs @@ -27,6 +27,7 @@ impl StoredVirtualMachine { fn new(id: String, inject_browser_module: bool) -> StoredVirtualMachine { let mut vm = VirtualMachine::new(); let scope = vm.ctx.new_scope(); + scope.init_builtins(&vm).unwrap(); if inject_browser_module { setup_browser_module(&vm); } From 509394080bc5262d3c3961ca16919631c9e1eb5b Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Sat, 4 May 2019 00:52:44 +0900 Subject: [PATCH 2/2] Inject __builtins__ to scope only when it doesn't exist --- benchmarks/bench.rs | 4 ++-- src/main.rs | 5 ++--- tests/snippets/builtins_module.py | 12 ++++++++++++ vm/src/builtins.rs | 15 ++++++++++++--- vm/src/eval.rs | 2 +- vm/src/frame.rs | 19 ++++++++++++++----- vm/src/import.rs | 2 +- vm/src/pyobject.rs | 4 ---- vm/src/vm.rs | 4 ++++ wasm/lib/src/vm_class.rs | 3 +-- 10 files changed, 49 insertions(+), 21 deletions(-) diff --git a/benchmarks/bench.rs b/benchmarks/bench.rs index b475da7cb..256fa47ad 100644 --- a/benchmarks/bench.rs +++ b/benchmarks/bench.rs @@ -99,7 +99,7 @@ fn bench_rustpy_nbody(b: &mut test::Bencher) { }; b.iter(|| { - let scope = vm.ctx.new_scope(); + let scope = vm.new_scope_with_builtins(); let res: PyResult = vm.run_code_obj(code.clone(), scope); assert!(res.is_ok()); }) @@ -118,7 +118,7 @@ fn bench_rustpy_mandelbrot(b: &mut test::Bencher) { }; b.iter(|| { - let scope = vm.ctx.new_scope(); + let scope = vm.new_scope_with_builtins(); let res: PyResult = vm.run_code_obj(code.clone(), scope); assert!(res.is_ok()); }) diff --git a/src/main.rs b/src/main.rs index e8dd48008..2100226c2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -77,7 +77,7 @@ fn _run_string(vm: &VirtualMachine, source: &str, source_path: String) -> PyResu // trace!("Code object: {:?}", code_obj.borrow()); let attrs = vm.ctx.new_dict(); attrs.set_item("__file__", vm.new_str(source_path), vm)?; - vm.run_code_obj(code_obj, Scope::new(None, attrs)) + vm.run_code_obj(code_obj, Scope::with_builtins(None, attrs, vm)) } fn handle_exception(vm: &VirtualMachine, result: PyResult) { @@ -217,8 +217,7 @@ fn run_shell(vm: &VirtualMachine) -> PyResult { "Welcome to the magnificent Rust Python {} interpreter \u{1f631} \u{1f596}", crate_version!() ); - let vars = vm.ctx.new_scope(); - vars.init_builtins(vm)?; + let vars = vm.new_scope_with_builtins(); // Read a single line: let mut input = String::new(); diff --git a/tests/snippets/builtins_module.py b/tests/snippets/builtins_module.py index b9feffd0a..e3bdcdc16 100644 --- a/tests/snippets/builtins_module.py +++ b/tests/snippets/builtins_module.py @@ -8,6 +8,18 @@ with assertRaises(AttributeError): __builtins__.x = 'new' assert x == 'new' +exec('assert "__builtins__" in globals()', dict()) +exec('assert __builtins__ == 7', {'__builtins__': 7}) +exec('assert not isinstance(__builtins__, dict)') +exec('assert isinstance(__builtins__, dict)', {}) + +namespace = {} +exec('', namespace) +assert namespace['__builtins__'] == __builtins__.__dict__ + +# with assertRaises(NameError): +# exec('print(__builtins__)', {'__builtins__': {}}) + # __builtins__ is deletable but names are alive del __builtins__ with assertRaises(NameError): diff --git a/vm/src/builtins.rs b/vm/src/builtins.rs index a48a3b441..5b3082b0d 100644 --- a/vm/src/builtins.rs +++ b/vm/src/builtins.rs @@ -218,18 +218,27 @@ fn make_scope( } None => None, }; - let current_scope = vm.current_scope(); let globals = match globals { - Some(dict) => dict.clone().downcast().unwrap(), + Some(dict) => { + let dict: PyDictRef = dict.clone().downcast().unwrap(); + if !dict.contains_key("__builtins__", vm) { + let builtins_dict = vm.builtins.dict.as_ref().unwrap().as_object(); + dict.set_item("__builtins__", builtins_dict.clone(), vm) + .unwrap(); + } + dict + } None => current_scope.globals.clone(), }; + let locals = match locals { Some(dict) => dict.clone().downcast().ok(), None => current_scope.get_only_locals(), }; - Ok(Scope::new(locals, globals)) + let scope = Scope::with_builtins(locals, globals, vm); + Ok(scope) } fn builtin_format( diff --git a/vm/src/eval.rs b/vm/src/eval.rs index 21bc9dadf..a927f8f03 100644 --- a/vm/src/eval.rs +++ b/vm/src/eval.rs @@ -24,7 +24,7 @@ mod tests { fn test_print_42() { let source = String::from("print('Hello world')\n"); let mut vm = VirtualMachine::new(); - let vars = vm.ctx.new_scope(); + let vars = vm.new_scope_with_builtins(); let _result = eval(&mut vm, &source, vars, ""); // TODO: check result? diff --git a/vm/src/frame.rs b/vm/src/frame.rs index 847487306..5955660b6 100644 --- a/vm/src/frame.rs +++ b/vm/src/frame.rs @@ -98,6 +98,20 @@ impl Scope { Scope { locals, globals } } + pub fn with_builtins( + locals: Option, + globals: PyDictRef, + vm: &VirtualMachine, + ) -> Scope { + if !globals.contains_key("__builtins__", vm) { + globals + .clone() + .set_item("__builtins__", vm.builtins.clone(), vm) + .unwrap(); + } + Scope::new(locals, globals) + } + pub fn get_locals(&self) -> PyDictRef { match self.locals.iter().next() { Some(dict) => dict.clone(), @@ -119,11 +133,6 @@ impl Scope { pub fn child_scope(&self, ctx: &PyContext) -> Scope { self.child_scope_with_locals(ctx.new_dict()) } - - pub fn init_builtins(&self, vm: &VirtualMachine) -> PyResult<()> { - let globals = self.globals.clone(); - globals.set_item("__builtins__", vm.builtins.clone(), vm).and(Ok(())) - } } pub trait NameProtocol { diff --git a/vm/src/import.rs b/vm/src/import.rs index a03f14623..8445e65f9 100644 --- a/vm/src/import.rs +++ b/vm/src/import.rs @@ -61,7 +61,7 @@ pub fn import_file( sys_modules.set_item(module_name, module.clone(), vm)?; // Execute main code in module: - vm.run_code_obj(code_obj, Scope::new(None, attrs))?; + vm.run_code_obj(code_obj, Scope::with_builtins(None, attrs, vm))?; Ok(module) } diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index 454a1605f..722588b3f 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -648,10 +648,6 @@ impl PyContext { objtype::new(self.type_type(), name, vec![base], PyAttributes::new()).unwrap() } - pub fn new_scope(&self) -> Scope { - Scope::new(None, self.new_dict()) - } - pub fn new_module(&self, name: &str, dict: PyDictRef) -> PyObjectRef { PyObject::new( PyModule { diff --git a/vm/src/vm.rs b/vm/src/vm.rs index 6b2f0e0b1..814631015 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -250,6 +250,10 @@ impl VirtualMachine { syntax_error } + pub fn new_scope_with_builtins(&self) -> Scope { + Scope::with_builtins(None, self.ctx.new_dict(), self) + } + pub fn get_none(&self) -> PyObjectRef { self.ctx.none() } diff --git a/wasm/lib/src/vm_class.rs b/wasm/lib/src/vm_class.rs index 64957e331..f9040dfcb 100644 --- a/wasm/lib/src/vm_class.rs +++ b/wasm/lib/src/vm_class.rs @@ -26,8 +26,7 @@ pub(crate) struct StoredVirtualMachine { impl StoredVirtualMachine { fn new(id: String, inject_browser_module: bool) -> StoredVirtualMachine { let mut vm = VirtualMachine::new(); - let scope = vm.ctx.new_scope(); - scope.init_builtins(&vm).unwrap(); + let scope = vm.new_scope_with_builtins(); if inject_browser_module { setup_browser_module(&vm); }