diff --git a/Cargo.lock b/Cargo.lock index ffb2e02d57..9eee244e9a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1749,7 +1749,6 @@ dependencies = [ "python3-sys", "rustpython-compiler", "rustpython-parser", - "rustpython-pylib", "rustpython-stdlib", "rustpython-vm", "rustyline", diff --git a/Cargo.toml b/Cargo.toml index 68e0e7968d..92ed81187a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,7 @@ flame-it = ["rustpython-vm/flame-it", "flame", "flamescope"] freeze-stdlib = ["rustpython-vm/freeze-stdlib"] jit = ["rustpython-vm/jit"] threading = ["rustpython-vm/threading"] +pylib = ["rustpython-vm/pylib"] zlib = ["rustpython-stdlib/zlib"] ssl = ["rustpython-stdlib/ssl"] ssl-vendor = ["rustpython-stdlib/ssl-vendor"] @@ -34,7 +35,6 @@ rustpython-compiler = { path = "compiler/porcelain", version = "0.1.1" } rustpython-parser = { path = "parser", version = "0.1.1" } rustpython-vm = { path = "vm", version = "0.1.1", default-features = false, features = ["compile-parse"] } rustpython-stdlib = {path = "stdlib", optional = true, default-features = false, features = ["compile-parse"]} -pylib = { package = "rustpython-pylib", path = "vm/pylib-crate", version = "0.1.0", optional = true } dirs = { package = "dirs-next", version = "2.0.0" } num-traits = "0.2.8" cfg-if = "1.0" @@ -66,6 +66,10 @@ path = "src/main.rs" [profile.dev.package."*"] opt-level = 3 +[profile.test] +opt-level = 3 +lto = "thin" + [profile.bench] lto = true codegen-units = 1 diff --git a/Lib/distutils/command/install.py b/Lib/distutils/command/install.py index 078b3d59b8..fd3357ea78 100644 --- a/Lib/distutils/command/install.py +++ b/Lib/distutils/command/install.py @@ -78,6 +78,11 @@ if HAS_USER_SITE: 'data' : '$userbase', } +# XXX RUSTPYTHON: replace python with rustpython in all these paths +for group in INSTALL_SCHEMES.values(): + for key in group.keys(): + group[key] = group[key].replace("Python", "RustPython").replace("python", "rustpython") + # The keys to an installation scheme; if any new types of files are to be # installed, be sure to add an entry to every installation scheme above, # and to SCHEME_KEYS here. diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py index b1a98539c6..3a5984f5c0 100644 --- a/Lib/distutils/sysconfig.py +++ b/Lib/distutils/sysconfig.py @@ -13,7 +13,6 @@ import _imp import os import re import sys -import fnmatch from .errors import DistutilsPlatformError @@ -24,36 +23,47 @@ BASE_PREFIX = os.path.normpath(sys.base_prefix) BASE_EXEC_PREFIX = os.path.normpath(sys.base_exec_prefix) # Path to the base directory of the project. On Windows the binary may -# live in project/PCBuild/win32 or project/PCBuild/amd64. +# live in project/PCbuild/win32 or project/PCbuild/amd64. # set for cross builds if "_PYTHON_PROJECT_BASE" in os.environ: project_base = os.path.abspath(os.environ["_PYTHON_PROJECT_BASE"]) else: - project_base = os.path.dirname(os.path.abspath(sys.executable)) -if (os.name == 'nt' and - project_base.lower().endswith(('\\pcbuild\\win32', '\\pcbuild\\amd64'))): - project_base = os.path.dirname(os.path.dirname(project_base)) + if sys.executable: + project_base = os.path.dirname(os.path.abspath(sys.executable)) + else: + # sys.executable can be empty if argv[0] has been changed and Python is + # unable to retrieve the real program name + project_base = os.getcwd() + # python_build: (Boolean) if true, we're either building Python or # building an extension with an un-installed Python, so we use # different (hard-wired) directories. -# Setup.local is available for Makefile builds including VPATH builds, -# Setup.dist is available on Windows def _is_python_source_dir(d): - for fn in ("Setup.dist", "Setup.local"): + for fn in ("Setup", "Setup.local"): if os.path.isfile(os.path.join(d, "Modules", fn)): return True return False + _sys_home = getattr(sys, '_home', None) -if (_sys_home and os.name == 'nt' and - _sys_home.lower().endswith(('\\pcbuild\\win32', '\\pcbuild\\amd64'))): - _sys_home = os.path.dirname(os.path.dirname(_sys_home)) + +if os.name == 'nt': + def _fix_pcbuild(d): + if d and os.path.normcase(d).startswith( + os.path.normcase(os.path.join(PREFIX, "PCbuild"))): + return PREFIX + return d + project_base = _fix_pcbuild(project_base) + _sys_home = _fix_pcbuild(_sys_home) + def _python_build(): if _sys_home: return _is_python_source_dir(_sys_home) return _is_python_source_dir(project_base) + python_build = _python_build() + # Calculate the build qualifier flags if they are defined. Adding the flags # to the include and lib directories only makes sense for an installation, not # an in-source build. @@ -100,11 +110,13 @@ def get_python_inc(plat_specific=0, prefix=None): incdir = os.path.join(get_config_var('srcdir'), 'Include') return os.path.normpath(incdir) python_dir = 'python' + get_python_version() + build_flags - if not python_build and plat_specific: - import sysconfig - return sysconfig.get_path('platinclude') return os.path.join(prefix, "include", python_dir) elif os.name == "nt": + if python_build: + # Include both the include and PC dir to ensure we can find + # pyconfig.h + return (os.path.join(prefix, "include") + os.path.pathsep + + os.path.join(prefix, "PC")) return os.path.join(prefix, "include") else: raise DistutilsPlatformError( @@ -126,7 +138,6 @@ def get_python_lib(plat_specific=0, standard_lib=0, prefix=None): If 'prefix' is supplied, use it instead of sys.base_prefix or sys.base_exec_prefix -- i.e., ignore 'plat_specific'. """ - is_default_prefix = not prefix or os.path.normpath(prefix) in ('/usr', '/usr/local') if prefix is None: if standard_lib: prefix = plat_specific and BASE_EXEC_PREFIX or BASE_PREFIX @@ -134,16 +145,18 @@ def get_python_lib(plat_specific=0, standard_lib=0, prefix=None): prefix = plat_specific and EXEC_PREFIX or PREFIX if os.name == "posix": - libpython = os.path.join(prefix, - "lib", "python" + get_python_version()) + if plat_specific or standard_lib: + # Platform-specific modules (any module from a non-pure-Python + # module distribution) or standard Python library modules. + libdir = sys.platlibdir + else: + # Pure Python + libdir = "lib" + libpython = os.path.join(prefix, libdir, + # XXX RUSTPYTHON: changed from python->rustpython + "rustpython" + get_python_version()) if standard_lib: return libpython - elif (is_default_prefix and - 'PYTHONUSERBASE' not in os.environ and - 'VIRTUAL_ENV' not in os.environ and - 'real_prefix' not in sys.__dict__ and - sys.prefix == sys.base_prefix): - return os.path.join(prefix, "lib", "python3", "dist-packages") else: return os.path.join(libpython, "site-packages") elif os.name == "nt": @@ -181,11 +194,9 @@ def customize_compiler(compiler): _osx_support.customize_compiler(_config_vars) _config_vars['CUSTOMIZED_OSX_COMPILER'] = 'True' - (cc, cxx, opt, cflags, ccshared, ldshared, shlib_suffix, ar, ar_flags, - configure_cppflags, configure_cflags, configure_ldflags) = \ - get_config_vars('CC', 'CXX', 'OPT', 'CFLAGS', - 'CCSHARED', 'LDSHARED', 'SHLIB_SUFFIX', 'AR', 'ARFLAGS', - 'CONFIGURE_CPPFLAGS', 'CONFIGURE_CFLAGS', 'CONFIGURE_LDFLAGS') + (cc, cxx, cflags, ccshared, ldshared, shlib_suffix, ar, ar_flags) = \ + get_config_vars('CC', 'CXX', 'CFLAGS', + 'CCSHARED', 'LDSHARED', 'SHLIB_SUFFIX', 'AR', 'ARFLAGS') if 'CC' in os.environ: newcc = os.environ['CC'] @@ -198,10 +209,6 @@ def customize_compiler(compiler): cc = newcc if 'CXX' in os.environ: cxx = os.environ['CXX'] - if fnmatch.filter([cc, cxx], '*-4.[0-8]'): - configure_cflags = configure_cflags.replace('-fstack-protector-strong', '-fstack-protector') - ldshared = ldshared.replace('-fstack-protector-strong', '-fstack-protector') - cflags = cflags.replace('-fstack-protector-strong', '-fstack-protector') if 'LDSHARED' in os.environ: ldshared = os.environ['LDSHARED'] if 'CPP' in os.environ: @@ -210,22 +217,13 @@ def customize_compiler(compiler): cpp = cc + " -E" # not always if 'LDFLAGS' in os.environ: ldshared = ldshared + ' ' + os.environ['LDFLAGS'] - elif configure_ldflags: - ldshared = ldshared + ' ' + configure_ldflags if 'CFLAGS' in os.environ: - cflags = opt + ' ' + os.environ['CFLAGS'] + cflags = cflags + ' ' + os.environ['CFLAGS'] ldshared = ldshared + ' ' + os.environ['CFLAGS'] - elif configure_cflags: - cflags = opt + ' ' + configure_cflags - ldshared = ldshared + ' ' + configure_cflags if 'CPPFLAGS' in os.environ: cpp = cpp + ' ' + os.environ['CPPFLAGS'] cflags = cflags + ' ' + os.environ['CPPFLAGS'] ldshared = ldshared + ' ' + os.environ['CPPFLAGS'] - elif configure_cppflags: - cpp = cpp + ' ' + configure_cppflags - cflags = cflags + ' ' + configure_cppflags - ldshared = ldshared + ' ' + configure_cppflags if 'AR' in os.environ: ar = os.environ['AR'] if 'ARFLAGS' in os.environ: diff --git a/Lib/test/test_zipfile.py b/Lib/test/test_zipfile.py index ae9a7dae2d..e5180c9fd4 100644 --- a/Lib/test/test_zipfile.py +++ b/Lib/test/test_zipfile.py @@ -1605,8 +1605,6 @@ class OtherTests(unittest.TestCase): self.assertEqual(zf.filelist[0].filename, "foo.txt") self.assertEqual(zf.filelist[1].filename, "\xf6.txt") - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_read_after_write_unicode_filenames(self): with zipfile.ZipFile(TESTFN2, 'w') as zipfp: zipfp.writestr('приклад', b'sample') @@ -1815,8 +1813,6 @@ class OtherTests(unittest.TestCase): self.assertEqual(zipfile.sizeEndCentDir64, 56) self.assertEqual(zipfile.sizeEndCentDir64Locator, 20) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_comments(self): """Check that comments on the archive are handled properly.""" @@ -2872,7 +2868,7 @@ class TestPath(unittest.TestCase): a, b, g = root.iterdir() with a.open() as strm: data = strm.read() - assert data == b"content of a" + assert data == "content of a" def test_read(self): for alpharep in self.zipfile_alpharep(): diff --git a/Lib/tokenize.py b/Lib/tokenize.py index 1aee21b5e1..215d032f45 100644 --- a/Lib/tokenize.py +++ b/Lib/tokenize.py @@ -24,7 +24,10 @@ __author__ = 'Ka-Ping Yee ' __credits__ = ('GvR, ESR, Tim Peters, Thomas Wouters, Fred Drake, ' 'Skip Montanaro, Raymond Hettinger, Trent Nelson, ' 'Michael Foord') -from builtins import open as _builtin_open +try: + from builtins import open as _builtin_open +except ImportError: + pass from codecs import lookup, BOM_UTF8 import collections from io import TextIOWrapper diff --git a/Lib/zipfile.py b/Lib/zipfile.py index cd309da01b..2a4097d0f5 100644 --- a/Lib/zipfile.py +++ b/Lib/zipfile.py @@ -4,7 +4,6 @@ Read and write ZIP files. XXX references to utf-8 need further investigation. """ import binascii -import functools import importlib.util import io import itertools @@ -26,7 +25,6 @@ except ImportError: import _dummy_thread as threading import time import contextlib -from collections import OrderedDict try: import zlib # We may need its compression method @@ -47,7 +45,8 @@ except ImportError: __all__ = ["BadZipFile", "BadZipfile", "error", "ZIP_STORED", "ZIP_DEFLATED", "ZIP_BZIP2", "ZIP_LZMA", - "is_zipfile", "ZipInfo", "ZipFile", "PyZipFile", "LargeZipFile"] + "is_zipfile", "ZipInfo", "ZipFile", "PyZipFile", "LargeZipFile", + "Path"] class BadZipFile(Exception): pass @@ -387,11 +386,11 @@ class ZipInfo (object): self.volume = 0 # Volume number of file header self.internal_attr = 0 # Internal attributes self.external_attr = 0 # External file attributes + self.compress_size = 0 # Size of the compressed file + self.file_size = 0 # Size of the uncompressed file # Other attributes are set by class ZipFile: # header_offset Byte offset to the file header # CRC CRC-32 of the uncompressed file - # compress_size Size of the compressed file - # file_size Size of the uncompressed file def __repr__(self): result = ['<%s filename=%r' % (self.__class__.__name__, self.filename)] @@ -476,44 +475,23 @@ class ZipInfo (object): if ln+4 > len(extra): raise BadZipFile("Corrupt extra field %04x (size=%d)" % (tp, ln)) if tp == 0x0001: - if ln >= 24: - counts = unpack(' A B C D - # unique_everseen('ABBCcAD', str.lower) --> A B C D - seen = set() - seen_add = seen.add - if key is None: - for element in itertools.filterfalse(seen.__contains__, iterable): - seen_add(element) - yield element - else: - for element in iterable: - k = key(element) - if k not in seen: - seen_add(k) - yield element - - def _parents(path): """ Given a path with elements separated by @@ -2193,6 +2153,18 @@ def _ancestry(path): path, tail = posixpath.split(path) +_dedupe = dict.fromkeys +"""Deduplicate an iterable in original order""" + + +def _difference(minuend, subtrahend): + """ + Return items in minuend not in subtrahend, retaining order + with O(1) lookup. + """ + return itertools.filterfalse(set(subtrahend).__contains__, minuend) + + class CompleteDirs(ZipFile): """ A ZipFile subclass that ensures that implied directories @@ -2202,13 +2174,8 @@ class CompleteDirs(ZipFile): @staticmethod def _implied_dirs(names): parents = itertools.chain.from_iterable(map(_parents, names)) - # Deduplicate entries in original order - implied_dirs = OrderedDict.fromkeys( - p + posixpath.sep for p in parents - # Cast names to a set for O(1) lookups - if p + posixpath.sep not in set(names) - ) - return implied_dirs + as_dirs = (p + posixpath.sep for p in parents) + return _dedupe(_difference(as_dirs, names)) def namelist(self): names = super(CompleteDirs, self).namelist() @@ -2337,20 +2304,31 @@ class Path: self.root = FastLookup.make(root) self.at = at - @property - def open(self): - return functools.partial(self.root.open, self.at) + def open(self, mode='r', *args, **kwargs): + """ + Open this entry as text or binary following the semantics + of ``pathlib.Path.open()`` by passing arguments through + to io.TextIOWrapper(). + """ + pwd = kwargs.pop('pwd', None) + zip_mode = mode[0] + stream = self.root.open(self.at, zip_mode, pwd=pwd) + if 'b' in mode: + if args or kwargs: + raise ValueError("encoding args invalid for binary operation") + return stream + return io.TextIOWrapper(stream, *args, **kwargs) @property def name(self): return posixpath.basename(self.at.rstrip("/")) def read_text(self, *args, **kwargs): - with self.open() as strm: - return io.TextIOWrapper(strm, *args, **kwargs).read() + with self.open('r', *args, **kwargs) as strm: + return strm.read() def read_bytes(self): - with self.open() as strm: + with self.open('rb') as strm: return strm.read() def _is_child(self, path): diff --git a/src/lib.rs b/src/lib.rs index ea9a9b74b9..4eb2d35584 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -45,13 +45,14 @@ extern crate log; use clap::{App, AppSettings, Arg, ArgMatches}; use rustpython_vm::{ - builtins::PyInt, compile, exceptions::print_exception, match_class, scope::Scope, stdlib::sys, - InitParameter, Interpreter, ItemProtocol, PyResult, PySettings, TypeProtocol, VirtualMachine, + builtins::PyDictRef, builtins::PyInt, compile, exceptions::print_exception, match_class, + scope::Scope, stdlib::sys, InitParameter, Interpreter, ItemProtocol, PyObjectRef, PyResult, + PySettings, TryFromObject, TypeProtocol, VirtualMachine, }; use std::convert::TryInto; use std::env; -use std::path::PathBuf; +use std::path::Path; use std::process; use std::str::FromStr; @@ -93,13 +94,7 @@ where }; let interp = Interpreter::new_with_init(settings, |vm| { - #[cfg(feature = "stdlib")] - { - let stdlib = rustpython_stdlib::get_module_inits(); - for (name, init) in stdlib.into_iter() { - vm.add_native_module(name, init); - } - } + add_stdlib(vm); init(vm); init_param }); @@ -312,6 +307,17 @@ fn parse_arguments<'a>(app: App<'a, '_>) -> ArgMatches<'a> { app.get_matches() } +fn add_stdlib(vm: &mut VirtualMachine) { + let _ = vm; + #[cfg(feature = "stdlib")] + { + let stdlib = rustpython_stdlib::get_module_inits(); + for (name, init) in stdlib.into_iter() { + vm.add_native_module(name, init); + } + } +} + /// Create settings by examining command line arguments and environment /// variables. fn create_settings(matches: &ArgMatches) -> PySettings { @@ -327,6 +333,9 @@ fn create_settings(matches: &ArgMatches) -> PySettings { }; let ignore_environment = settings.ignore_environment || settings.isolated; + // when rustpython-vm/pylib is enabled, PySettings::default().path_list has pylib::LIB_PATH + let maybe_pylib = settings.path_list.pop(); + // add the current directory to sys.path settings.path_list.push("".to_owned()); @@ -336,8 +345,7 @@ fn create_settings(matches: &ArgMatches) -> PySettings { std::env::split_paths(paths).map(|path| path.into_os_string().into_string().unwrap()), ) } else { - #[cfg(all(feature = "pylib", not(feature = "freeze-stdlib")))] - settings.path_list.push(pylib::LIB_PATH.to_owned()); + settings.path_list.extend(maybe_pylib); } if !ignore_environment { @@ -524,7 +532,7 @@ fn write_profile(matches: &ArgMatches) -> Result<(), Box> Ok(()) } -fn run_rustpython(vm: &VirtualMachine, matches: &ArgMatches) -> PyResult<()> { +fn setup_main_module(vm: &VirtualMachine) -> PyResult { let scope = vm.new_scope_with_builtins(); let main_module = vm.new_module("__main__", scope.globals.clone(), None); main_module @@ -542,6 +550,12 @@ fn run_rustpython(vm: &VirtualMachine, matches: &ArgMatches) -> PyResult<()> { vm.get_attribute(vm.sys_module.clone(), "modules")? .set_item("__main__", main_module, vm)?; + Ok(scope) +} + +fn run_rustpython(vm: &VirtualMachine, matches: &ArgMatches) -> PyResult<()> { + let scope = setup_main_module(vm)?; + let site_result = vm.import("site", None, 0); if site_result.is_err() { @@ -613,58 +627,91 @@ fn run_module(vm: &VirtualMachine, module: &str) -> PyResult<()> { Ok(()) } -fn run_script(vm: &VirtualMachine, scope: Scope, script_file: &str) -> PyResult<()> { - debug!("Running file {}", script_file); - let mut file_path = PathBuf::from(script_file); - let file_meta = file_path.metadata().unwrap_or_else(|e| { - error!("can't open file '{}': {}", file_path.display(), e); - process::exit(1); - }); - if file_meta.is_dir() { - file_path.push("__main__.py"); - if !file_path.is_file() { - error!("can't find '__main__' module in '{}'", file_path.display()); - process::exit(1); +fn get_importer(path: &str, vm: &VirtualMachine) -> PyResult> { + let path_importer_cache = vm.get_attribute(vm.sys_module.clone(), "path_importer_cache")?; + let path_importer_cache = PyDictRef::try_from_object(vm, path_importer_cache)?; + if let Some(importer) = path_importer_cache.get_item_option(path, vm)? { + return Ok(Some(importer)); + } + let path = vm.ctx.new_utf8_str(path); + let path_hooks = vm.get_attribute(vm.sys_module.clone(), "path_hooks")?; + let mut importer = None; + for path_hook in vm.extract_elements(&path_hooks)? { + match vm.invoke(&path_hook, (path.clone(),)) { + Ok(imp) => { + importer = Some(imp); + break; + } + Err(e) if e.isinstance(&vm.ctx.exceptions.import_error) => continue, + Err(e) => return Err(e), } } + Ok(if let Some(imp) = importer { + let imp = path_importer_cache.get_or_insert(vm, path, || imp.clone())?; + Some(imp) + } else { + None + }) +} - let dir = file_path.parent().unwrap().to_str().unwrap().to_owned(); +fn insert_sys_path(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<()> { let sys_path = vm.get_attribute(vm.sys_module.clone(), "path").unwrap(); - vm.call_method(&sys_path, "insert", (0, dir))?; + vm.call_method(&sys_path, "insert", (0, obj))?; + Ok(()) +} - match std::fs::read_to_string(&file_path) { +fn run_script(vm: &VirtualMachine, scope: Scope, script_file: &str) -> PyResult<()> { + debug!("Running file {}", script_file); + if get_importer(script_file, vm)?.is_some() { + insert_sys_path(vm, vm.ctx.new_utf8_str(script_file))?; + let runpy = vm.import("runpy", None, 0)?; + let run_module_as_main = vm.get_attribute(runpy, "_run_module_as_main")?; + vm.invoke( + &run_module_as_main, + (vm.ctx.new_utf8_str("__main__"), false), + )?; + return Ok(()); + } + let dir = Path::new(script_file).parent().unwrap().to_str().unwrap(); + insert_sys_path(vm, vm.ctx.new_utf8_str(dir))?; + + match std::fs::read_to_string(script_file) { Ok(source) => { - _run_string(vm, scope, &source, file_path.to_str().unwrap().to_owned())?; + _run_string(vm, scope, &source, script_file.to_owned())?; } Err(err) => { - error!( - "Failed reading file '{}': {:?}", - file_path.to_str().unwrap(), - err.kind() - ); + error!("Failed reading file '{}': {}", script_file, err); process::exit(1); } } Ok(()) } -#[test] -fn test_run_script() { - Interpreter::default().enter(|vm| { - // test file run - let r = run_script( - vm, - vm.new_scope_with_builtins(), - "extra_tests/snippets/dir_main/__main__.py", - ); - assert!(r.is_ok()); +#[cfg(test)] +mod tests { + use super::*; - // test module run - let r = run_script( - vm, - vm.new_scope_with_builtins(), - "extra_tests/snippets/dir_main", - ); - assert!(r.is_ok()); - }) + fn interpreter() -> Interpreter { + Interpreter::new_with_init(PySettings::default(), |vm| { + add_stdlib(vm); + InitParameter::External + }) + } + + #[test] + fn test_run_script() { + interpreter().enter(|vm| { + vm.unwrap_pyresult((|| { + let scope = setup_main_module(vm)?; + // test file run + run_script(vm, scope, "extra_tests/snippets/dir_main/__main__.py")?; + + let scope = setup_main_module(vm)?; + // test module run + run_script(vm, scope, "extra_tests/snippets/dir_main")?; + + Ok(()) + })()); + }) + } } diff --git a/vm/src/builtins/dict.rs b/vm/src/builtins/dict.rs index 7a57d688df..31ab82f10a 100644 --- a/vm/src/builtins/dict.rs +++ b/vm/src/builtins/dict.rs @@ -302,6 +302,15 @@ impl PyDict { .setdefault(vm, key, || default.unwrap_or_none(vm)) } + pub fn get_or_insert( + &self, + vm: &VirtualMachine, + key: PyObjectRef, + default: impl FnOnce() -> PyObjectRef, + ) -> PyResult { + self.entries.setdefault(vm, key, default) + } + #[pymethod] pub fn copy(&self) -> PyDict { PyDict { diff --git a/vm/src/builtins/function.rs b/vm/src/builtins/function.rs index 8b5b04b18e..70fefe5a6a 100644 --- a/vm/src/builtins/function.rs +++ b/vm/src/builtins/function.rs @@ -317,6 +317,7 @@ impl PyFunction { } } + #[inline(always)] pub fn invoke(&self, func_args: FuncArgs, vm: &VirtualMachine) -> PyResult { self.invoke_with_locals(func_args, None, vm) } diff --git a/vm/src/frame.rs b/vm/src/frame.rs index 02d345dcda..ee9898fc1c 100644 --- a/vm/src/frame.rs +++ b/vm/src/frame.rs @@ -202,7 +202,7 @@ impl Frame { } impl FrameRef { - #[inline] + #[inline(always)] fn with_exec(&self, f: impl FnOnce(ExecutingFrame) -> R) -> R { let mut state = self.state.lock(); let exec = ExecutingFrame { diff --git a/vm/src/function.rs b/vm/src/function.rs index af461ff3a1..632cf3467f 100644 --- a/vm/src/function.rs +++ b/vm/src/function.rs @@ -594,6 +594,7 @@ impl IntoPyNativeFunc<(T, R, VM)> for F where F: PyNativeFuncInternal, { + #[inline(always)] fn call(&self, vm: &VirtualMachine, args: FuncArgs) -> PyResult { self.call_(vm, args) } diff --git a/vm/src/stdlib/sys.rs b/vm/src/stdlib/sys.rs index fa6480c920..9c0e59bf76 100644 --- a/vm/src/stdlib/sys.rs +++ b/vm/src/stdlib/sys.rs @@ -655,6 +655,7 @@ settrace() -- set the global debug tracing function let base_prefix = option_env!("RUSTPYTHON_BASEPREFIX").unwrap_or(prefix); let exec_prefix = option_env!("RUSTPYTHON_EXECPREFIX").unwrap_or(prefix); let base_exec_prefix = option_env!("RUSTPYTHON_BASEEXECPREFIX").unwrap_or(exec_prefix); + let platlibdir = option_env!("RUSTPYTHON_PLATLIBDIR").unwrap_or("lib"); extend_module!(vm, module, { "__name__" => ctx.new_ascii_literal(ascii!("sys")), @@ -702,6 +703,7 @@ settrace() -- set the global debug tracing function "base_prefix" => ctx.new_utf8_str(base_prefix), "exec_prefix" => ctx.new_utf8_str(exec_prefix), "base_exec_prefix" => ctx.new_utf8_str(base_exec_prefix), + "platlibdir" => ctx.new_utf8_str(platlibdir), "exit" => named_function!(ctx, sys, exit), "abiflags" => ctx.new_utf8_str(ABIFLAGS.to_owned()), "audit" => named_function!(ctx, sys, audit), diff --git a/vm/src/vm.rs b/vm/src/vm.rs index ec1ab4a833..5575def1de 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -495,6 +495,7 @@ impl VirtualMachine { self.run_frame_full(frame) } + #[inline(always)] pub fn run_frame_full(&self, frame: FrameRef) -> PyResult { match self.run_frame(frame)? { ExecutionResult::Return(value) => Ok(value), @@ -804,7 +805,8 @@ impl VirtualMachine { self.new_exception_empty(stop_iteration_type) } - // TODO: #[track_caller] when stabilized + #[track_caller] + #[cold] fn _py_panic_failed(&self, exc: PyBaseExceptionRef, msg: &str) -> ! { #[cfg(not(all(target_arch = "wasm32", not(target_os = "wasi"))))] { @@ -831,13 +833,21 @@ impl VirtualMachine { panic!("{}; exception backtrace above", msg) } } + #[track_caller] pub fn unwrap_pyresult(&self, result: PyResult) -> T { - result.unwrap_or_else(|exc| { - self._py_panic_failed(exc, "called `vm.unwrap_pyresult()` on an `Err` value") - }) + match result { + Ok(x) => x, + Err(exc) => { + self._py_panic_failed(exc, "called `vm.unwrap_pyresult()` on an `Err` value") + } + } } + #[track_caller] pub fn expect_pyresult(&self, result: PyResult, msg: &str) -> T { - result.unwrap_or_else(|exc| self._py_panic_failed(exc, msg)) + match result { + Ok(x) => x, + Err(exc) => self._py_panic_failed(exc, msg), + } } pub fn new_scope_with_builtins(&self) -> Scope { @@ -1196,7 +1206,7 @@ impl VirtualMachine { } } - #[inline] + #[inline(always)] pub fn invoke(&self, func_ref: &PyObjectRef, args: T) -> PyResult where T: IntoFuncArgs,