I've been playing with an "uncommitted" op version of invoke that takes a method or sub by name like below:
invoke "foo", 0
The 0 is irrelevant to the eye, but it is a placeholder for the self-modifying instruction. Upon call, invoke by name does:
op invoke(STR, INT) PMC sub if($2 == 0) { sub = lookup $1 $2 = sub # store the ref in the immediate data of the instruction } else { sub = (PMC*)$2 } sub->vtable->invoke() }
Basically it is just caching the lookup into the immediate data portion of the bytecode instruction.
It isn't really anything new, this has been done before in VMs, but the problem becomes the PMC that is stored in the bytecode is unknown to the GC/DOD. Easy enough to fix, rather than store the PMC * itself, simply keep a method_cache[] that the DOD can traverse, and store only the array slot in the bytecode.
Maybe this is only syntactic sugar, I don't know.
The case is a win for loops that call the same method.
P0 = find_method "foo" # Lookup by name LOOP: invoke P0 if something goto LOOP
becomes:
LOOP invoke "foo" # Lookup by name only the 1st execution if something goto LOOP
There is no register usage for the method PMC.
Already, we are going to have a method_cache[] structure, so it follows that we could allow for this shortcut simply to hide the cache for some cases. This shortcut has the same challenges as the non-shortcut with notifiying/invalidating PMC method references, so the same solutions apply.
The other question is: does this little trick apply to other things that do lookups by name with constant strings?
-Melvin