Merge pull request #2153 from skinny121/use-libffi

Use libffi to call jitted functions.
This commit is contained in:
Ben Lewis
2020-08-28 20:38:15 +12:00
committed by GitHub
7 changed files with 216 additions and 16 deletions

View File

@@ -20,8 +20,12 @@ jobs:
- uses: actions/checkout@master
- name: Set up the Windows environment
run: |
choco install llvm
powershell.exe scripts/symlinks-to-hardlinks.ps1
if: runner.os == 'Windows'
- name: Set up the Mac environment
run: brew install autoconf automake libtool
if: runner.os == 'macOS'
- name: Cache cargo dependencies
uses: actions/cache@v2
with:
@@ -52,8 +56,12 @@ jobs:
- uses: actions/checkout@master
- name: Set up the Windows environment
run: |
choco install llvm
powershell.exe scripts/symlinks-to-hardlinks.ps1
if: runner.os == 'Windows'
- name: Set up the Mac environment
run: brew install autoconf automake libtool
if: runner.os == 'macOS'
- name: Cache cargo dependencies
uses: actions/cache@v2
with:

139
Cargo.lock generated
View File

@@ -6,6 +6,12 @@ version = "0.11.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3"
[[package]]
name = "abort_on_panic"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "955f37ac58af2416bac687c8ab66a4ccba282229bd7422a28d2281a5e66a6116"
[[package]]
name = "adler"
version = "0.2.3"
@@ -117,6 +123,30 @@ dependencies = [
"serde",
]
[[package]]
name = "bindgen"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1c85344eb535a31b62f0af37be84441ba9e7f0f4111eb0530f43d15e513fe57"
dependencies = [
"bitflags",
"cexpr",
"cfg-if",
"clang-sys",
"clap",
"env_logger",
"lazy_static 1.4.0",
"lazycell",
"log",
"peeking_take_while",
"proc-macro2",
"quote",
"regex",
"rustc-hash",
"shlex",
"which",
]
[[package]]
name = "bit-set"
version = "0.5.2"
@@ -234,6 +264,15 @@ version = "1.0.59"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "66120af515773fb005778dc07c261bd201ec8ce50bd6e7144c927753fe013381"
[[package]]
name = "cexpr"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fce5b5fb86b0c57c20c834c1b412fd09c77c8a59b9473f86272709e78874cd1d"
dependencies = [
"nom",
]
[[package]]
name = "cfg-if"
version = "0.1.10"
@@ -253,6 +292,17 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "clang-sys"
version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81de550971c976f176130da4b2978d3b524eaa0fd9ac31f3ceb5ae1231fb4853"
dependencies = [
"glob",
"libc",
"libloading",
]
[[package]]
name = "clap"
version = "2.33.3"
@@ -722,6 +772,12 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "glob"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
[[package]]
name = "hashbrown"
version = "0.8.2"
@@ -868,6 +924,12 @@ version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "lazycell"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]]
name = "lexical-core"
version = "0.7.4"
@@ -887,6 +949,39 @@ version = "0.2.76"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "755456fae044e6fa1ebbbd1b3e902ae19e73097ed4ed87bb79934a867c007bc3"
[[package]]
name = "libffi"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c18efe55925cc7f83bf60a61394696a734ae90e668d1f2bbd954354416fec6f2"
dependencies = [
"abort_on_panic",
"libc",
"libffi-sys",
]
[[package]]
name = "libffi-sys"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f00e48ce437c5741a4da3b51738498343b5158c37bfa02bcb969efcc44e4e06"
dependencies = [
"bindgen",
"cc",
"make-cmd",
"pkg-config",
]
[[package]]
name = "libloading"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2b111a074963af1d37a139918ac6d49ad1d0d5e47f72fd55388619691a7d753"
dependencies = [
"cc",
"winapi",
]
[[package]]
name = "libz-sys"
version = "1.1.0"
@@ -932,6 +1027,12 @@ dependencies = [
"libc",
]
[[package]]
name = "make-cmd"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8ca8afbe8af1785e09636acb5a41e08a765f5f0340568716c18a8700ba3c0d3"
[[package]]
name = "maplit"
version = "1.0.2"
@@ -999,6 +1100,16 @@ dependencies = [
"void",
]
[[package]]
name = "nom"
version = "4.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6"
dependencies = [
"memchr",
"version_check",
]
[[package]]
name = "num-bigint"
version = "0.3.0"
@@ -1195,6 +1306,12 @@ dependencies = [
"proc-macro-hack",
]
[[package]]
name = "peeking_take_while"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
[[package]]
name = "petgraph"
version = "0.5.1"
@@ -1539,6 +1656,7 @@ dependencies = [
"cranelift",
"cranelift-module",
"cranelift-simplejit",
"libffi",
"num-traits",
"rustpython-bytecode",
"thiserror",
@@ -1810,6 +1928,12 @@ dependencies = [
"opaque-debug",
]
[[package]]
name = "shlex"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"
[[package]]
name = "siphasher"
version = "0.3.3"
@@ -2204,6 +2328,12 @@ version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
[[package]]
name = "version_check"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
[[package]]
name = "void"
version = "1.0.2"
@@ -2298,6 +2428,15 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "which"
version = "3.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d011071ae14a2f6671d0b74080ae0cd8ebf3a6f8c9589a2cd45f23126fe29724"
dependencies = [
"libc",
]
[[package]]
name = "winapi"
version = "0.3.9"

View File

@@ -74,6 +74,30 @@ cargo build --release --target wasm32-wasi --features="freeze-stdlib"
> Note: we use the `freeze-stdlib` to include the standard library inside the binary.
### JIT(Just in time) compiler
RustPython has an **very** experimental JIT compiler that compile python functions into native code.
#### Building
By default the JIT compiler isn't enabled, it's enabled with the `jit` cargo feature.
$ cargo run --features jit
This requires autoconf, automake, libtool, and clang to be installed.
#### Using
To compile a function, call `__jit__()` on it.
```python
def foo():
a = 5
return 10 + a
foo.__jit__() # this will compile foo to native code and subsequent calls will execute that native code
assert foo() == 15
```
## Embedding RustPython into your Rust Applications

View File

@@ -12,5 +12,6 @@ cranelift = "0.66.0"
cranelift-module = "0.66.0"
cranelift-simplejit = "0.66.0"
num-traits = "0.2"
libffi = "0.9.0"
rustpython-bytecode = { path = "../bytecode", version = "0.1.1" }
thiserror = "1.0"

View File

@@ -10,6 +10,16 @@ pub struct JitSig {
pub ret: Option<JitType>,
}
impl JitSig {
pub fn to_cif(&self) -> libffi::middle::Cif {
let ret = match self.ret {
Some(ref ty) => ty.to_libffi(),
None => libffi::middle::Type::void(),
};
libffi::middle::Cif::new(Vec::new(), ret)
}
}
#[derive(Clone, PartialEq)]
pub enum JitType {
Int,
@@ -23,6 +33,13 @@ impl JitType {
Self::Float => types::F64,
}
}
fn to_libffi(&self) -> libffi::middle::Type {
match self {
Self::Int => libffi::middle::Type::i64(),
Self::Float => libffi::middle::Type::f64(),
}
}
}
#[derive(Clone)]
@@ -132,8 +149,9 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> {
Ok(())
}
Instruction::BinaryOperation { op, .. } => {
let a = self.stack.pop().ok_or(JitCompileError::BadBytecode)?;
// the rhs is popped off first
let b = self.stack.pop().ok_or(JitCompileError::BadBytecode)?;
let a = self.stack.pop().ok_or(JitCompileError::BadBytecode)?;
match (a.ty, b.ty) {
(JitType::Int, JitType::Int) => match op {
BinaryOperator::Add => {

View File

@@ -1,5 +1,4 @@
use std::fmt;
use std::mem;
use cranelift::prelude::*;
use cranelift_module::{Backend, FuncId, Linkage, Module, ModuleError};
@@ -98,20 +97,13 @@ pub struct CompiledCode {
impl CompiledCode {
pub fn invoke(&self) -> Option<AbiValue> {
match self.sig.ret {
Some(JitType::Int) => {
let func = unsafe { mem::transmute::<_, fn() -> i64>(self.code) };
Some(AbiValue::Int(func()))
}
Some(JitType::Float) => {
let func = unsafe { mem::transmute::<_, fn() -> f64>(self.code) };
Some(AbiValue::Float(func()))
}
None => {
let func = unsafe { mem::transmute::<_, fn()>(self.code) };
func();
None
}
let cif = self.sig.to_cif();
unsafe {
let value = cif.call::<UnTypedAbiValue>(
libffi::middle::CodePtr::from_ptr(self.code as *const _),
&[],
);
self.sig.ret.as_ref().map(|ty| value.to_typed(ty))
}
}
}
@@ -121,6 +113,21 @@ pub enum AbiValue {
Int(i64),
}
union UnTypedAbiValue {
float: f64,
int: i64,
_void: (),
}
impl UnTypedAbiValue {
unsafe fn to_typed(&self, ty: &JitType) -> AbiValue {
match ty {
JitType::Int => AbiValue::Int(self.int),
JitType::Float => AbiValue::Float(self.float),
}
}
}
unsafe impl Send for CompiledCode {}
unsafe impl Sync for CompiledCode {}

View File

@@ -3,6 +3,7 @@ def foo():
a = 5
return 10 + a
def bar():
a = 1e6
return a / 5.0
@@ -12,9 +13,11 @@ def tests():
assert foo() == 15
assert bar() == 2e5
tests()
if hasattr(foo, "__jit__"):
print("Has jit")
foo.__jit__()
bar.__jit__()
tests()