template <Runtime> would be the way to do it: we’d identify runtimes that want to use alternatives to relative pointers in some way and make the runtime abstraction substitute the right information. And then InProcess would ultimately use #if, yeah.
Well, it’s an option, if not necessarily an appealing one. Does that instruction format limit the range of the function, or does it encode a full 32 bit-immediate?
Let me step back and state where I think we are now. I always think it's valuable in this kind of project to first try to figure out the best thing we could do, so we know where want to end up. Once we've done that, then we can decide about how we want to get there.
Relative references on other targets don’t really have many significant trade-offs: they're nearly as cheap to access as absolute references, and they're substantially smaller (on 64-bit targets), and they don't have load-time or binary-size overheads. As a result, there isn’t much reason to avoid using them whenever possible in our constant metadata, especially since we expect PIC to be the common case: even executables are PIC on Darwin, and that seems to be where other OSes are headed as well, albeit somewhat slowly.
But as we’re figuring out here, the trade-offs are clearly different on Wasm, even with a perfectly cooperative toolchain: relative references from data to code aren’t possible in PIC, and the natural alternative (image-base-relative references) will require a runtime lookup that completely changes the cost profile. And I believe we also expect that the dominant code pattern on Wasm will not be PIC, and the general rule is that uncommon cases shouldn't greatly burden common cases. Therefore, we need to take the trade-offs of relative references more seriously on Wasm than we do elsewhere.
I think what that suggests is that we should be using absolute references in a lot more cases when targeting Wasm. Since data-to-data relative references are still okay, and they have size benefits on Wasm64 (and load-time/code-size benefits in PIC), we might as well continue to use those everywhere we do now. But data-to-code references should probably either be (1) unconditionally absolute or (2) somehow discriminated between absolute and either image-base-relative or indirect-relative, similarly to how we discriminate between direct and indirect relative in other places on existing targets.
Now, going unconditionally absolute for data-to-code references would have costs for PIC. The immediate question is how much this matters. If PIC on Wasm is expected to just be used for things like dynamic plugins, then this seems very low priority. But if people expect Wasm to have a robust shared library system, then we need to treat PIC as seriously as we do on other targets.
If we want to maintain the benefits of relative references in PIC while using absolute references in non-PIC, we'll need to dynamically distinguish absolute from relative references. The easiest way to do this is to use a bit in the reference, but as discussed, we may not be able to do that without constraining the range of references (unless it's already constrained by the instruction format). Otherwise, we'll have to go one-by-one through all the places that currently store data-to-code relative references and see if they have an external bit we could use to distinguish these cases. I suspect a lot of them do.
If we're going to embrace absolute data-to-code references from metadata, it also matters a lot whether Wasm64 ends up adopting 64-bit code pointers. (That really does seem extremely high given their representation, but if it's what the project decides, it's what they decide.) We might end up wanting a "code model" sort of thing where we usually emit 32-bit references but have the ABI ability to fall back on 64-bit references (with some sort of indirection) if requested. Ideally, this would be integrated with the linker such that the linker could turn an indirect reference into a direct one when the pointer value is small enough. But we're not likely to get the level of cooperation we would need to do this in the linker if the discriminator is stored separately from the reference.