PIC details

Previous Topic Next Topic
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view

PIC details

Bryce Kampjes
Jecel Assumpcao Jr writes:
 > I am interested in the various efforts to add Polymorphic Inline Caches
 > to Squeak, like in
 > > slides - http://www.iam.unibe.ch/~denker/talks/07ICOOLPS/07PICsICOOOLPS.pdf
 > > paper - http://www.hirschfeld.org/misc/media/HauptHirschfeldDenker_2007_TypeFeedbackForBytecodeInterpreters.pdf
 > For this design they just replace the pointer to the symbol in the
 > method's literal frame with a pointer to an object which then points to
 > that symbol and which also adds the needed information (class / compiled
 > method pairs).
 > I plan to browse the Exupery sources to see what its PICs are like, but
 > for now I just took a quick look at the various presentations that are
 > available and saw a thread on this list from October 2008. My impression
 > so far is that PICs are short code fragments with pointers to classes
 > and which are treated mostly like native methods.
 > If there are more details anywhere, it would be very helpful.
 > -- Jecel

Exupery's PICs are still very simple. They are a short sequence of
null instructions that are replaced with cmp reg class, je newMethod
sequences. The PICs are made of two parts a control block with a
little data describing the PIC and a single slot to record any
interpreted classes. The profiler doesn't see primitives so the
PIC records interpreted receivers so primitives from interpreted
methods can be inlined.

The PICs are only used for classes in old space. On a full GC they
are all cleared and set back to all NULLs.

The image can inspect them to see what classes they've seen. The only
information stored is that the class has been seen. The PICs currently
have room for three receivers, if they're full they overwrite the
oldest entry.

The code to populate the PIC is in exuperyPopulatePic:with:receiver:
which is called by exuperySetup:Message:Send:

Here's the send code sequence:

(block 6
 (mov (address block240) (8 ecx))
 (mov 7 (12 ecx))
 (mov eax (32 ecx))
 (mov ebx (36 ecx))
 (bitTest 0 eax)
 (jnc block241)
 (mov #(#specialObjectsOop) eax)
 (mov (24 eax) eax)

 (mov (picEntry -1313050144) ecx)
 (add 64 esp)
 (pop edi)
 (pop esi)
 (pop ebx)
 (mov ebp esp)
 (pop ebp)
 (pic eax)
 (push ecx)
 (mov 1 eax)
 (push eax)
 (push edx)
 (mov #exuperySetup:Message:Send: eax)
 (call eax)
 (mov esp ebx)
 (add 12 ebx)
 (mov ebx esp)
 (cmp 0 eax)
 (jz block239)
 (jmp eax)

 (mov 1 eax)
 (ret eax)

 (mov (eax) ebx)
 (sar 12 ebx)
 (and 31 ebx)
 (mov 0 ecx)
 (cmp ebx ecx)
 (je block242)
 (mov #(#specialObjectsOop) eax)
 (sub 1 ebx)
 (sal 2 ebx)
 (mov 4 ecx)
 (add ebx ecx)
 (add (116 eax) ecx)
 (mov (ecx) eax)
 (jmp block243)

 (sub 4 eax)
 (mov (eax) eax)
 (and 4294967292 eax)
 (jmp block243)

In block 6 first the return address is saved into the context (stored
in ecx here). Then the stack height is saved, it's tracked at compile
time, then the arguments including the receiver are saved. Finally we
check if the receiver is a SmallInteger, if it is then we load the
class SmallInteger from the special objects array.

Block 243 loads the picEntry, the control block for the PIC into ecx
so that we can store it and the receiver if we fall through the PIC.
It then pops out of the C stack enters the PIC, if the PIC falls
through then it re-establishes the C stack frame, calls
exuperySetup:Message:Send: which looks up the method using the same
logic as the interpreter including using the interpreters message
cache. The rest of the block and block 239 either returns to native
code via "jmp eax" or returns back into the interpreter.

Blocks 241 and 242 are decoding the receivers class. Block 241 is
required because of compact classes.

The PIC entries look like:
  (cmp eax classAddress)
  (je newMethod)

Yes there's more than a few inefficiences here that could be removed
with a bit of tuning.

Exupery mailing list
[hidden email]