Patch proposal: use __builtin_expect

Anthony Green green@cygnus.com
Sat Apr 22 08:36:00 GMT 2000


__builtin_expect is a new builtin function for providing hints to the
compiler.

Consider this (very!) frequently called function:

jint
_Jv_MonitorEnter (jobject obj)
{
#ifndef HANDLE_SEGV
  if (! obj)
    JvThrow (new java::lang::NullPointerException);
#endif
  if (INIT_NEEDED (obj))
    obj->sync_init ();
  _Jv_SyncInfo *si = (_Jv_SyncInfo *) obj->sync_info;
  return _Jv_MutexLock (&si->mutex);
}

For IA-32 targets, each `if' generates a test and a branch-if-false.
We know, however, that the conditions will be false the vast majority
of the time.

jint
_Jv_MonitorEnter (jobject obj)
{
#ifndef HANDLE_SEGV
  if (__builtin_expect (! obj, 0))
    JvThrow (new java::lang::NullPointerException);
#endif
  if (__builtin_expect (INIT_NEEDED (obj), 0))
    obj->sync_init ();
  _Jv_SyncInfo *si = (_Jv_SyncInfo *) obj->sync_info;
  return _Jv_MutexLock (&si->mutex);
}

These changes tell the compiler that we expect the tests to result in
0 most of the time.  It will reorder the basic blocks to generate
straight line code for the common case and the JvThrow() and
obj->sync_init() blocks are moved to the very end of the function.

(Of course, INIT_NEEDED needs to be expanded to take advantage of
__builtin_expect also.)

I have a simple question, and am not committing this patch yet.

I need to add a configure check to test for the existence of
__builtin_expect.  There doesn't appear to be a header file for
general private macros.  Where should I `#define __builtin_expect(A,B) (A)'
if it isn't supported?

(Another reason not to commit yet is that there's a bug in the new block
 reordering code when -g is used. I've reported this to gcc-bugs.)

Now that I think about it, we should modify the front end to take
advantage of block reordering when we generate array bounds and class
initialization tests.


2000-04-21  Anthony Green  <green@cygnus.com>

	* java/lang/natObject.cc (_Jv_MonitorEnter): Add __builtin_expect.
	(notify): Ditto.
	(notifyAll): Ditto.
	(wait): Ditto.
	(_Jv_MonitorExit): Ditto.
	* boehm.cc (_Jv_MarkObj): Ditto.
	(_Jv_MarkObj): Ditto.
	(_Jv_MarkArray): Ditto.
	(_Jv_AllocBytes): Ditto.
	* prims.cc (_Jv_AllocObject): Ditto.
	(_Jv_NewObjectArray): Ditto.
	(_Jv_NewPrimArray): Ditto.
	(_Jv_Malloc): Ditto.
	(_Jv_Realloc): Ditto.
	(_Jv_MallocUnchecked): Ditto.
	(_Jv_divI): Ditto.
	(_Jv_remI): Ditto.
	(_Jv_divJ): Ditto.
	(_Jv_remJ): Ditto.

Index: boehm.cc
===================================================================
RCS file: /cvs/java/libgcj/libjava/boehm.cc,v
retrieving revision 1.17
diff -c -r1.17 boehm.cc
*** boehm.cc	2000/04/19 10:10:39	1.17
--- boehm.cc	2000/04/22 15:04:39
***************
*** 8,13 ****
--- 8,17 ----
  Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
  details.  */
  
+ // FIXME: Remove this macro definition once __builtin_expect is known
+ // to work.
+ #define __builtin_expect(A,B) (A)
+ 
  #include <config.h>
  
  #include <stdio.h>
***************
*** 87,93 ****
    _Jv_VTable *dt = *(_Jv_VTable **) addr;
    // We check this in case a GC occurs before the vtbl is set.  FIXME:
    // should use allocation lock while initializing object.
!   if (! dt)
      return mark_stack_ptr;
    jclass klass = dt->clas;
  
--- 91,97 ----
    _Jv_VTable *dt = *(_Jv_VTable **) addr;
    // We check this in case a GC occurs before the vtbl is set.  FIXME:
    // should use allocation lock while initializing object.
!   if (__builtin_expect (! dt, 0))
      return mark_stack_ptr;
    jclass klass = dt->clas;
  
***************
*** 98,104 ****
    p = (ptr_t) klass;
    MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, obj, o2label);
  
!   if (klass == &ClassClass)
      {
        jclass c = (jclass) addr;
  
--- 102,108 ----
    p = (ptr_t) klass;
    MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, obj, o2label);
  
!   if (__builtin_expect (klass == &ClassClass, 0))
      {
        jclass c = (jclass) addr;
  
***************
*** 281,287 ****
    _Jv_VTable *dt = *(_Jv_VTable **) addr;
    // We check this in case a GC occurs before the vtbl is set.  FIXME:
    // should use allocation lock while initializing object.
!   if (! dt)
      return mark_stack_ptr;
    jclass klass = dt->clas;
  
--- 285,291 ----
    _Jv_VTable *dt = *(_Jv_VTable **) addr;
    // We check this in case a GC occurs before the vtbl is set.  FIXME:
    // should use allocation lock while initializing object.
!   if (__builtin_expect (! dt, 0))
      return mark_stack_ptr;
    jclass klass = dt->clas;
  
***************
*** 329,335 ****
    // guarantee that PTRFREE allocations are zeroed.  Note that we
    // don't have to do this for other allocation types because we set
    // the `ok_init' flag in the type descriptor.
!   if (r != NULL)
      memset (r, 0, size);
    return r;
  }
--- 333,339 ----
    // guarantee that PTRFREE allocations are zeroed.  Note that we
    // don't have to do this for other allocation types because we set
    // the `ok_init' flag in the type descriptor.
!   if (__builtin_expect (r != NULL, !NULL))
      memset (r, 0, size);
    return r;
  }
Index: prims.cc
===================================================================
RCS file: /cvs/java/libgcj/libjava/prims.cc,v
retrieving revision 1.25
diff -c -r1.25 prims.cc
*** prims.cc	2000/04/02 15:34:17	1.25
--- prims.cc	2000/04/22 15:04:39
***************
*** 8,13 ****
--- 8,17 ----
  Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
  details.  */
  
+ // FIXME: Remove this macro definition once __builtin_expect is known
+ // to work.
+ #define __builtin_expect(A,B) (A)
+ 
  #include <config.h>
  
  #ifdef USE_WIN32_SIGNALLING
***************
*** 322,328 ****
    _Jv_InitClass (c);
  
    jobject obj = (jobject) _Jv_AllocObj (size);
!   if (! obj)
      JvThrow (no_memory);
    *((_Jv_VTable **) obj) = c->vtable;
  
--- 326,332 ----
    _Jv_InitClass (c);
  
    jobject obj = (jobject) _Jv_AllocObj (size);
!   if (__builtin_expect (! obj, 0))
      JvThrow (no_memory);
    *((_Jv_VTable **) obj) = c->vtable;
  
***************
*** 339,345 ****
  #ifdef ENABLE_JVMPI
    // Service JVMPI request.
  
!   if (_Jv_JVMPI_Notify_OBJECT_ALLOC)
      {
        JVMPI_Event event;
  
--- 343,349 ----
  #ifdef ENABLE_JVMPI
    // Service JVMPI request.
  
!   if (__builtin_expect (_Jv_JVMPI_Notify_OBJECT_ALLOC != 0, 0))
      {
        JVMPI_Event event;
  
***************
*** 366,372 ****
  jobjectArray
  _Jv_NewObjectArray (jsize count, jclass elementClass, jobject init)
  {
!   if (count < 0)
      JvThrow (new java::lang::NegativeArraySizeException);
  
    JvAssert (! elementClass->isPrimitive ());
--- 370,376 ----
  jobjectArray
  _Jv_NewObjectArray (jsize count, jclass elementClass, jobject init)
  {
!   if (__builtin_expect (count < 0, 0))
      JvThrow (new java::lang::NegativeArraySizeException);
  
    JvAssert (! elementClass->isPrimitive ());
***************
*** 376,382 ****
  							     elementClass);
  
    // Check for overflow.
!   if ((size_t) count > (SIZE_T_MAX - size) / sizeof (jobject))
      JvThrow (no_memory);
  
    size += count * sizeof (jobject);
--- 380,387 ----
  							     elementClass);
  
    // Check for overflow.
!   if (__builtin_expect ((size_t) count > 
! 			(SIZE_T_MAX - size) / sizeof (jobject), 0));
      JvThrow (no_memory);
  
    size += count * sizeof (jobject);
***************
*** 385,391 ****
    jclass clas = _Jv_FindArrayClass (elementClass, 0);
  
    obj = (jobjectArray) _Jv_AllocArray (size);
!   if (! obj)
      JvThrow (no_memory);
    obj->length = count;
    jobject* ptr = elements(obj);
--- 390,396 ----
    jclass clas = _Jv_FindArrayClass (elementClass, 0);
  
    obj = (jobjectArray) _Jv_AllocArray (size);
!   if (__builtin_expect (! obj, 0))
      JvThrow (no_memory);
    obj->length = count;
    jobject* ptr = elements(obj);
***************
*** 409,415 ****
  _Jv_NewPrimArray (jclass eltype, jint count)
  {
    int elsize = eltype->size();
!   if (count < 0)
      JvThrow (new java::lang::NegativeArraySizeException ());
  
    JvAssert (eltype->isPrimitive ());
--- 414,420 ----
  _Jv_NewPrimArray (jclass eltype, jint count)
  {
    int elsize = eltype->size();
!   if (__builtin_expect (count < 0, 0))
      JvThrow (new java::lang::NegativeArraySizeException ());
  
    JvAssert (eltype->isPrimitive ());
***************
*** 417,427 ****
    size_t size = (size_t) _Jv_GetArrayElementFromElementType (dummy, eltype);
  
    // Check for overflow.
!   if ((size_t) count > (SIZE_T_MAX - size) / elsize)
      JvThrow (no_memory);
  
    __JArray *arr = (__JArray*) _Jv_AllocObj (size + elsize * count);
!   if (! arr)
      JvThrow (no_memory);
    arr->length = count;
    // Note that we assume we are given zeroed memory by the allocator.
--- 422,433 ----
    size_t size = (size_t) _Jv_GetArrayElementFromElementType (dummy, eltype);
  
    // Check for overflow.
!   if (__builtin_expect ((size_t) count > 
! 			(SIZE_T_MAX - size) / elsize, 0))
      JvThrow (no_memory);
  
    __JArray *arr = (__JArray*) _Jv_AllocObj (size + elsize * count);
!   if (__builtin_expect (! arr, 0))
      JvThrow (no_memory);
    arr->length = count;
    // Note that we assume we are given zeroed memory by the allocator.
***************
*** 924,933 ****
  void *
  _Jv_Malloc (jsize size)
  {
!   if (size == 0)
      size = 1;
    void *ptr = malloc ((size_t) size);
!   if (ptr == NULL)
      JvThrow (no_memory);
    return ptr;
  }
--- 930,939 ----
  void *
  _Jv_Malloc (jsize size)
  {
!   if (__builtin_expect (size == 0, 0))
      size = 1;
    void *ptr = malloc ((size_t) size);
!   if (__builtin_expect (ptr == NULL, 0))
      JvThrow (no_memory);
    return ptr;
  }
***************
*** 935,944 ****
  void *
  _Jv_Realloc (void *ptr, jsize size)
  {
!   if (size == 0)
      size = 1;
    ptr = realloc (ptr, (size_t) size);
!   if (ptr == NULL)
      JvThrow (no_memory);
    return ptr;
  }
--- 941,950 ----
  void *
  _Jv_Realloc (void *ptr, jsize size)
  {
!   if (__builtin_expect (size == 0, 0))
      size = 1;
    ptr = realloc (ptr, (size_t) size);
!   if (__builtin_expect (ptr == NULL, 0))
      JvThrow (no_memory);
    return ptr;
  }
***************
*** 946,952 ****
  void *
  _Jv_MallocUnchecked (jsize size)
  {
!   if (size == 0)
      size = 1;
    return malloc ((size_t) size);
  }
--- 952,958 ----
  void *
  _Jv_MallocUnchecked (jsize size)
  {
!   if (__builtin_expect (size == 0, 0))
      size = 1;
    return malloc ((size_t) size);
  }
***************
*** 967,973 ****
  jint
  _Jv_divI (jint dividend, jint divisor)
  {
!   if (divisor == 0)
      _Jv_Throw (arithexception);
    
    if (dividend == (jint) 0x80000000L && divisor == -1)
--- 973,979 ----
  jint
  _Jv_divI (jint dividend, jint divisor)
  {
!   if (__builtin_expect (divisor == 0, 0))
      _Jv_Throw (arithexception);
    
    if (dividend == (jint) 0x80000000L && divisor == -1)
***************
*** 979,985 ****
  jint
  _Jv_remI (jint dividend, jint divisor)
  {
!   if (divisor == 0)
      _Jv_Throw (arithexception);
    
    if (dividend == (jint) 0x80000000L && divisor == -1)
--- 985,991 ----
  jint
  _Jv_remI (jint dividend, jint divisor)
  {
!   if (__builtin_expect (divisor == 0, 0))
      _Jv_Throw (arithexception);
    
    if (dividend == (jint) 0x80000000L && divisor == -1)
***************
*** 991,997 ****
  jlong
  _Jv_divJ (jlong dividend, jlong divisor)
  {
!   if (divisor == 0)
      _Jv_Throw (arithexception);
    
    if (dividend == (jlong) 0x8000000000000000LL && divisor == -1)
--- 997,1003 ----
  jlong
  _Jv_divJ (jlong dividend, jlong divisor)
  {
!   if (__builtin_expect (divisor == 0, 0))
      _Jv_Throw (arithexception);
    
    if (dividend == (jlong) 0x8000000000000000LL && divisor == -1)
***************
*** 1003,1009 ****
  jlong
  _Jv_remJ (jlong dividend, jlong divisor)
  {
!   if (divisor == 0)
      _Jv_Throw (arithexception);
    
    if (dividend == (jlong) 0x8000000000000000LL && divisor == -1)
--- 1009,1015 ----
  jlong
  _Jv_remJ (jlong dividend, jlong divisor)
  {
!   if (__builtin_expect (divisor == 0, 0))
      _Jv_Throw (arithexception);
    
    if (dividend == (jlong) 0x8000000000000000LL && divisor == -1)
Index: java/lang/natObject.cc
===================================================================
RCS file: /cvs/java/libgcj/libjava/java/lang/natObject.cc,v
retrieving revision 1.10
diff -c -r1.10 natObject.cc
*** natObject.cc	2000/04/09 01:26:20	1.10
--- natObject.cc	2000/04/22 15:04:40
***************
*** 8,13 ****
--- 8,17 ----
  Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
  details.  */
  
+ // FIXME: Remove this macro definition once __builtin_expect is known
+ // to work.
+ #define __builtin_expect(A,B) (A)
+ 
  #include <config.h>
  
  #include <string.h>
***************
*** 172,181 ****
  void
  java::lang::Object::notify (void)
  {
!   if (INIT_NEEDED (this))
      sync_init ();
    _Jv_SyncInfo *si = (_Jv_SyncInfo *) sync_info;
!   if (_Jv_CondNotify (&si->condition, &si->mutex))
      JvThrow (new IllegalMonitorStateException(JvNewStringLatin1 
                                                ("current thread not owner")));
  }
--- 176,185 ----
  void
  java::lang::Object::notify (void)
  {
!   if (__builtin_expect (INIT_NEEDED (this), 0))
      sync_init ();
    _Jv_SyncInfo *si = (_Jv_SyncInfo *) sync_info;
!   if (__builtin_expt (_Jv_CondNotify (&si->condition, &si->mutex), 0))
      JvThrow (new IllegalMonitorStateException(JvNewStringLatin1 
                                                ("current thread not owner")));
  }
***************
*** 183,192 ****
  void
  java::lang::Object::notifyAll (void)
  {
!   if (INIT_NEEDED (this))
      sync_init ();
    _Jv_SyncInfo *si = (_Jv_SyncInfo *) sync_info;
!   if (_Jv_CondNotifyAll (&si->condition, &si->mutex))
      JvThrow (new IllegalMonitorStateException(JvNewStringLatin1 
                                                ("current thread not owner")));
  }
--- 187,196 ----
  void
  java::lang::Object::notifyAll (void)
  {
!   if (__builtin_expect (INIT_NEEDED (this), 0))
      sync_init ();
    _Jv_SyncInfo *si = (_Jv_SyncInfo *) sync_info;
!   if (__builtin_expect (_Jv_CondNotifyAll (&si->condition, &si->mutex), 0))
      JvThrow (new IllegalMonitorStateException(JvNewStringLatin1 
                                                ("current thread not owner")));
  }
***************
*** 194,202 ****
  void
  java::lang::Object::wait (jlong timeout, jint nanos)
  {
!   if (INIT_NEEDED (this))
      sync_init ();
!   if (timeout < 0 || nanos < 0 || nanos > 999999)
      JvThrow (new IllegalArgumentException);
    _Jv_SyncInfo *si = (_Jv_SyncInfo *) sync_info;
    switch (_Jv_CondWait (&si->condition, &si->mutex, timeout, nanos))
--- 198,206 ----
  void
  java::lang::Object::wait (jlong timeout, jint nanos)
  {
!   if (__builtin_expect (INIT_NEEDED (this), 0))
      sync_init ();
!   if (__builtin_expect (timeout < 0 || nanos < 0 || nanos > 999999, 0))
      JvThrow (new IllegalArgumentException);
    _Jv_SyncInfo *si = (_Jv_SyncInfo *) sync_info;
    switch (_Jv_CondWait (&si->condition, &si->mutex, timeout, nanos))
***************
*** 226,235 ****
  _Jv_MonitorEnter (jobject obj)
  {
  #ifndef HANDLE_SEGV
!   if (! obj)
      JvThrow (new java::lang::NullPointerException);
  #endif
!   if (INIT_NEEDED (obj))
      obj->sync_init ();
    _Jv_SyncInfo *si = (_Jv_SyncInfo *) obj->sync_info;
    return _Jv_MutexLock (&si->mutex);
--- 230,239 ----
  _Jv_MonitorEnter (jobject obj)
  {
  #ifndef HANDLE_SEGV
!   if (__builtin_expect (! obj, 0))
      JvThrow (new java::lang::NullPointerException);
  #endif
!   if (__builtin_expect (INIT_NEEDED (obj), 0))
      obj->sync_init ();
    _Jv_SyncInfo *si = (_Jv_SyncInfo *) obj->sync_info;
    return _Jv_MutexLock (&si->mutex);
***************
*** 241,247 ****
    JvAssert (obj);
    JvAssert (! INIT_NEEDED (obj));
    _Jv_SyncInfo *si = (_Jv_SyncInfo *) obj->sync_info;
!   if (_Jv_MutexUnlock (&si->mutex))
      JvThrow (new java::lang::IllegalMonitorStateException);
    return 0;
  }
--- 245,251 ----
    JvAssert (obj);
    JvAssert (! INIT_NEEDED (obj));
    _Jv_SyncInfo *si = (_Jv_SyncInfo *) obj->sync_info;
!   if (__builtin_expect (_Jv_MutexUnlock (&si->mutex), 0))
      JvThrow (new java::lang::IllegalMonitorStateException);
    return 0;
  }

-- 
Anthony Green                                                        Red Hat
                                                       Sunnyvale, California


More information about the Java-patches mailing list