Handle first couple of bytecode instructions in jit. · RustPython/RustPython@bf221bf · GitHub
Skip to content

Commit bf221bf

Browse files
committed
Handle first couple of bytecode instructions in jit.
1 parent b2ab9d9 commit bf221bf

5 files changed

Lines changed: 132 additions & 30 deletions

File tree

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

jit/Cargo.toml

Lines changed: 2 additions & 1 deletion

jit/src/instructions.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
use cranelift::prelude::*;
2+
use num_traits::cast::ToPrimitive;
3+
use rustpython_bytecode::bytecode::{Constant, Instruction};
4+
5+
use super::JITCompileError;
6+
7+
pub struct FunctionCompiler<'a, 'b> {
8+
builder: &'a mut FunctionBuilder<'b>,
9+
stack: Vec<Value>,
10+
}
11+
12+
impl<'a, 'b> FunctionCompiler<'a, 'b> {
13+
pub fn new(builder: &'a mut FunctionBuilder<'b>) -> FunctionCompiler<'a, 'b> {
14+
FunctionCompiler {
15+
builder,
16+
stack: Vec::new(),
17+
}
18+
}
19+
20+
pub fn add_instruction(&mut self, instruction: &Instruction) -> Result<(), JITCompileError> {
21+
match instruction {
22+
Instruction::LoadConst {
23+
value: Constant::Integer { value },
24+
} => {
25+
let val = self.builder.ins().iconst(
26+
types::I64,
27+
value.to_i64().ok_or(JITCompileError::NotSupported)?,
28+
);
29+
self.stack.push(val);
30+
Ok(())
31+
}
32+
Instruction::ReturnValue => {
33+
self.builder
34+
.ins()
35+
.return_(&[self.stack.pop().ok_or(JITCompileError::BadBytecode)?]);
36+
Ok(())
37+
}
38+
_ => Err(JITCompileError::NotSupported),
39+
}
40+
}
41+
}

jit/src/lib.rs

Lines changed: 76 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,48 @@
1+
use std::error::Error;
12
use std::fmt;
23
use std::mem;
34

45
use cranelift::prelude::*;
5-
use cranelift_module::{Backend, Module, Linkage, FuncId};
6+
use cranelift_module::{Backend, FuncId, Linkage, Module, ModuleError};
67
use cranelift_simplejit::{SimpleJITBackend, SimpleJITBuilder};
78

9+
use rustpython_bytecode::bytecode;
10+
11+
mod instructions;
12+
13+
use self::instructions::FunctionCompiler;
14+
15+
#[derive(Debug)]
16+
pub enum JITCompileError {
17+
NotSupported,
18+
BadBytecode,
19+
CraneliftError(ModuleError),
20+
}
21+
22+
impl From<ModuleError> for JITCompileError {
23+
fn from(err: ModuleError) -> Self {
24+
JITCompileError::CraneliftError(err)
25+
}
26+
}
27+
28+
impl fmt::Display for JITCompileError {
29+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30+
match *self {
31+
JITCompileError::NotSupported => f.write_str("Function can't be jitted."),
32+
JITCompileError::BadBytecode => f.write_str("Bad bytecode."),
33+
JITCompileError::CraneliftError(ref err) => err.fmt(f),
34+
}
35+
}
36+
}
37+
38+
impl Error for JITCompileError {
39+
fn source(&self) -> Option<&(dyn Error + 'static)> {
40+
match *self {
41+
JITCompileError::CraneliftError(ref err) => Some(err),
42+
_ => None,
43+
}
44+
}
45+
}
846

947
struct JIT {
1048
builder_context: FunctionBuilderContext,
@@ -23,53 +61,70 @@ impl JIT {
2361
}
2462
}
2563

26-
fn build_function(&mut self) -> FuncId {
27-
let id = self
28-
.module
29-
.declare_function("jitted", Linkage::Export, &self.ctx.func.signature)
30-
.unwrap();
64+
fn build_function(
65+
&mut self,
66+
bytecode: &bytecode::CodeObject,
67+
) -> Result<FuncId, JITCompileError> {
68+
// currently always returns an int
69+
self.ctx
70+
.func
71+
.signature
72+
.returns
73+
.push(AbiParam::new(types::I64));
74+
75+
let id = self.module.declare_function(
76+
&format!("jit_{}", bytecode.obj_name),
77+
Linkage::Export,
78+
&self.ctx.func.signature,
79+
)?;
3180

3281
let mut builder = FunctionBuilder::new(&mut self.ctx.func, &mut self.builder_context);
3382
let entry_block = builder.create_block();
3483
// builder.append_block_params_for_function_params(entry_block);
3584
builder.switch_to_block(entry_block);
36-
// builder.seal_block(entry_block);
37-
builder.ins().return_(&[]);
85+
builder.seal_block(entry_block);
86+
87+
{
88+
let mut compiler = FunctionCompiler::new(&mut builder);
89+
90+
for instruction in &bytecode.instructions {
91+
compiler.add_instruction(instruction)?;
92+
}
93+
};
94+
3895
builder.finalize();
3996

4097
self.module
41-
.define_function(id, &mut self.ctx, &mut codegen::binemit::NullTrapSink {})
42-
.unwrap();
98+
.define_function(id, &mut self.ctx, &mut codegen::binemit::NullTrapSink {})?;
4399

44100
self.module.clear_context(&mut self.ctx);
45101

46-
id
102+
Ok(id)
47103
}
48104
}
49105

50-
pub fn compile() -> CompiledCode {
51-
106+
pub fn compile(bytecode: &bytecode::CodeObject) -> Result<CompiledCode, JITCompileError> {
52107
let mut jit = JIT::new();
53108

54-
let id = jit.build_function();
109+
let id = jit.build_function(bytecode)?;
55110

56111
jit.module.finalize_definitions();
57112

58113
let code = jit.module.get_finalized_function(id);
59-
CompiledCode {
114+
Ok(CompiledCode {
60115
code,
61-
memory: jit.module.finish()
62-
}
116+
memory: jit.module.finish(),
117+
})
63118
}
64119

65120
pub struct CompiledCode {
66121
code: *const u8,
67-
memory: <SimpleJITBackend as Backend>::Product
122+
memory: <SimpleJITBackend as Backend>::Product,
68123
}
69124

70125
impl CompiledCode {
71-
pub fn invoke(&self) {
72-
let func = unsafe { mem::transmute::<_, fn()>(self.code) };
126+
pub fn invoke(&self) -> i64 {
127+
let func = unsafe { mem::transmute::<_, fn() -> i64>(self.code) };
73128
func()
74129
}
75130
}
@@ -79,9 +134,7 @@ unsafe impl Send for CompiledCode {}
79134
impl Drop for CompiledCode {
80135
fn drop(&mut self) {
81136
// SAFETY: The only pointer that this memory will also be dropped now
82-
unsafe {
83-
self.memory.free_memory()
84-
}
137+
unsafe { self.memory.free_memory() }
85138
}
86139
}
87140

vm/src/obj/objfunction.rs

Lines changed: 11 additions & 6 deletions

0 commit comments

Comments
 (0)