Java Solaris Communities Sun Store Join SDN My Profile Why Join?
 
Bug Database
Bug Detail
Quick Lists
Top 25 Bugs
Top 25 RFE's
Recently Closed Bugs
Printable Page Printable Page


Bug Database
Bug ID: 4364685
Votes 0
Synopsis JIT confused parameter's type after inlining
Category java:runtime
Reported Against 1.2.2_005
Release Fixed 1.2.2_11
State 10-Fix Delivered, bug
Priority: 4-Low
Related Bugs
Submit Date 22-AUG-2000
Description
Problem
-------
When calling a method with with a certain number/type of parameters, the JIT can confuse the  customer 's type ('Class').
This occurs while trying to inline the method.  Disabling the JIT or simply preventing this method from being inlined removes the problem.
The problem does not occur with Java2 SDK 1.3.
This corruption can be seen by using either "parm.getClass()" or "instanceof".
The test-case supplied shows the parameter changing from a byte[] to another user defined class.  It will reproduce with byte[] changed to java.lang.Object implying not array specific.
Removing any of the method parameters will remove the problem as will removing seemingly irrelevant code sections.


Code Example
------------
import java.util.Vector;

public class JIT2 {
    public static void main(String [] args) {
        InstructionToDebit mj = new InstructionToDebit();

        for (int i=0;i<6;i++) {
            mj.processMessage();
        }
    }
}

class InstructionToDebit {
    long        myLong;

    Object      o1, o2, o3, o4;

    byte[]      tknListHash;
    TokenList   trCopyTokens;

    InstructionToDebit() {
        tknListHash           = new byte[16];
    }

    void processMessage() {
        Object v;

        try {
            trCopyTokens = null;
            trCopyTokens = new TokenList();

            System.err.println("RUNNING MESSAGE");
            System.err.println("BEFORE> " + tknListHash.getClass());

            sendCheckAuthorisation(tknListHash,
                    myLong,
                    myLong,
                    o1,
                    o2,
                    o3,
                    o4,
                    trCopyTokens.getTrustThreshold());

            System.err.println("AFTER> " + tknListHash.getClass());
            System.err.println("RUNNING MESSAGE .. done");

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    void sendCheckAuthorisation(byte[]         bob,
            long           l1,
            long           l2,
            Object         o1,
            Object         o2,
            Object         o3,
            Object         o4,
            short          trustThreshold) {

        Object ob = (Object) bob;
        if (ob instanceof byte[]) {
            System.err.println("************ NO ERROR ***************");
            System.err.println("DURING> " + ob.getClass());
            System.err.println("************ NO ERROR ***************");
        } else {
            System.err.println("************ ERROR ***************");
            System.err.println("DURING> " + ob.getClass());
            System.err.println("************ ERROR ***************");

        }
    }
}

class TokenList {
    Vector tknList= new Vector();

    TokenList() {
        TokenWrapper trTkn= new TokenWrapper();
        tknList.add(trTkn);
    }

    TokenWrapper get() {
        Object y = new Object();

        return (TokenWrapper) tknList.get(0);
    }

    short getTrustThreshold() {
        TokenWrapper tkn = get();
        return(tkn.getTrustThreshold());
    }
}

class TokenWrapper {
    TokenRec tkn = null;

    TokenWrapper() {
        tkn = new TokenRec();
    }

    short getTrustThreshold() {
        return tkn.getTrustThreshold();
    }
}

class TokenRec {
    short  trustThreshold = 0;

    TokenRec () {
    }

    short getTrustThreshold () {
        return trustThreshold;
    }
}


To Reproduce
------------
Compile and run with 1.2 JDK (tested with 1.2.2_05a).

Error output is:
===
	  xxxxx@xxxxx   (/share/calls/36057806/Test/Mods): java JIT2
	RUNNING MESSAGE
	BEFORE> class [B
	************ NO ERROR ***************
	DURING> class [B
	************ NO ERROR ***************
	AFTER> class [B
	RUNNING MESSAGE .. done
	RUNNING MESSAGE
	BEFORE> class [B
	************ NO ERROR ***************
	DURING> class [B
	************ NO ERROR ***************
	AFTER> class [B
	RUNNING MESSAGE .. done
	RUNNING MESSAGE
	BEFORE> class [B
	************ NO ERROR ***************
	DURING> class [B
	************ NO ERROR ***************
	AFTER> class [B
	RUNNING MESSAGE .. done
	RUNNING MESSAGE
	BEFORE> class [B
	************ NO ERROR ***************
	DURING> class [B
	************ NO ERROR ***************
	AFTER> class [B
	RUNNING MESSAGE .. done
	RUNNING MESSAGE
	BEFORE> class [B
	************ ERROR ***************
	DURING> class TokenRec
	************ ERROR ***************
	AFTER> class [B
	RUNNING MESSAGE .. done
	RUNNING MESSAGE
	BEFORE> class [B
	************ ERROR ***************
	DURING> class TokenRec
	************ ERROR ***************
	AFTER> class [B
	RUNNING MESSAGE .. done
===

Problem not happening when no "* ERROR *" lines appear (only "* NO ERROR *").


Other Related Information
-------------------------
Original code had access modifiers - removed these - no change.
Tried changing names of "getTrustThreshold" to different name per class - no change.
Tried removing other code that should be irrelevant - error vanishes.
Changed other classes that seem to be space fillers (eg. Non-referenced "Vector v" that needs to be present) to java.lang.Object to prove irrelevance.

Work Around
The problem will not be seen when run with any of the following:
    -Djava.compiler=none
    export _JVM_ARGS="inline_instrs_jit=0"
    export _JIT_ARGS="novinline"
    export _JIT_ARGS="exclude(InstructionToDebit)"
    export _JIT_ARGS="exclude(InstructionToDebit.processMessage)"


Additionally either add a dummy arg to the inlined method
method invocation or remove it from the invocation :

  338 % diff JIT2.java tt2/
26a27
>       short myShort;
34a36
>           myShort = trCopyTokens.getTrustThreshold();
42c44
<                     trCopyTokens.getTrustThreshold());
---
>                     myShort);

  xxxxx@xxxxx   2001-03-20
Evaluation
The following is the problem. If you either add another
arg or move the trCopyTokens.getTrustThreshold() invocation
out of the sendCheckAuthorisation invocation, the bug dissappears.

Initially we use a temp (l3 below) as the pointer to byte array tknListHash.
then the JIT inlines the trCopyTokens.getTrustThreshold etal recursively.
In the process we spill a register (l3) and the value is overwritten.
However when we return to the 1st level of the JITPass2 code,
we have popped the stack back to the point where the code indicates
that the temp reg is still valid. So we pass the wrong data into
sendCheckAuthorisation.

        at InstructionToDebit.sendCheckAuthorisation(JIT2t.java:72)
        at InstructionToDebit.processMessage(Compiled Code)
        at JIT2.main(Compiled Code)

    36
    37              sendCheckAuthorisation(myInt, tknListHash,
    38                      myLong,
    39                      myLong,
    40                      o1,
    41                      o2,
    42                      o3,
    43                      o4,
>>> 44                      trCopyTokens.getTrustThreshold());
    45


   102      short getTrustThreshold() {
   103          TokenWrapper tkn = get();
   104          return(tkn.getTrustThreshold());
   105      }
   106  }


   111      TokenWrapper() {
   112          tkn = new TokenRec();
   113      }

================================================================
---
< (fa03fd90) (e6062020) lduw    [%i0 + 32], _%l3_
    sets l3 as ptr for  54 getfield #33 <Field byte tknListHash[]>
(dbx6l) stopi at 0xfa03fd94

(dbx6l) x 0xfa03fd90/8i
dbx6l: warning: unknown language, 'ansic' assumed
0xfa03fd90:     ld      [%i0 + 0x20], %l3
0xfa03fd94:     ldx     [%i0 + 0x8], %g2
0xfa03fd98:     srlx    %g2, 32, %l5
0xfa03fd9c:     or      %g2, %g0, %l7
0xfa03fda0:     ldx     [%i0 + 0x8], %g2
0xfa03fda4:     srlx    %g2, 32, %i4
0xfa03fda8:     or      %g2, %g0, %i5
0xfa03fdac:     ld      [%i0 + 0x10], %l1
(dbx6l) print -f"%08x" $l3
$l3 = fb43d3d0
(dbx6l) x ($l3)/X
0xfb43d3d0:      0x00111800


< (fa03fe10) (80a04003) subcc   %g1, %g3, %g0
< (fa03fe14) (32400016) bne,a,pn%icc,fa03fe6c

< (fa03fe18) (e627bfc0) stw     _%l3_, [%fp - 64]
This is generated by spillParticularIntFromStack/stackUndo during inline of TokenWrapper.getTrustThreshold:
< (fa03fe1c) (e627bfc0) stw     _%l3_, [%fp - 64]
< (fa03fe20) (e606e008) lduw    [%i3 + 8], _%l3_
< (fa03fe24) (c404e000) lduw    [ _%l3_ + 0], %g2
< (fa03fe28) (90100013) or      %g0, _%l3_, %o0

BLAMO We have destroyed the value in l3...

  xxxxx@xxxxx   (  xxxxx@xxxxx  ) stopped in (unknown) at 0xfa03fe2c
0xfa03fe2c:     ld      [%g2 + 0x68], %g3
(dbx6l) print -f"%08x" $l3  
$l3 = fb440fd0
(dbx6l) print -f"%08x" *(int *)$l3
*((int *) $l3) = 002d2000
(dbx6l) x ($fp - 64)/X
0xffbee028:      0xfb43d3d0
(dbx6l) print -f"%08x" *(int *)($fp - 64)
*((int *) ($fp-64)) = fb43d3d0
(dbx6l) print -f"%08x" *(int *)(*(int *)($fp - 64))
*((int *) *((int *) ($fp-64))) = 00111800 <Field byte tknListHash[]>

< (fa03fe2c) (c600a068) lduw    [%g2 + 104], %g3
< (fa03fe30) ( 3000000) sethi   %hi(0x0), %g1
< (fa03fe34) (82006000) add     %g1, 0, %g1 
< (fa03fe38) (80a04003) subcc   %g1, %g3, %g0
< (fa03fe3c) (32400007) bne,a,pn%icc,fa03fe58
< (fa03fe40) (c600a068) lduw    [%g2 + 104], %g3
< (fa03fe44) (f627bfb0) stw     %i3, [%fp - 80]
< (fa03fe48) (f627bfb4) stw     %i3, [%fp - 76]

< (fa03fe4c) (f604e008) lduw    [ _%l3_  + 8], %i3

(dbx6l) print -f"%08x" $l3
$l3 = fb440fd0
< (fa03fe98) (c4062000) lduw    [%i0 + 0], %g2
< (fa03fe9c) (90100018) or      %g0, %i0, %o0
< (fa03fea0) (f623a06c) stw     %i3, [%sp + 108]
< (fa03fea4) (ec23a068) stw     %l6, [%sp + 104]
< (fa03fea8) (e823a064) stw     %l4, [%sp + 100]
< (fa03feac) (e423a060) stw     %l2, [%sp + 96]
< (fa03feb0) (e223a05c) stw     %l1, [%sp + 92]
< (fa03feb4) (9a174000) or      %i5, %g0, %o5
< (fa03feb8) (98170000) or      %i4, %g0, %o4
< (fa03febc) (9615c000) or      %l7, %g0, %o3
< (fa03fec0) (94154000) or      %l5, %g0, %o2
Here we load the pointer from the inline of 
trCopyTokens.getTrustThreshold as our arg
ptr for getfield #33 <Field byte tknListHash[]> ooops..

< (fa03fec4) (9214c000) or      _%l3_, %g0, %o1

And we're busted...

So why did we do it ?

  xxxxx@xxxxx   (  xxxxx@xxxxx  ) stopped in JITInlineMethodMb at line 8157 in file "JITPass2.c"
 8157           popUndo(&subjit, height);
                _________________________
(dbx6l) print (int)(jit)->m->currentSparcStack[1].reg 
(int ) jit->m->currentSparcStack[1].reg = -1
(dbx6l) next
  xxxxx@xxxxx   (  xxxxx@xxxxx  ) stopped in JITInlineMethodMb at line 8158 in file "JITPass2.c"
 8158           debugOnly(checkAndDestroySavedState(jit, *height, sav);)
(dbx6l) print (int)(jit)->m->currentSparcStack[1].reg 
(int ) jit->m->currentSparcStack[1].reg = 19

  xxxxx@xxxxx   (  xxxxx@xxxxx  ) stopped in stackUndo_work at line 724 in file "JIT_md.c"
  724       DynArrayOf_nm(StateUndoRec,addhi)(jit->mu->undoStack, ur);
stackUndo_work:
ur.tag = UNDO_STACK
ur.index = 1
ur.u.stk = {
    type           = 'A'
    is_constant    = '\0'
    constant_value = 0
    vn             = 80
    reg            = 19U
}
(dbx6l) where
current thread:   xxxxx@xxxxx  
=>[1] stackUndo_work(jit = 0xffbed1dc, n = 1), line 724 in "JIT_md.c"
  [2] stackUndo(jit = 0xffbed1dc, n = 1), line 60 in "JIT_undo.h"
  [3] spillParticularIntFromStack(jit = 0xffbed1dc, height = 10, reg = 19), line
 388 in "JITSparcGenerate.c"
  [4] spillSomeIntFromStack(jit = 0xffbed1dc, height = 10, low = 10), line 351 i
n "JITSparcGenerate.c"
  [5] getOutRegIntWork(jit = 0xffbed1dc, height = 10, low = 10, useORegs = FALSE
), line 703 in "JITSparcGenerate.c"
  [6] getOutRegInt(jit = 0xffbed1dc, height = 10, low = 10), line 559 in "JITSpa
rcGenerate.h"
  [7] emitPushField(jit = 0xffbed1dc, sig = 0x2c53e8 "LTokenRec;", base_reg = 27
U, offset = 8, ind_reg = 0, align = FALSE, vn1 = 97, vn2 = -1, height = 10, dreg
1 = -1, dreg2 = -1), line 6361 in "JITPass2.c"
  [8] emitGetField(jit = 0xffbed1dc, fieldIndex = 8U, height = 10, pc = 5, dreg1
 = -1, dreg2 = -1), line 6188 in "JITPass2.c"
  [9] JITSecondPass(jit = 0xffbed1dc, heightPtr = 0xffbed544), line 2578 in "JIT
Pass2.c"
  [10] JITCompile_md(jit = 0xffbed1dc, height = 0xffbed544), line 427 in "JIT_md
.c"
  [11] JITInlineMethodMb(jit = 0xffbed7d4, mb = 0x2d09e8, pc = 10, ck = CALL_VIR
TUAL, height = 0xffbed544, notUsed = (nil)), line 8137 in "JITPass2.c"
  [12] JITInlineMethodNdx(jit = 0xffbed7d4, methodIndex = 12U, pc = 10, ck = CAL
L_VIRTUAL, height = 0xffbed544), line 153 in "JITInlineRegion.c"
  [13] JITSecondPass(jit = 0xffbed7d4, heightPtr = 0xffbedb3c), line 2602 in "JI
TPass2.c"
  [14] JITCompile_md(jit = 0xffbed7d4, height = 0xffbedb3c), line 427 in "JIT_md
.c"
  [15] JITInlineMethodMb(jit = 0xffbede48, mb = 0x2c39a0, pc = 85, ck = CALL_VIR
TUAL, height = 0xffbedb3c, notUsed = (nil)), line 8137 in "JITPass2.c"
  [16] JITInlineMethodNdx(jit = 0xffbede48, methodIndex = 24U, pc = 85, ck = CAL
L_VIRTUAL, height = 0xffbedb3c), line 153 in "JITInlineRegion.c"
  [17] JITSecondPass(jit = 0xffbede48, heightPtr = 0xffbedc54), line 2602 in "JI
TPass2.c"
  [18] JITCompile_md(jit = 0xffbede48, height = 0xffbedc54), line 427 in "JIT_md
.c"
  [19] jitCompileMethod(mb = 0x2c0c08, jit = 0xffbede48), line 650 in "JIT.c"
  [20] compileMethodLocked(mb = 0x2c0c08, recompile = FALSE), line 2134 in "comp
iler.c"
  [21] compileOrStopCounting(mb = 0x2c0c08), line 153 in "classruntime.c"
  [22] incInvocationCountConsistent(ee = 0x38258, mb = 0x2c0c08), line 251 in "c
lassruntime.c"
  [23] incInvocationCountInconsistent(ee = 0x38258, mb = 0x2c0c08), line 260 in 
"classruntime.c"
  [24] countingInvoker(objectOrNull = 0xffbee240, mb = 0x2c0c08, ee = 0x38258), 
line 266 in "classruntime.c"
  [25] executeJava(initial_pc = 0xff23c9ac "\xb7", ee = 0x38258), line 1407 in "
executeJavaLoop.h"
  [26] runJavaMethod(ee = 0x38258, current_frame = 0x3860c, transition_mb = 0xff
bee3b0, terseRetType = 0x24df1 "\n"), line 1927 in "interpreter.c"
  [27] JITCallbackInterpreter(ee = 0x38258, mb = 0x2c0c08, args = 0xffbee568 "")
, line 1811 in "compiler.c"
  [28] JITInterpreterStub(0xfb43d3a8, 0x2c5c00, 0xfb8, 0xfec5a398, 0x0, 0x0), at
 0xfeec2264
  [29] 0xfa0390a0(0x4, 0xfb43d3a8, 0xfb8, 0xfec5a398, 0x0, 0x0), at 0xfa03909f
  [30] JITInvokeCompiledMethod(0x385f4, 0x2c3dc0, 0x38258, 0x11fdc0, 0xffbee698,
 0x0), at 0xff24d448
  [31] invokeCompiledMethod(objectOrNull = 0xffbee778, mb = 0x2c3dc0, ee = 0x382
58), line 474 in "classruntime.c"
  [32] executeJava(initial_pc = 0xff23c9a4 "\xb8", ee = 0x38258), line 1407 in "
executeJavaLoop.h"
  [33] runJavaMethod(ee = 0x38258, current_frame = 0x385e0, transition_mb = 0xff
bee920, terseRetType = 0xd180a "\n"), line 1927 in "interpreter.c"
  [34] jni_Invoke(env = 0x38560, self = 0x385d4, methodID = 0x2c3dc0, pushArgume
nts = 0xfeb79878 = &`libjvm_g.so`jni.c`jni_PushArgumentsVararg(JNIEnv *env, stru
ct Method *mb, struct javaframe *current_frame, JNI_PushArgsType a), args = UNIO
N, isStatic = 1, isVirtual = 0, isJVMCall = 0), line 744 in "jni.c"
  [35] jni_CallStaticVoidMethod(env = 0x38560, clazz = 0x385d4, methodID = 0x2c3
dc0, ...), line 1907 in "jni.c"
  [36] main(argc = 0, argv = 0xffbeebcc), line 300 in "java.c"
(dbx6l) 

  xxxxx@xxxxx   2001-03-20

After lots of digging the problem is that the alteration of register state 
in inner virtual inlined functions is not propagated to the outer state.
I tried various fixes that had repercussions, but Alex Garthwaite and 
Dave Detlefs provided a simple fix. Its in the suggested fix field.

  xxxxx@xxxxx   2001-11-01
Comments
  
  Include a link with my name & email   


PLEASE NOTE: JDK6 is formerly known as Project Mustang