Observing stale instruction fetching on x86 with self-modifying code
stackoverflow.com
stackoverflow.com
Existing implementations may be tighter, but as a programmer if you want your code to run reliably in the future you should follow the declared rules.
An example from elsewhere: RISC-V has an instruction that you execute between when you write the data to memory and when you execute the changed code. How it's implemented is up to the chip architect (this rather puts the shoe on a different foot architecturally) - at a worst case you have to: 1) flush the data to memory, 2) flush the instructions caches, 3) flush the execution queue .... a system with a good cache coherency setup might minimise this with: 1) flush the write queue to L1 data cache (as a side effect cache coherency flushes just the required instruction cache entries rather than the whole cache) 2) flush the execution queue - still not exactly lightweight, but you're likely going to pull those new instructions from the companion L1 data cache
I don't think any of JITs take this approach, as when they emit machine code it is always a fresh memory allocation and fresh compilation. JITs don't "poke and peek" already compiled code. But I could be wrong as JITs are getting complex today.
2) It greatly complicates things in terms of software engineering. It's bad practice unless strictly necessary. Code that rewrites itself is very hard to debug, trace and just generally work with, compared to immutable blocks of read-only code. Most high-level languages don't expose anything except function pointers in terms of self-modification, so compiled output would rarely need SMC. (Though it may be faster to emit SMC to implement high-level constructs, in some edge cases.)
The hardware doesn't like it and maintainers, managers, and most professors don't like it, either.
I think it was the Pentium that introduced split instruction/data caches on x86.