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