3 comments

[ 5.6 ms ] story [ 15.8 ms ] thread
> we can replace binaries on disk atomically, and their next invocation will automatically pick up the change.

Is there more to this than creating the new binary and renaming it into place? I think it even works on Windows.

> Cross-modifying machine code!

> Intel tells us we're not supposed to do that

> C library

ehhhh I think I'm okay.

>> Cross-modifying machine code!

>> Intel tells us we're not supposed to do that

> ehhhh I think I'm okay.

Much further down the text we discover it’s not as gung-ho as that: every switch involves two mprotect() calls (per affected page) to enable and disable write access, which entail TLB and cache flushes on all cores, and per Intel manuals this is actually pretty OK (except of course flag flips affecting multiple places in the code, including because of inlining, are non-atomic, so the guarded code needs to be ready for that; this is mentioned in the description as well). Intel do warn you self-modifying code is slow, and of course a multicore TLB flush is orders of magnitude slower than even that, but for a switch that is flipped manually, how fast do you really need it to be? It’s not like your systems are running close enough to their limit that the millisecond it’s going to take will cause the work queues to clog up.

I was also somewhat dismayed by that passage in the introduction at first, but all in all I’m surprised by how much I like this. I mean, I don’t think I have the problem this is supposed to solve, but provided somebody does, this solution has a refreshingly straightforward vibe. The kind from the primordial regular expressions library that implemented a JIT compiler by just writing 7094 code into an array[1]. You need to flip a jump, you patch the opcode byte. Why not? It’s a byte, it’s not like you need a complete machine-code generation library to change one.

[1] https://swtch.com/~rsc/regexp/regexp2.html

Similar logic is used to toggle on/off GC write barriers in JS jitcode.