[8u] RFR: fix java_calling_convention for longs
Anton Kozlov
akozlov at azul.com
Mon Mar 14 09:02:19 UTC 2016
Hi Ed,
Thanks for review! Regarding T_DOUBLE: I beleive that
fp_args = round_to(fp_args, 2); // (3rd line of inlined code)
will guard against descibed situation. If we came here with fp_args ==
15, then fp_args will be rounded first to 16 and then checked against
FP_ArgReg_N boundary.
Java calling convention for floating point arguments looks like integer
register arguments: adjacent single floats will occupy 2 single
registers
float, float, float -> f0, f1, f2
But if single float (placed to even single register) will be followed
by double float, then one single register will not be used
float, double, float -> f0, d1(f3:f2), f4 // f1 not used
Note, that C calling convention is different, it places third argument
to f1 in last example.
Thanks,
Anton
On Sun, 2016-03-13 at 15:07 +0000, Edward Nevill wrote:
> Hi Anton,
>
> Thanks for this. Your fix looks correct. Could you also check the
> code for T_DOUBLE a few lines later.
>
>
> case T_DOUBLE:
> assert(sig_bt[i + 1] == T_VOID, "expecting half");
> fp_args = round_to(fp_args, 2);
> if (fp_args < FP_ArgReg_N) {
> regs[i].set2(FP_ArgReg[fp_args]->as_VMReg());
> fp_args += 2;
> } else {
> regs[i].set2(VMRegImpl::stack2reg(stk_args));
> stk_args += 2;
> }
> break;
>
> Here it would seem then if fp_args was == 15 then it could end up
> using f15 and f16 which is invalid? It can only do this if there is a
> mixture of double and float arguments previously.
>
> Thanks,
> Ed.
>
>
> On Thu, 2016-03-10 at 17:59 +0000, Anton Kozlov wrote:
> > Current java calling convention have a bug: when last long argument
> > fitting to be passed on registers, high word could occupy register
> > outside of register set intended for argument passing. With java
> > c/c
> > argument on registers r1,r2,r3,r0: r4 may be used. Test case for
> > this
> > issue is not straightforward, because only few places uses r4
> > directly, so it's rarely destroyed. However, itable_stub is one of
> > them, so here is a test.
> >
> > === Test ===
> >
> > class Test {
> > public static final long goldValue = (0xdeadL << 32) |
> > 0xdead;
> >
> > public static void checkLong(long j3) {
> > System.out.printf("%s: got %x, should be %x\n", j3
> > ==
> > goldValue ? "OK" : "Fail", j3, goldValue);
> > }
> >
> > interface TestInterface {
> > public abstract void callee(int i1, long j3);
> > }
> >
> > class TestImpl1 implements TestInterface {
> > @Override
> > public void callee(int i1, long j3) {
> > checkLong(j3);
> > }
> > }
> >
> > class TestImpl2 implements TestInterface {
> > @Override
> > public void callee(int i1, long j3) {
> > checkLong(j3);
> > }
> > }
> >
> > class TestImpl3 implements TestInterface {
> > @Override
> > public void callee(int i1, long j3) {
> > checkLong(j3);
> > }
> > }
> >
> > public void vmain() {
> > TestInterface ifaces[] = { new TestImpl1(), new
> > TestImpl2(), new TestImpl3() };
> > TestInterface iface = null;
> > for (int i = 0; i < ifaces.length; ++i) {
> > iface = ifaces[i];
> > iface.callee(0, goldValue);
> > }
> > }
> >
> > public static void main(String[] args) {
> > Test test = new Test();
> > test.vmain();
> > }
> > }
> > === End of Test ===
> >
> > However, problem could be verified by hands easier. Calling
> > java_calling_convention for checkLong2 signature will allocate r1
> > for
> > i1, r2 for i2 and r4:r3 for j3; however, r0:r3 expected.
> >
> > === TestLongPass ===
> > class TestLongPass {
> > public static final long goldValue = (0x31414L << 32) |
> > 0x31415;
> >
> > public static void checkLong2(int i1, int i2, long j3) {
> > System.out.printf("%s: got %x, should be %x\n", j3
> > ==
> > goldValue ? "OK" : "Fail", j3, goldValue);
> > }
> >
> > public static void main(String[] args) {
> > checkLong2(0, 0, goldValue);
> > }
> > }
> > === End of TestLongPass
> >
> >
>
More information about the aarch32-port-dev
mailing list