I think I’ve finally settled on the basics of an interpreter calling convention. It’s difficult as I don’t really know what I’ll need in the interpreter and it took a bit of thrashing around while I tried to figure out what to do with the stack, but here goes:

There are two non-volatile registers:

Rmethod is the address of the current methodOopRlocals is the address of first local variable

These are expected to be valid at all times within the interpreter.

In addition there are two volatile registers:

Rnparams is the number of parametersRnlocals is the number of local variables (including parameters)

These are only expected to be valid at interpreter entry points. They don’t even need to be in registers (you can read them from the methodOop) but a) they are already in registers in call_stub and b) both are needed in registers in the entry points, so as long as it’s no trouble to pass them like this I will continue to do so.

Such that the first local variable is accessed as 0(Rlocals), the second as wordSize(Rlocals), and so on. This only works if always know in advance how many local variables the method we are calling will need, which seems reasonable. If there are cases where this isn’t so I can insert a check in the method entry to resize the frame as necessary, but this is expected to be time-consuming so should be the exception rather than the rule.

Any additional stack slots will be allocated below the first local variable, such that the first additional stack slot will be referenced as -wordSize(Rlocals).

Monitors will be allocated below any additional stack slots. I may well always allocate some space for monitors depending on how frequently they are created, how many any given method is expected to require, and exactly how time-consuming a frame-resize is.

Ok, I think that’s it.

Posted by gbenson on Wednesday, September 19th, 2007, at 15:56, and filed under Uncategorized.