This is the mail archive of the java@gcc.gnu.org mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Why does GCJ generate so many explicit checks for null pointers?


Tom Tromey wrote:

"David" == David Daney <ddaney@avtrex.com> writes:



David> I am running gcj 3.3 on a i386-linux platform.


How did you configure?

David> I have noticed that in the code the GCJ generates, most (if not
David> all) places that a reference (or is that a pointer) is
David> dereferenced, an explicit check for null is done.

This doesn't happen for me.  Do you have sample code that shows the
problem?  The smaller the better.

Right now I think the only time we generate an explicit check is when
calling a final method.  In this case we must check to see if the
object is null, since we won't get a SEGV if it is.

David> Am I missing something here?

I'm guessing some kind of configuration problem.

Tom

You are right. It seems that the explicit null pointer checks ARE only done for final methods. I should have investigated further.

So now for some general observations WRT code generation for string concatenation and final methods and generation of NullPointerExceptions.

Idea #1:
Move the null pointer check to the final method.

Many final methods may dereference their 'this' pointer as their first action. In this case nothing has to be done as the SEGV generated NPE happens before any possible side effects of the method call. In cases where you would not SEGV before the call generated any side effects you would have to do an explicit check.

There would be savings in the calling code as you could eliminate the explicit checks there. The question is: Would the savings in the calling code be more than offset by checks needed in the called code? I don't know. The overall code size would probably be smaller, but the number of times the test is run could be much greater (especially where optimization is used).

Idea #2:
Fix string concatenation. It should never be necessary to do checks for null pointers in string concatenation.


In the code below it looks like ("Length of \"" + s + "\" is: " + l) is translated into roughly:

gnu.gcj.runtime.StringBuffer t = new gnu.gcj.runtime.StringBuffer("Length of \"");
t.append(s).append("\" is: ").append(l);


With checks for null done before the constructor call as well as before all the append calls.

Why check before the constructor call? Is it ever possible for _Jv_AllocObjectNoFinalizer to return null?

Why not just do:
t.append(s);
t.append("\" is: ");
t.append(l);

with no null pointer checks?

I don't have quite enough ambition to try to change this myself, but I feel better having gotten it off my chest.

David Daney.

Here is my test program:

public class Hello1
{
   public void doNPE(String s)
   {
       int l = s.length();
       System.out.println("Length of \"" + s + "\" is: " + l);
   }
}

This was compiled with "stock" gcc 3.3 configured as --host=i686-pc-linux-gnu using this command:
gcj -S -O2 Hello1.java


The resulting .s file is :

.file "Hello1.java"
.text
.align 2
.p2align 4,,15
.globl _ZN6Hello15doNPEEPN4java4lang6StringE
.type _ZN6Hello15doNPEEPN4java4lang6StringE, @function
_ZN6Hello15doNPEEPN4java4lang6StringE:
.LFB2:
pushl %ebp
.LCFI0:
movl %esp, %ebp
.LCFI1:
pushl %edi
.LCFI2:
pushl %esi
.LCFI3:
pushl %ebx
.LCFI4:
subl $12, %esp
.LCFI5:
movl 12(%ebp), %esi
cmpb $13, _ZN4java4lang6System6class$E+74
setg %bl
testl %esi, %esi
je .L14
movl %esi, (%esp)
call _ZN4java4lang6String6lengthEv
movl %eax, -16(%ebp)
testb %bl, %bl
je .L15
.L5:
movl $12, 4(%esp)
movl _ZN4java4lang6System3outE, %edi
movl $_ZN3gnu3gcj7runtime12StringBuffer6class$E, (%esp)
call _Jv_AllocObjectNoFinalizer
movl %eax, %ebx
movl _CD_Hello1+4, %eax
movl %ebx, (%esp)
movl %eax, 4(%esp)
call _ZN3gnu3gcj7runtime12StringBufferC1EPN4java4lang6StringE
testl %ebx, %ebx
je .L14
movl %esi, 4(%esp)
movl %ebx, (%esp)
call _ZN3gnu3gcj7runtime12StringBuffer6appendEPN4java4lang6StringE
testl %eax, %eax
movl %eax, %edx
je .L14
movl %edx, (%esp)
movl _CD_Hello1+8, %eax
movl %eax, 4(%esp)
call _ZN3gnu3gcj7runtime12StringBuffer6appendEPN4java4lang6StringE
testl %eax, %eax
je .L14
movl %eax, (%esp)
movl -16(%ebp), %edx
movl %edx, 4(%esp)
call _ZN3gnu3gcj7runtime12StringBuffer6appendEi
testl %eax, %eax
je .L14
movl %eax, (%esp)
call _ZN3gnu3gcj7runtime12StringBuffer8toStringEv
movl (%edi), %edx
movl %edi, (%esp)
movl %eax, 4(%esp)
call *116(%edx)
addl $12, %esp
popl %ebx
popl %esi
popl %edi
popl %ebp
ret
.p2align 4,,7
.L15:
movl $_ZN4java4lang6System6class$E, (%esp)
call _Jv_InitClass
jmp .L5
.L14:
call _Jv_ThrowNullPointerException
.LFE2:
.size _ZN6Hello15doNPEEPN4java4lang6StringE, .-_ZN6Hello15doNPEEPN4java4lang6StringE
.align 2
.p2align 4,,15
.globl _ZN6Hello1C1Ev
.type _ZN6Hello1C1Ev, @function
_ZN6Hello1C1Ev:
.LFB3:
pushl %ebp
.LCFI6:
movl %esp, %ebp
.LCFI7:
popl %ebp
jmp _ZN4java4lang6ObjectC1Ev
.LFE3:
.size _ZN6Hello1C1Ev, .-_ZN6Hello1C1Ev
.section .rodata
.align 2
.type _Utf1, @object
.size _Utf1, 4
_Utf1:
.value 53848
.value 5
.ascii "doNPE"
.zero 1
.align 2
.type _Utf2, @object
.size _Utf2, 4
_Utf2:
.value 54943
.value 21
.ascii "(Ljava.lang.String;)V"
.zero 1
.align 2
.type _Utf3, @object
.size _Utf3, 4
_Utf3:
.value 626
.value 6
.ascii "<init>"
.zero 1
.align 2
.type _Utf4, @object
.size _Utf4, 4
_Utf4:
.value 39797
.value 3
.ascii "()V"
.zero 1
.data
.align 32
.type _MT_Hello1, @object
.size _MT_Hello1, 40
_MT_Hello1:
.long _Utf1
.long _Utf2
.value 16385
.value 5
.long _ZN6Hello15doNPEEPN4java4lang6StringE
.long 0
.long _Utf3
.long _Utf4
.value 16385
.value -1
.long _ZN6Hello1C1Ev
.long 0
.globl _ZTVN6Hello1E
.align 32
.type _ZTVN6Hello1E, @object
.size _ZTVN6Hello1E, 40
_ZTVN6Hello1E:
.long 0
.long 0
.long _ZN6Hello16class$E
.long 4
.long _ZN4java4lang6Object8finalizeEv
.long _ZN4java4lang6Object8hashCodeEv
.long _ZN4java4lang6Object6equalsEPS1_
.long _ZN4java4lang6Object8toStringEv
.long _ZN4java4lang6Object5cloneEv
.long _ZN6Hello15doNPEEPN4java4lang6StringE
.section .rodata
.align 2
.type _Utf5, @object
.size _Utf5, 4
_Utf5:
.value 9998
.value 6
.ascii "\" is: "
.zero 1
.align 2
.type _Utf6, @object
.size _Utf6, 4
_Utf6:
.value 13555
.value 11
.ascii "Length of \""
.zero 1
.data
.align 4
.type _CD_Hello1, @object
.size _CD_Hello1, 12
_CD_Hello1:
.long 0
.long _Utf6
.long _Utf5
.type _CT_Hello1, @object
.size _CT_Hello1, 3
_CT_Hello1:
.byte 0
.byte 8
.byte 8
.section .rodata
.align 2
.type _Utf7, @object
.size _Utf7, 4
_Utf7:
.value 60863
.value 6
.ascii "Hello1"
.zero 1
.globl _ZN6Hello16class$E
.data
.align 32
.type _ZN6Hello16class$E, @object
.size _ZN6Hello16class$E, 104
_ZN6Hello16class$E:
.long _ZTVN4java4lang5ClassE+8
.long 0
.long _Utf7
.value 1
.zero 2
.long _ZN4java4lang6Object6class$E
.long 3
.long _CT_Hello1
.long _CD_Hello1
.long _MT_Hello1
.value 2
.value 6
.long 0
.long 4
.value 0
.value 0
.long _ZTVN6Hello1E+8
.long 0
.long 0
.long 0
.long 0
.value 0
.byte 0
.zero 1
.long 0
.value 0
.zero 2
.long 0
.long 0
.long 0
.long 0
.long 0
.section .jcr,"aw",@progbits
.align 4
.long _ZN6Hello16class$E
.section .eh_frame,"a",@progbits
.Lframe1:
.long .LECIE1-.LSCIE1
.LSCIE1:
.long 0x0
.byte 0x1
.string "zP"
.uleb128 0x1
.sleb128 -4
.byte 0x8
.uleb128 0x5
.byte 0x0
.long __gcj_personality_v0
.byte 0xc
.uleb128 0x4
.uleb128 0x4
.byte 0x88
.uleb128 0x1
.align 4
.LECIE1:
.LSFDE1:
.long .LEFDE1-.LASFDE1
.LASFDE1:
.long .LASFDE1-.Lframe1
.long .LFB2
.long .LFE2-.LFB2
.uleb128 0x0
.byte 0x4
.long .LCFI0-.LFB2
.byte 0xe
.uleb128 0x8
.byte 0x85
.uleb128 0x2
.byte 0x4
.long .LCFI1-.LCFI0
.byte 0xd
.uleb128 0x5
.byte 0x4
.long .LCFI5-.LCFI1
.byte 0x83
.uleb128 0x5
.byte 0x86
.uleb128 0x4
.byte 0x87
.uleb128 0x3
.align 4
.LEFDE1:
.LSFDE3:
.long .LEFDE3-.LASFDE3
.LASFDE3:
.long .LASFDE3-.Lframe1
.long .LFB3
.long .LFE3-.LFB3
.uleb128 0x0
.byte 0x4
.long .LCFI6-.LFB3
.byte 0xe
.uleb128 0x8
.byte 0x85
.uleb128 0x2
.byte 0x4
.long .LCFI7-.LCFI6
.byte 0xd
.uleb128 0x5
.align 4
.LEFDE3:
.ident "GCC: (GNU) 3.3"





Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]