From b2ab9d9bdf81cf642910d275da050cd490908ea8 Mon Sep 17 00:00:00 2001 From: Ben Lewis Date: Sat, 22 Aug 2020 13:26:39 +1200 Subject: [PATCH] Initial jit prototype. --- Cargo.lock | 229 ++++++++++++++++++++++++++++++++++++++ Cargo.toml | 2 +- jit/Cargo.toml | 14 +++ jit/src/lib.rs | 92 +++++++++++++++ vm/Cargo.toml | 1 + vm/src/obj/objfunction.rs | 15 +++ 6 files changed, 352 insertions(+), 1 deletion(-) create mode 100644 jit/Cargo.toml create mode 100644 jit/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 0c4714c5c..2c9fd426a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -36,6 +36,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "anyhow" +version = "1.0.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b602bfe940d21c130f3895acd65221e8a61270debe89d628b9cb4e3ccb8569b" + [[package]] name = "arr_macro" version = "0.1.3" @@ -289,6 +295,117 @@ dependencies = [ "python3-sys", ] +[[package]] +name = "cranelift" +version = "0.66.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fc21c925da7fbb64597c86521b59726426fb660ad30f898a01b957f39d15558" +dependencies = [ + "cranelift-codegen", + "cranelift-frontend", +] + +[[package]] +name = "cranelift-bforest" +version = "0.66.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dcc286b052ee24a1e5a222e7c1125e6010ad35b0f248709b9b3737a8fedcfdf" +dependencies = [ + "cranelift-entity", +] + +[[package]] +name = "cranelift-codegen" +version = "0.66.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d9badfe36176cb653506091693bc2bb1970c9bddfcd6ec7fac404f7eaec6f38" +dependencies = [ + "byteorder", + "cranelift-bforest", + "cranelift-codegen-meta", + "cranelift-codegen-shared", + "cranelift-entity", + "log", + "regalloc", + "smallvec", + "target-lexicon", + "thiserror", +] + +[[package]] +name = "cranelift-codegen-meta" +version = "0.66.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3f460031861e4f4ad510be62b2ae50bba6cc886b598a36f9c0a970feab9598" +dependencies = [ + "cranelift-codegen-shared", + "cranelift-entity", +] + +[[package]] +name = "cranelift-codegen-shared" +version = "0.66.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76ad12409e922e7697cd0bdc7dc26992f64a77c31880dfe5e3c7722f4710206d" + +[[package]] +name = "cranelift-entity" +version = "0.66.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d97cdc58972ea065d107872cfb9079f4c92ade78a8af85aaff519a65b5d13f71" + +[[package]] +name = "cranelift-frontend" +version = "0.66.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ef419efb4f94ecc02e5d9fbcc910d2bb7f0040e2de570e63a454f883bc891d6" +dependencies = [ + "cranelift-codegen", + "log", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-module" +version = "0.66.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "001d9b320ce30999c618db554ae9b23ec16d410493a502be674e2ef146bbdf0d" +dependencies = [ + "anyhow", + "cranelift-codegen", + "cranelift-entity", + "log", + "thiserror", +] + +[[package]] +name = "cranelift-native" +version = "0.66.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e69d44d59826eef6794066ac2c0f4ad3975f02d97030c60dbc04e3886adf36e" +dependencies = [ + "cranelift-codegen", + "raw-cpuid", + "target-lexicon", +] + +[[package]] +name = "cranelift-simplejit" +version = "0.66.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7506acda1b0df5419e8de5f1706cfcd8779d3d40d70c179f361e647fe9b18f0" +dependencies = [ + "cranelift-codegen", + "cranelift-module", + "cranelift-native", + "errno", + "libc", + "region", + "target-lexicon", + "winapi", +] + [[package]] name = "crc" version = "1.8.1" @@ -459,6 +576,27 @@ dependencies = [ "termcolor", ] +[[package]] +name = "errno" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eab5ee3df98a279d9b316b1af6ac95422127b1290317e6d18c1743c99418b01" +dependencies = [ + "errno-dragonfly", + "libc", + "winapi", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14ca354e36190500e1e1fb267c647932382b54053c50b14970856c0b00a35067" +dependencies = [ + "gcc", + "libc", +] + [[package]] name = "exitcode" version = "1.1.2" @@ -547,6 +685,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" +[[package]] +name = "gcc" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" + [[package]] name = "generic-array" version = "0.12.3" @@ -779,6 +923,15 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "761104bf97f13a3caf47d822498a0760a10d00d220148bac2669f63fc3bb8270" +[[package]] +name = "mach" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" +dependencies = [ + "libc", +] + [[package]] name = "maplit" version = "1.0.2" @@ -1180,6 +1333,17 @@ dependencies = [ "rand_core", ] +[[package]] +name = "raw-cpuid" +version = "7.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4a349ca83373cfa5d6dbb66fd76e58b2cca08da71a5f6400de0a0a6a9bceeaf" +dependencies = [ + "bitflags", + "cc", + "rustc_version", +] + [[package]] name = "redox_syscall" version = "0.1.57" @@ -1197,6 +1361,17 @@ dependencies = [ "rust-argon2", ] +[[package]] +name = "regalloc" +version = "0.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ba8aaf5fe7cf307c6dbdaeed85478961d29e25e3bee5169e11b92fa9f027a8" +dependencies = [ + "log", + "rustc-hash", + "smallvec", +] + [[package]] name = "regex" version = "1.3.9" @@ -1224,6 +1399,18 @@ version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8" +[[package]] +name = "region" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877e54ea2adcd70d80e9179344c97f93ef0dffd6b03e1f4529e6e83ab2fa9ae0" +dependencies = [ + "bitflags", + "libc", + "mach", + "winapi", +] + [[package]] name = "result-like" version = "0.2.1" @@ -1245,6 +1432,12 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustc_version" version = "0.2.3" @@ -1338,6 +1531,15 @@ dependencies = [ "syn-ext", ] +[[package]] +name = "rustpython-jit" +version = "0.1.2" +dependencies = [ + "cranelift", + "cranelift-module", + "cranelift-simplejit", +] + [[package]] name = "rustpython-parser" version = "0.1.2" @@ -1422,6 +1624,7 @@ dependencies = [ "rustpython-common", "rustpython-compiler", "rustpython-derive", + "rustpython-jit", "rustpython-parser", "rustpython-pylib", "rustyline", @@ -1692,6 +1895,12 @@ dependencies = [ "syn", ] +[[package]] +name = "target-lexicon" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab0e7238dcc7b40a7be719a25365910f6807bd864f4cce6b2e6b873658e2b19d" + [[package]] name = "term" version = "0.5.2" @@ -1721,6 +1930,26 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "thiserror" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dfdd070ccd8ccb78f4ad66bf1982dc37f620ef696c6b5028fe2ed83dd3d0d08" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd80fc12f73063ac132ac92aceea36734f04a1d93c1240c6944e23a3b8841793" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "thread-id" version = "3.3.0" diff --git a/Cargo.toml b/Cargo.toml index 99e67c50e..4942fd37d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT" include = ["LICENSE", "Cargo.toml", "src/**/*.rs"] [workspace] -members = [".", "derive", "vm", "wasm/lib", "parser", "compiler", "bytecode", "vm/pylib-crate", "common"] +members = [".", "derive", "vm", "wasm/lib", "parser", "compiler", "bytecode", "vm/pylib-crate", "common", "jit"] [[bench]] name = "bench" diff --git a/jit/Cargo.toml b/jit/Cargo.toml new file mode 100644 index 000000000..d759dfe4c --- /dev/null +++ b/jit/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "rustpython-jit" +version = "0.1.2" +description = "Experimental JIT(just in time) compiler for python code." +authors = [ "RustPython Team" ] +repository = "https://github.com/RustPython/RustPython" +license = "MIT" +edition = "2018" + +[dependencies] +cranelift = "0.66.0" +cranelift-module = "0.66.0" +cranelift-simplejit = "0.66.0" + diff --git a/jit/src/lib.rs b/jit/src/lib.rs new file mode 100644 index 000000000..fc51b6435 --- /dev/null +++ b/jit/src/lib.rs @@ -0,0 +1,92 @@ +use std::fmt; +use std::mem; + +use cranelift::prelude::*; +use cranelift_module::{Backend, Module, Linkage, FuncId}; +use cranelift_simplejit::{SimpleJITBackend, SimpleJITBuilder}; + + +struct JIT { + builder_context: FunctionBuilderContext, + ctx: codegen::Context, + module: Module, +} + +impl JIT { + fn new() -> Self { + let builder = SimpleJITBuilder::new(cranelift_module::default_libcall_names()); + let module = Module::new(builder); + Self { + builder_context: FunctionBuilderContext::new(), + ctx: module.make_context(), + module, + } + } + + fn build_function(&mut self) -> FuncId { + let id = self + .module + .declare_function("jitted", Linkage::Export, &self.ctx.func.signature) + .unwrap(); + + let mut builder = FunctionBuilder::new(&mut self.ctx.func, &mut self.builder_context); + let entry_block = builder.create_block(); + // builder.append_block_params_for_function_params(entry_block); + builder.switch_to_block(entry_block); + // builder.seal_block(entry_block); + builder.ins().return_(&[]); + builder.finalize(); + + self.module + .define_function(id, &mut self.ctx, &mut codegen::binemit::NullTrapSink {}) + .unwrap(); + + self.module.clear_context(&mut self.ctx); + + id + } +} + +pub fn compile() -> CompiledCode { + + let mut jit = JIT::new(); + + let id = jit.build_function(); + + jit.module.finalize_definitions(); + + let code = jit.module.get_finalized_function(id); + CompiledCode { + code, + memory: jit.module.finish() + } +} + +pub struct CompiledCode { + code: *const u8, + memory: ::Product +} + +impl CompiledCode { + pub fn invoke(&self) { + let func = unsafe { mem::transmute::<_, fn()>(self.code) }; + func() + } +} + +unsafe impl Send for CompiledCode {} + +impl Drop for CompiledCode { + fn drop(&mut self) { + // SAFETY: The only pointer that this memory will also be dropped now + unsafe { + self.memory.free_memory() + } + } +} + +impl fmt::Debug for CompiledCode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("[compiled code]") + } +} diff --git a/vm/Cargo.toml b/vm/Cargo.toml index b1376c10c..451a79df0 100644 --- a/vm/Cargo.toml +++ b/vm/Cargo.toml @@ -43,6 +43,7 @@ rustpython-derive = { path = "../derive", version = "0.1.2" } rustpython-parser = { path = "../parser", optional = true, version = "0.1.2" } rustpython-compiler = { path = "../compiler", optional = true, version = "0.1.2" } rustpython-bytecode = { path = "../bytecode", version = "0.1.2" } +rustpython-jit = { path = "../jit", version = "0.1.2" } rustpython-pylib = { path = "pylib-crate", optional = true, version = "0.1.0" } serde = { version = "1.0.66", features = ["derive"] } byteorder = "1.2.6" diff --git a/vm/src/obj/objfunction.rs b/vm/src/obj/objfunction.rs index 34b94b166..5b18d84d1 100644 --- a/vm/src/obj/objfunction.rs +++ b/vm/src/obj/objfunction.rs @@ -17,6 +17,8 @@ use crate::scope::Scope; use crate::slots::{SlotCall, SlotDescriptor}; use crate::VirtualMachine; use itertools::Itertools; +use rustpython_common::cell::PyMutex; +use rustpython_jit::CompiledCode; pub type PyFunctionRef = PyRef; @@ -24,6 +26,7 @@ pub type PyFunctionRef = PyRef; #[derive(Debug)] pub struct PyFunction { code: PyCodeRef, + jitted_code: PyMutex>, scope: Scope, defaults: Option, kw_only_defaults: Option, @@ -54,6 +57,7 @@ impl PyFunction { ) -> Self { PyFunction { code, + jitted_code: PyMutex::new(None), scope, defaults, kw_only_defaults, @@ -223,6 +227,11 @@ impl PyFunction { scope: &Scope, vm: &VirtualMachine, ) -> PyResult { + if let Some(jitted_code) = &*self.jitted_code.lock() { + jitted_code.invoke(); + return Ok(vm.get_none()); + } + let code = &self.code; let scope = if self.code.flags.contains(bytecode::CodeFlags::NEW_LOCALS) { @@ -285,6 +294,12 @@ impl PyFunction { fn globals(&self) -> PyDictRef { self.scope.globals.clone() } + + #[pymethod(magic)] + fn jit(&self) { + let mut guard = self.jitted_code.lock(); + *guard = Some(rustpython_jit::compile()); + } } #[pyclass(module = false, name = "method")]