Live data from Hacker News

Hot-code reloading on macOS/arm64 with Zig

jakubkonka.com

41–50 of 57 posts

Re: Hot-code reloading on macOS/arm64 with Zig

#41

> Instead of having your program managed by a running side-by-side loader program, what if the compiler would “simply” update the memory of the running process? You will most inevitably think I have gone completely crazy This isn't crazy - this is how just-in-time compilers work.

A typical JIT compiler runs in the same process as the executable as part of its runtime -- it's a program modifying itself. This is describing a compiler modifying the memory of a separate running process out from underneath it. Which does seem a little crazy, and the post doesn't go into details about how the compiler knows when it's reasonable to rewrite instructions -- it seems like you would need some runtime me…

> it seems like you would need some runtime mechanism in the child to coordinate this

I had been thinking about what mechanism you could put in place to coordinate, but you made me realize that if your language provides some kind of event loop, then that would be the right place to have the "please stop while I push this old function under the rug" functionality. And languages that have async/await have to have such a runtime, which can make the whole thing completely transparent to the programmer. But you still need the inter-process comms to let the runtime know it should wait for a bit, so your last sentence still applies: at that point have the process rewrite itself.

Re: Hot-code reloading on macOS/arm64 with Zig

#42
post #21

This looks awesome for game development! Short feedback loops are a superpower.

If you watch some of Notch’s old game jam live streams; this is exactly how he used his Java environment and is probably why he was so invested in it. You can see some examples here when he just tests logic changes: https://youtu.be/MhQ70O1MiXc (Though, he restarts often since he’s editing preloaded assets also)

The irony is that C++ got it before Java, but those environments were too resource hungry for them to suceed in the market.

Now almost 30 years later is when we see them being adopted.

"Lucid Energize Demo VHS 1993"

https://www.youtube.com/watch?v=pQQTScuApWk

Visual Age for C++ v4 had a similar capability, it was image based and allowed for Smalltalk like workflows.

Re: Hot-code reloading on macOS/arm64 with Zig

#43
post #42

Earlier quoted context omitted.

If you watch some of Notch’s old game jam live streams; this is exactly how he used his Java environment and is probably why he was so invested in it. You can see some examples here when he just tests logic changes: https://youtu.be/MhQ70O1MiXc (Though, he restarts often since he’s editing preloaded assets also)

The irony is that C++ got it before Java, but those environments were too resource hungry for them to suceed in the market. Now almost 30 years later is when we see them being adopted. "Lucid Energize Demo VHS 1993" https://www.youtube.com/watch?v=pQQTScuApWk Visual Age for C++ v4 had a similar capability, it was image based and allowed for Smalltalk like workflows.

Yeah it's weird - basically all JIT compilers have this feature built-n - they usually create stubs for not yet called functions which invoke the JIT, and replace the stub calls with actual executable code.

Re: Hot-code reloading on macOS/arm64 with Zig

#44

> Instead of having your program managed by a running side-by-side loader program, what if the compiler would “simply” update the memory of the running process? You will most inevitably think I have gone completely crazy This isn't crazy - this is how just-in-time compilers work.

A typical JIT compiler runs in the same process as the executable as part of its runtime -- it's a program modifying itself. This is describing a compiler modifying the memory of a separate running process out from underneath it. Which does seem a little crazy, and the post doesn't go into details about how the compiler knows when it's reasonable to rewrite instructions -- it seems like you would need some runtime me…

>how the compiler knows when it's reasonable to rewrite instructions

JIT languages tend to be also GC languages, which tend to have a very good idea of when it's safe to stop a thread, and what the values in the registers and stack mean at a particular point in time.

Re: Hot-code reloading on macOS/arm64 with Zig

#45

This seems like it would just crash or make your program get into an inconsistent state. What happens if you are executing a transaction but mid transaction your binary gets updated and your transaction now has done half of what's needed by the old version and half of what's needed by the new version. I don't think it would be that hard to get into an inconsistent state.

Well, games have a leg up on the competition in this regard - games tend to have some update logic which is called 60 times per second.

If you can restrict the code that runs between frames, you can just replace the logic everywhere between the frames, and not have to worry about what code the threads are executing at this time - since game logic is not running.

Re: Hot-code reloading on macOS/arm64 with Zig

#46
post #42

Earlier quoted context omitted.

The irony is that C++ got it before Java, but those environments were too resource hungry for them to suceed in the market. Now almost 30 years later is when we see them being adopted. "Lucid Energize Demo VHS 1993" https://www.youtube.com/watch?v=pQQTScuApWk Visual Age for C++ v4 had a similar capability, it was image based and allowed for Smalltalk like workflows.

Yeah it's weird - basically all JIT compilers have this feature built-n - they usually create stubs for not yet called functions which invoke the JIT, and replace the stub calls with actual executable code.

Visual Studio also has had it for several years in debug mode for C++, Edit-and-Continue.

Since last year they have been working on it to make it more dynamic, improving the use cases.

It is these little things that make it so much better than the UNIX alternatives.

However there is also ROOT and now CINT from CERN, or Live++.

Re: Hot-code reloading on macOS/arm64 with Zig

#48
post #37

Awesome! vlang has it too: https://github.com/vlang/v/blob/master/doc/docs.md#hot-code-...

Nice! V does it the same way as Nim though, right? From quickly browsing over the sources, it looks like it is based on dynamic library hot swapping https://github.com/vlang/v/tree/master/vlib/v/live

What are the pros/cons of one vs. the other?

Re: Hot-code reloading on macOS/arm64 with Zig

#49
post #11

Earlier quoted context omitted.

Wait, but what about debuggers then? Plus hot-code reloading should only ever be used for quick development cycles when prototyping your app in debug mode, so very much what a debugger is used for, right? Additionally, I actually based the implementation of this PoC on lldb's debugserver for macOS.

Yeah this entitlement says your application is still “in-development” and allows a debugger to modify its executable memory.

Exactly, and the way I see it, this is the only valid use case for hot-code reloading in the first place: app in-development. I'll try augmenting my linker to be able to bake in the entitlements into the Zig compiler and this hopefully will remove the requirement for elevating privs via "sudo". Thanks for your comments though - it's been very enlightening :-)

Re: Hot-code reloading on macOS/arm64 with Zig

#50
post #37

Earlier quoted context omitted.

Nice! V does it the same way as Nim though, right? From quickly browsing over the sources, it looks like it is based on dynamic library hot swapping https://github.com/vlang/v/tree/master/vlib/v/live

What are the pros/cons of one vs. the other?

Great question. With the presented approach in Zig, since you work on the binary directly, after you finish your hot-code reloading session, you can still run the generated binary from disk (and debug it or whatnot) as all writes to memory were also committed to the underlying file on disk. There is therefore no need to recompile your program to an executable from a dynamic library as I guess would be the case for approach taken by Nim/V.

The presented approach might also be more resource efficient as it is writing directly to program's memory rather than unloading and reloading a dynamic library, but this is very much a guess and I would need to do some benchmarking to get a better feel for it.

In general though, this approach is possible in Zig since first of all, we have our own linker for each target file format (ELF, MachO, COFF-coming-soon-tm), secondly, the compiler generates the executable file directly, and thirdly, incremental updates are super granular in order to minimise writes to the file as much as possible.

Post reply on HN