This is quite an interesting idea about dynamic recompiling and caching of method lookups. And it smells like more MOPS and generally just a faster Parrot VM. So I've hacked together an initial version for testing, only MMD lookups currently.
PMC MOPS (examples/benchmarks/mops.pasm)
parrot -C CVS 13.6 parrot -j 13.4 parrot -C PIC 16.7
This is a 22% speedup for MOPS and very likely more for method lookups. With JIT_CGP the JIT core could also use this optimization. (Numbers with -O3 build, AMD 800)
Below is a (very) preliminary pod generated from src/pic.c.
Before spending more time on that, I'd like to hear some comments about possible hidden drawbacks or whatever. I can provide a patch too.
Thanks, leo
[1] http://citeseer.ist.psu.edu/hlzle91optimizing.html
PIC.C(1) User Contributed Perl Documentation PIC.C(1)
NNNNAAAAMMMMEEEE
src/pic.c - Polymorphic Inline Cache
DDDDEEEESSSSCCCCRRRRIIIIPPPPTTTTIIIIOOOONNNN
The PIC supports inline caching for MMD and object method
lookups in the CGP (direct threaded run core).
� During predereferencing the bytecode,
Parrot_PIC_prederef() is called. If it's a MMD
function, the prederefed code pointer is replaced with
a stub that caches MMD lookups. For callmethod opcodes
another stub is created that caches classes or does a
method lookup.
� This stub inside pic_cgp_core checks the PMC types. If
a match with the cache is found the MMD function is
called directly. If no match is found the MMD
function is looked up, and function pointer and types
are stored in the cache.
� For objects, the cache holds entries per
class/method_name.
TODO
- create a circular LRU buffer for a few types.
- cache all MMD functions
- cache method lookups
- provide an API to invalidate the cache per class or all.
FFFFuuuunnnnccccttttiiiioooonnnnssss
static opcode_t *pic_cgp_core(opcode_t *cur_op, Interp*)
This has the same signature and usage as the cgp_core.
Actually this function is just used to return the
address of the CGoto jump table. The code is executed
by just jumping inside the labels (from and to the CGP
core).
static void pic_create_mmd(Interp *, opcode_t *pc, void
**pc_pred, INTVAL func_nr)
Create a PIC structure for the given MMD func_nr. The
*pc is the plain bytecode pointer, pc_pred points into
the prederefed code.
The first argument of the opcode gets the pic
structure, which has as slot first_arg, where this
argument is preserved. A typical opcode with a PIC
looks like:
[opcode] [pic] [left] [right]
20/Nov/2004 perl 5.008 1
PIC.C(1) User Contributed Perl Documentation PIC.C(1)
The [dest] argument is in the PIC struture.
void Parrot_PIC_prederef(Interp *, opcode_t *pc, void
**pc_pred)
Define either the normal prederef function or the PIC
stub, if PIC for this opcode function is available.
Called from do_prederef.
AAAAUUUUTTTTHHHHOOOORRRR
Leopold Toetsch with many hints from Ken Fox.
SSSSEEEEEEEE AAAALLLLSSSSOOOO
_s_r_c_/_m_m_d_._c, _s_r_c_/_o_b_j_e_c_t_._c,
_s_r_c_/_i_n_t_e_r_p_r_e_t_e_r_._c,
_o_p_s_/_c_o_r_e___o_p_s___c_g_p_._c
20/Nov/2004 perl 5.008 2
