I have an variant of the proposal.
- A
subroutine
may only start at PCs divisable by 32:0
,32
, 64` etc. - The
BEGINSUB
, if executed at some other position, causes error. - If a
BEGINSUB
is atPC % 32 == 0
, then we say that a newsubroutine
starts there.
With these changes, the following effects happen:
- We keep the old
code/data
bitmap. Sizecodelen / 8
. (A
) - We create one more bitmap during jumpdest-analysis. Bit
0
representsPC=0
, bit1
representsPC=32
. If a new subroutine starts there, we place a1
in the bitmap. (B
). Size ofB
iscodelen/ 32 /8
Now, whenever we need to check if a JUMP
is valid, we do
- Check
A
as before, - Check
LOC is JUMPDEST
as before, - Seek through
B
fromPC
toLOC
. This seek operation effectively covers 32 bytes per check. On a64
-bit platform, large large jumps can be checked with 64 bits at a time, effectively covering32*64
bytes of code per check. A jump across1MB
gigantic subroutine can be performed with~490
checks.
This means that compilers will have to be smart about allocating the subroutines, and use some padding here and there, and maybe inline small stuff instead of subroutining it.
For code merklization, that might be a good thing too, since it puts a floor on the size of a code chunk.
Furthermore:
- this decreases the chance of causing backward compatibility problems: any non-32
BEGINSUB
op is still ājust an invalid opcodeā, and the only case that would cause problems would be- A jump across a data-section, where a
BEGINSUB
is atPC %32 ==0
.
- A jump across a data-section, where a
PS: The choice of 32
is pretty arbitrary.