Function pointers ================= Should we have them? - Makes it possible to have a "custom" option for class structs (e.g. custom List, custom Allocator, etc.) Downsides: - Code cannot be replaced, because addresses are now "locked". Possible workarounds: - Relative function pointers make the code moveable as a unit, but individual code areas cannot move (or change layout) - Could use fat pointers, with e.g: -- Code "area" ID and function ID -- This may be able to fit in a pointer! type FunctionPointer = struct ( ushort code_area ushort func_id ) - Or we just use a function ID? With a per-"area" lookup table. - (We cannot just have a area-local function ID, because the function pointer could be passed to other modules) - We could also register function pointers, so we can update them when the code is moved or updated. - We could also register the *function itself* and get a handle. The registration could happen automatically at load time. -- Handles need to be process-global (or system global in a unikernel). -- Getting the handle (from the function pointer) requires indirection. How to do this with position independent code? Perhaps pass in a relative offset and then, inside the "get handle" function, look at the return address. -- Calling the function requires indirection. How to do this without having a race condition? -- BUT we could generate code for the "call" function at load time, so it becomes basically a switch-case of IDs with calls to the functions. --- Because the size of the function can change, the function needs to use a jump "trampoline" to jump to the current function body. --- This way we will never do a jump to an address (except from function returns). --- Also, this way we can compare function pointers. => have function pointers, but allow the implementation to transform them to something else.