Compile function with limited set of registers? Jump to another function?

Hi,

Can anyone tell me, is it possible to express in LLVM IR:

  • that, for a specific function, register allocator can use only limited set of registers? (specifically, cannot touch any registers that might contain parameters)
  • that stack can’t be touched? (or at least must balance on exit from thunk)
  • jump, not call, to another function leaving any received parameters unchanged in registers and on stack?

Thanks,
– James Williams

Background:

I’m looking for some advice on implementing thunks required by my language’s interface call mechanism. This is a fairly conventional arrangement where method selectors in interfaces are hashed to determine their index within a vtable and hash collisions are disambiguated at runtime by a thunk, which determines which method to call from a selector id passed as the first method parameter.

I’m currently using a single thunk (written in assembly) for all collisions that walks a table to determine what method to call. This works but it’s inefficient and requires the a hand written thunk for each supported target.

I’d like to instead generate IR for a specific thunk for each vtable collisoin that does a binary search of possible selectors because this will avoid some pointer dereferences and an additional indirect call.

The problem is that a thunk may need to decide between methods with different signatures without disturbing parameters in registers and on the stack and then jump to, rather than call, another function:

interface X:
method A(a, b)

interface Y:
method B(c, d, e)

class Z implements X, y:
method A(a, b) …
method B(c, d, e) …

X.A + Y.B happen to hash to same vtable index, say -3

This would require a thunk something like:

vtable[-3] =
thunk_Z_AorB(selector_id, …)
// binary search for matching selector id:
if selector_id <= selector_Z_A then
Z.A(selector_id, …)
else
Z.B(selector_id, …)
fi

which would ideally would compile on x64 to something like:

thunk_Z_AorB:
cmp $selector_Z_A, %rdi
jle Z.A
jmp Z.B

Hi James,

I see the problem now. You might look at VMKit (a Java VM build with the LLVM JIT compiler) - I would expect it uses a similar method for resolving interface calls (the method, if I understand it correctly, is well-known in the Java world).

I’ve CC’d the main dev behind VMKit - he might be able to lend some insight.

–Joshua

Thanks, that’s a good idea - I’ll have a look through the VMKit source.

– James

Forgot to cc the list.

Hi James,

Joshua is right, what you’re trying to accomplish is quite known in the Java VM world (http://domino.research.ibm.com/comm/research_people.nsf/pages/dgrove.oopsla01.html).

In order to express the “thunk” code in LLVM you need a full control of how registers are used (because otherwise they would mess up with the arguments). I haven’t investigated enough to know if that’s possible today in LLVM (I think it wasn’t a few years ago when I added the optimization). So what I ended up with was a generic IR that walks the interface table of an object and detects collisions. The IR was inline in the caller to make sure that arguments in registers are not overriden.

This may not be the best approach today, but I believe it was the easiest way to have something efficient at that point.

Cheers,
Nicolas

Hi Sam,

Thanks for this + sorry for not replying earlier.

I’m afraid I’m not sure I’ve understood your advice. I have a working implementation for interfaces with inheritance - I use constant negative indexes into class vtables for class methods that implement methods in interfaces. These indexes are allocated at compile time either via graph coloring (if whole program is compiled as a unit) or by hashing method signatures (if parts of program are compiled separately). Any collisions arising from the hashing method are resolved on method call by thunks in any vtable slots hashed to by more than one selector.

Advantages of this mechanism are it’s as fast as regular virtual method dispatch (except in the method signature hash collision case) and that there is no difference between calls through objects and calls through interfaces (in fact there are no interfaces as such at runtime, only references to regular objects)

What I’m looking to do is speed up the thunk that’s called when two or more interface method signatures hash to the same slot in the vtable. Currently it just does a linear search over a compile time generated table of selector ids->method address. I think common improvements are using a self ordering list or using a binary search.

My conclusion is that I could probably use LLVM to generate a thunk to resolve each vtable collision to do a binary search over the expected method signatures, providing I use varargs calling convention. I’ll need to do some profiling to determine if this is worthwhile, given the overhead of adding an additional parameter to both all calls to methods interfaces and methods in classes that implement methods in interfaces.

– James.

Hi Nicholas,

Yes - that’s exactly the paper got the idea from!

I suspect it’s still not possible to do this in LLVM IR (without using varargs, which adds some overhead).

However, it may be possible to use the new machine code stuff although I’d obviously need to recode the binary search generation for each supported target.

– James