Stream: cranelift

Topic: ✔ Question about hotswapping


view this post on Zulip Setzer22 (Apr 17 2023 at 18:23):

Hi! Apologies if I'm on the wrong channel or I didn't post this properly, I'm still getting this Zulip thing figured out :)

I've been checking out Cranelift as a potential backend to build a toy language. The main focus of the language is to support runtime compilation to native code via a JIT (no interpreter+JIT, just the JIT) and to have a very strong focus on hot reloading. Initially I was considering Inkwell (LLVM), but somone pointed me at cranelift and I must say after a quick look it looks like a great fit!

Anyway, I wanted to ask about the hotswapping feature in cranelift, which I actually stumbled upon when browsing through the code. There's this function:

    /// Enable or disable hotswap support. See [`JITModule::prepare_for_function_redefine`]
    /// for more information.
    ///
    /// Enabling hotswap support requires PIC code.
    pub fn hotswap(&mut self, enabled: bool) -> &mut Self {

And what this (and the documentation for prepare_for_function_redefine) seems to indicate, is that if I keep a JITModule around at runtime, when there are changes for a function, I can simply update the code for that function and redefine it inside the module without having to throw away the whole module and recompile that plus every module it's linked to from scratch?

In general, I'd appreciate it if someone could point me at some piece of documentation that discusses this. I've not been able to figure out much after a few google searches :sweat_smile:

view this post on Zulip Chris Fallin (Apr 17 2023 at 18:28):

cc @bjorn3 ; I'll note that cranelift-jit is a layer on top of the core compiler (cranelift-codegen) that you don't have to use, and e.g. Wasmtime has its own JIT code management. But it's probably a good start if you have no other specific requirements and we should fix any gaps in the documentation you find!

view this post on Zulip bjorn3 (Apr 17 2023 at 18:38):

The hotswap feature of cranelift-jit allows you to swap out individual functions at runtime such that all future calls will call the new function, while calls that are still on the stack will use the old version. Note that it will currently never deallocate old functions and if you are doing many memory allocations before hot swapping, you may get a panic. I introduced it for an experiment to add hotswap support to rustc_codegen_cranelift, but haven't worked on the experiment since. I don't know if it will be suitable for your use. If not, you could either try improving cranelift-jit or write something from scratch. There is no need to use cranelift-jit. cranelift-codegen is the actual core of Cranelift and compiles individual functions. cranelift-jit and cranelift-object merely glue the codegen results together into executable memory and object files respectively.

view this post on Zulip Setzer22 (Apr 18 2023 at 07:45):

Thanks for the quick replies!

I'll note that cranelift-jit is a layer on top of the core compiler (cranelift-codegen)

Right, that makes sense! For now I'm going to use it since it's convenient to have, but it's really good to know that the jit crate is not that huge and could be customized if needed.

if you are doing many memory allocations before hot swapping, you may get a panic

Sorry for the ignorance :sweat_smile: But when you say memory allocations here, I assume you don't mean the runtime program allocating stuff on the heap (e.g. via malloc)? I assume you mean constants that are stored in the executable at compile time will not get freed? That sounds fair, and I can probably live with that.

I don't know if it will be suitable for your use. If not, you could either try improving cranelift-jit or write something from scratch. (...) cranelift-jit and cranelift-object merely glue the codegen results together into executable memory and object files respectively.

Thanks! That helps me see the whole picture a lot better. I was confused by the multiple cranelift crates at first. I'm going to start with cranelift-jit since it looks like a good starting point.

view this post on Zulip bjorn3 (Apr 18 2023 at 20:00):

I mean memory allocated using malloc. The issue is that all memory used by cranelift-jit needs to be within 2GB of each other to allow using signed 32bit relative relocations. Doing memory allocations can push new memory allocated by cranelift-jit outside of this range.

view this post on Zulip bjorn3 (Apr 18 2023 at 20:04):

To fix this, cranelift-jit would either need to reserve the entire 2GB range or allocate the GOT (the table containing pointers to all functions that hotswapping writes to) and code pages together and duplicate GOT entries between the GOT of multiple allocated ranges.

view this post on Zulip Notification Bot (Apr 19 2023 at 19:37):

Setzer22 has marked this topic as resolved.


Last updated: Oct 23 2024 at 20:03 UTC