* src/threads/native/lock.h, src/threads/native/lock.c: Tasuki lock
authoredwin <none@none>
Thu, 18 May 2006 14:33:32 +0000 (14:33 +0000)
committeredwin <none@none>
Thu, 18 May 2006 14:33:32 +0000 (14:33 +0000)
implementation (without lock deflation). This is a straight-forward
implementation that uses an extra word in java_objectheader for the
FLC (flat lock contention) bit.

* src/vm/global.h (java_objectheader): Added field `flcword`.

* src/threads/native/lock.h (Authors): Changed to myself, as there
is none of the old code remaining in this file.

* src/vm/jit/powerpc/codegen.c, src/vm/jit/alpha/codegen.c,
src/vm/jit/mips/codegen.c, src/vm/jit/i386/codegen.c,
src/vm/jit/x86_64/codegen.c (codegen, createnativestub): Add the
FLC word when creating the fake object header for patcher
synchronization.

src/threads/native/lock.c
src/threads/native/lock.h
src/vm/global.h
src/vm/jit/alpha/codegen.c
src/vm/jit/i386/codegen.c
src/vm/jit/mips/codegen.c
src/vm/jit/powerpc/codegen.c
src/vm/jit/x86_64/codegen.c

index 0cf9c7d77c63c0697ad9db2335c515483f0efc7d..fd75800a70e13bfed291aa2e8bb44a8300c17c49 100644 (file)
 #include "machine-instr.h"
 #endif
 
+
+/******************************************************************************/
+/* DEBUGGING MACROS                                                           */
+/******************************************************************************/
+
 /* #define LOCK_VERBOSE */
 
+#if defined(LOCK_VERBOSE)
+#define LOCK_LOG(args)  do { printf args; fflush(stdout); } while (0)
+#else
+#define LOCK_LOG(args)
+#endif
+
 
 /******************************************************************************/
 /* MACROS                                                                     */
 /******************************************************************************/
 
 /* number of lock records in the first pool allocated for a thread */
-#define INITIALLOCKRECORDS 8
+#define LOCK_INITIAL_LOCK_RECORDS 8
+
+#define LOCK_INITIAL_HASHTABLE_SIZE  1613  /* a prime in the middle between 1024 and 2048 */
+
+#define LOCK_HASH(obj)  ((ptrint)(obj))
 
 #define COMPARE_AND_SWAP_OLD_VALUE(address, oldvalue, newvalue) \
        ((ptrint) compare_and_swap((long *)(address), (long)(oldvalue), (long)(newvalue)))
        (compare_and_swap((long *)(address), (long)(oldvalue), (long)(newvalue)) == (long)(oldvalue))
 
 
+/******************************************************************************/
+/* MACROS FOR THE FLAT LOCK CONTENTION BIT                                    */
+/******************************************************************************/
+
+#define LOCK_SET_FLC_BIT(obj)    ((obj)->flcword = 1)
+#define LOCK_CLEAR_FLC_BIT(obj)  ((obj)->flcword = 0)
+#define LOCK_TEST_FLC_BIT(obj)   ((obj)->flcword != 0)
+
+
 /******************************************************************************/
 /* MACROS FOR THIN/FAT LOCKS                                                  */
 /******************************************************************************/
 
-/* We use a variant of the thin locks described in the paper
+/* We use a variant of the tasuki locks described in the paper
+ *     
+ *     Tamiya Onodera, Kiyokuni Kawachiya
+ *     A Study of Locking Objects with Bimodal Fields
+ *     Proceedings of the ACM OOPSLA '99, pp. 223-237
+ *     1999
+ *
+ * The underlying thin locks are a variant of the thin locks described in
  * 
  *     Bacon, Konuru, Murthy, Serrano
  *     Thin Locks: Featherweight Synchronization for Java
@@ -147,6 +178,23 @@ lock_record_pool_t *lock_global_pool;
 /* mutex for synchronizing access to the global pool */
 pthread_mutex_t lock_global_pool_lock;
 
+/* hashtable mapping objects to lock records */
+static lock_hashtable_t lock_hashtable;
+
+
+/******************************************************************************/
+/* PROTOTYPES                                                                 */
+/******************************************************************************/
+
+static void lock_hashtable_init(void);
+static lock_record_t * lock_hashtable_get_lock_record(threadobject *t, java_objectheader *o);
+
+static lock_record_t * lock_record_alloc(threadobject *t);
+
+static void lock_record_enter(threadobject *t, lock_record_t *lr);
+static void lock_record_exit(threadobject *t, lock_record_t *lr);
+static void lock_record_wait(threadobject *t, lock_record_t *lr, s8 millis, s4 nanos);
+static void lock_record_notify(threadobject *t, lock_record_t *lr, bool one);
 
 
 /*============================================================================*/
@@ -163,6 +211,8 @@ pthread_mutex_t lock_global_pool_lock;
 void lock_init(void)
 {
        pthread_mutex_init(&lock_global_pool_lock, NULL);
+
+       lock_hashtable_init();
 }
 
 
@@ -178,7 +228,7 @@ void lock_init(void)
 
 static void lock_record_init(lock_record_t *r, threadobject *t)
 {
-       r->owner = t;
+       r->owner = NULL;
        r->count = 0;
        r->waiters = NULL;
 
@@ -307,7 +357,7 @@ static lock_record_pool_t *lock_record_alloc_pool(threadobject *t, int size)
                /* re-initialize owner and freelist chaining */
 
                for (i=0; i < pool->header.size; i++) {
-                       pool->lr[i].owner = t;
+                       pool->lr[i].owner = NULL;
                        pool->lr[i].nextfree = &pool->lr[i+1];
                }
                pool->lr[i-1].nextfree = NULL;
@@ -371,10 +421,6 @@ void lock_record_free_pools(lock_record_pool_t *pool)
    IN:
       t............the current thread 
 
-   POST-CONDITION:
-      The current thread holds the mutex of the returned lock record
-         and is recored as owner of the record.
-
 *******************************************************************************/
 
 static lock_record_t *lock_record_alloc(threadobject *t)
@@ -390,7 +436,8 @@ static lock_record_t *lock_record_alloc(threadobject *t)
 
                /* get a new pool */
 
-               poolsize = t->ee.lockrecordcount ? t->ee.lockrecordcount * 2 : INITIALLOCKRECORDS;
+               poolsize = t->ee.lockrecordcount ? t->ee.lockrecordcount * 2
+                                                                                : LOCK_INITIAL_LOCK_RECORDS;
                pool = lock_record_alloc_pool(t, poolsize);
 
                /* add it to our per-thread pool list */
@@ -410,10 +457,6 @@ static lock_record_t *lock_record_alloc(threadobject *t)
        r->nextfree = NULL; /* in order to find invalid uses of nextfree */
 #endif
 
-       /* pre-acquire the mutex of the new lock record */
-
-       pthread_mutex_lock(&(r->mutex));
-
        return r;
 }
 
@@ -433,7 +476,7 @@ static inline void lock_record_recycle(threadobject *t, lock_record_t *r)
 {
        assert(t);
        assert(r);
-       assert(r->owner == t);
+       assert(r->owner == NULL);
        assert(r->nextfree == NULL);
 
        r->nextfree = t->ee.firstfree;
@@ -442,6 +485,157 @@ static inline void lock_record_recycle(threadobject *t, lock_record_t *r)
 
 
 
+/*============================================================================*/
+/* HASHTABLE MAPPING OBJECTS TO LOCK RECORDS                                  */
+/*============================================================================*/
+
+
+/* lock_hashtable_init *********************************************************
+
+   Initialize the global hashtable mapping objects to lock records.
+
+*******************************************************************************/
+
+static void lock_hashtable_init(void)
+{
+       pthread_mutex_init(&(lock_hashtable.mutex), NULL);
+
+       lock_hashtable.size = LOCK_INITIAL_HASHTABLE_SIZE;
+       lock_hashtable.entries = 0;
+       lock_hashtable.ptr = MNEW(lock_record_t *, lock_hashtable.size);
+       MZERO(lock_hashtable.ptr, lock_record_t *, lock_hashtable.size);
+}
+
+
+/* lock_hashtable_grow *********************************************************
+
+   Grow the lock record hashtable to about twice its current size and
+   rehash the entries.
+
+*******************************************************************************/
+
+/* must be called with hashtable mutex locked */
+static void lock_hashtable_grow(void)
+{
+       u4 oldsize;
+       u4 newsize;
+       lock_record_t **oldtable;
+       lock_record_t **newtable;
+       lock_record_t *lr;
+       lock_record_t *next;
+       u4 i;
+       u4 h;
+       u4 newslot;
+
+       /* allocate a new table */
+
+       oldsize = lock_hashtable.size;
+       newsize = oldsize*2 + 1; /* XXX should use prime numbers */
+
+       LOCK_LOG(("growing lock hashtable to size %d\n", newsize));
+
+       oldtable = lock_hashtable.ptr;
+       newtable = MNEW(lock_record_t *, newsize);
+       MZERO(newtable, lock_record_t *, newsize);
+
+       /* rehash the entries */
+
+       for (i=0; i<oldsize; ++i) {
+               lr = oldtable[i];
+               while (lr) {
+                       next = lr->hashlink;
+
+                       h = LOCK_HASH(lr->obj);
+                       newslot = h % newsize;
+
+                       lr->hashlink = newtable[newslot];
+                       newtable[newslot] = lr;
+
+                       lr = next;
+               }
+       }
+
+       /* replace the old table */
+
+       lock_hashtable.ptr = newtable;
+       lock_hashtable.size = newsize;
+
+       MFREE(oldtable, lock_record_t *, oldsize);
+}
+
+
+/* lock_hashtable_get_lock_record **********************************************
+
+   Find the lock record for the given object. If it does not exists, yet,
+   create it and enter it in the hashtable.
+
+   IN:
+      t.................the current thread
+         o.................the object to look up
+
+   RETURN VALUE:
+      the lock record to use for this object
+
+*******************************************************************************/
+
+static lock_record_t *lock_hashtable_get_lock_record(threadobject *t, java_objectheader *o)
+{
+       ptrint lockword;
+       u4 slot;
+       lock_record_t *lr;
+
+       lockword = (ptrint) o->monitorPtr;
+
+       if (IS_FAT_LOCK(lockword)) {
+               return GET_FAT_LOCK(lockword);
+       }
+
+       /* lock the hashtable */
+
+       pthread_mutex_lock(&(lock_hashtable.mutex));
+
+       /* lookup the lock record in the hashtable */
+
+       slot = LOCK_HASH(o) % lock_hashtable.size;
+       lr = lock_hashtable.ptr[slot];
+       while (lr) {
+               if (lr->obj == o) {
+                       pthread_mutex_unlock(&(lock_hashtable.mutex));
+                       return lr;
+               }
+
+               lr = lr->hashlink;
+       }
+
+       /* not found, we must create a new one */
+
+       lr = lock_record_alloc(t);
+       lr->obj = o;
+       LOCK_LOG(("thread %d allocated for %p new lr %p\n",
+                       t->index, (void*) o, (void*) lr));
+
+       /* enter it in the hashtable */
+
+       lr->hashlink = lock_hashtable.ptr[slot];
+       lock_hashtable.ptr[slot] = lr;
+       lock_hashtable.entries++;
+
+       /* check whether the hash should grow */
+
+       if (lock_hashtable.entries * 3 > lock_hashtable.size * 4) {
+               lock_hashtable_grow();
+       }
+
+       /* unlock the hashtable */
+
+       pthread_mutex_unlock(&(lock_hashtable.mutex));
+
+       /* return the new lock record */
+
+       return lr;
+}
+
+
 /*============================================================================*/
 /* OBJECT LOCK INITIALIZATION                                                 */
 /*============================================================================*/
@@ -459,6 +653,7 @@ void lock_init_object_lock(java_objectheader *o)
        assert(o);
 
        o->monitorPtr = (lock_record_t *) THIN_UNLOCKED;
+       o->flcword = 0;
 }
 
 
@@ -482,52 +677,94 @@ lock_record_t *lock_get_initial_lock_word(void)
 /*============================================================================*/
 
 
+/* lock_record_enter ***********************************************************
+
+   Enter the lock represented by the given lock record.
+
+   IN:
+      t.................the current thread
+         lr................the lock record
+
+*******************************************************************************/
+
+static inline void lock_record_enter(threadobject *t, lock_record_t *lr)
+{
+       pthread_mutex_lock(&(lr->mutex));
+       lr->owner = t;
+}
+
+
+/* lock_record_exit ************************************************************
+
+   Release the lock represented by the given lock record.
+
+   IN:
+      t.................the current thread
+         lr................the lock record
+
+   PRE-CONDITION:
+      The current thread must own the lock represented by this lock record.
+         This is NOT checked by this function!
+
+*******************************************************************************/
+
+static inline void lock_record_exit(threadobject *t, lock_record_t *lr)
+{
+       lr->owner = NULL;
+       pthread_mutex_unlock(&(lr->mutex));
+}
+
+
 /* lock_inflate ****************************************************************
 
    Inflate the lock of the given object. This may only be called by the
-   owner of the monitor.
+   owner of the monitor of the object.
 
    IN:
       t............the current thread
          o............the object of which to inflate the lock
-
-   RETURN VALUE:
-      the new lock record of the object
+         lr...........the lock record to install. The current thread must
+                      own the lock of this lock record!
 
    PRE-CONDITION:
-      The current thread must be the owner of this object's monitor!
+      The current thread must be the owner of this object's monitor AND
+         of the lock record's lock!
 
 *******************************************************************************/
 
-static lock_record_t *lock_inflate(threadobject *t, java_objectheader *o)
+static void lock_inflate(threadobject *t, java_objectheader *o, lock_record_t *lr)
 {
-       lock_record_t *lr;
        ptrint lockword;
-       ptrint count;
 
        /* get the current lock count */
 
        lockword = (ptrint) o->monitorPtr;
 
-       assert( LOCK_WORD_WITHOUT_COUNT(lockword) == t->thinlock );
+       if (IS_FAT_LOCK(lockword)) {
+               assert(GET_FAT_LOCK(lockword) == lr);
+       }
+       else {
+               assert( LOCK_WORD_WITHOUT_COUNT(lockword) == t->thinlock );
 
-       count = (lockword & THIN_LOCK_COUNT_MASK) >> THIN_LOCK_COUNT_SHIFT;
+               /* copy the count from the thin lock */
 
-       /* allocate a fat lock */
+               lr->count = (lockword & THIN_LOCK_COUNT_MASK) >> THIN_LOCK_COUNT_SHIFT;
+       }
 
-       lr = lock_record_alloc(t);
-       lr->count = count;
+       LOCK_LOG(("thread %3d: inflating lock of object %p current lockword %lx, count %d\n",
+                       t->index, (void*) o, (long)o->monitorPtr, (int)lr->count));
 
-#if defined(LOCK_VERBOSE)
-       printf("thread %3d: inflating lock of object %p current lockword %lx, count %d\n",
-                       t->index, (void*) o, (long)o->monitorPtr, (int)count);
-#endif
+       /* clear flat-lock-contention bit */
+
+       LOCK_CLEAR_FLC_BIT(o);
+
+       /* notify waiting objects */
+
+       lock_record_notify(t, lr, false);
 
        /* install it */
 
        o->monitorPtr = (lock_record_t *) MAKE_FAT_LOCK(lr);
-
-       return lr;
 }
 
 
@@ -583,7 +820,9 @@ void lock_monitor_enter(threadobject *t, java_objectheader *o)
 
                        /* recursion count overflow */
 
-                       lr = lock_inflate(t, o);
+                       lr = lock_hashtable_get_lock_record(t, o);
+                       lock_record_enter(t, lr);
+                       lock_inflate(t, o, lr);
                        lr->count++;
 
                        return;
@@ -594,7 +833,6 @@ void lock_monitor_enter(threadobject *t, java_objectheader *o)
 
        {
                lock_record_t *lr;
-               ptrint fatlock;
 
                if (IS_FAT_LOCK(lockword)) {
 
@@ -605,53 +843,54 @@ void lock_monitor_enter(threadobject *t, java_objectheader *o)
                                lr->count++;
                                return;
                        }
-               }
-               else {
-                       /* alloc a lock record owned by us */
-                       lr = lock_record_alloc(t);
-                       fatlock = MAKE_FAT_LOCK(lr);
 
-#if defined(LOCK_VERBOSE)
-                       printf("thread %3d: SPINNING for inflating lock of %p, current lockword = %lx\n",
-                                       t->index, (void*)o, (long)lockword);
-#endif
+                       /* acquire the mutex of the lock record */
 
-                       /* SPIN LOOP */
-                       while (true) {
-                               lockword = COMPARE_AND_SWAP_OLD_VALUE(&(o->monitorPtr), THIN_UNLOCKED, fatlock);
-                               if (lockword == THIN_UNLOCKED) {
-#if defined(LOCK_VERBOSE)
-                                       printf("thread %3d: successfully inflated lock of %p\n",
-                                                       t->index, (void*)o);
-#endif
-                                       /* we managed to install our lock record */
-                                       /* The Java Memory Model requires a memory barrier here: */
-                                       MEMORY_BARRIER();
-                                       return;
-                               }
+                       lock_record_enter(t, lr);
 
-                               if (IS_FAT_LOCK(lockword)) {
-#if defined(LOCK_VERBOSE)
-                                       printf("thread %3d: lock of %p was inflated by other thread, lockword = %lx\n",
-                                                       t->index, (void*)o, (long)lockword);
-#endif
-                                       /* another thread inflated the lock */
-                                       pthread_mutex_unlock(&(lr->mutex));
-                                       lock_record_recycle(t, lr);
+                       assert(lr->count == 0);
 
-                                       lr = GET_FAT_LOCK(lockword);
-                                       break;
-                               }
-                       }
+                       return;
                }
 
-               /* acquire the mutex of the lock record */
-               pthread_mutex_lock(&(lr->mutex));
+               /****** inflation path ******/
+
+               /* first obtain the lock record for this object */
+
+               lr = lock_hashtable_get_lock_record(t, o);
+
+               /* enter the monitor */
 
-               /* enter us as the owner */
-               lr->owner = t;
+               lock_record_enter(t, lr);
 
-               assert(lr->count == 0);
+               /* inflation loop */
+
+               while (IS_THIN_LOCK(lockword = (ptrint) o->monitorPtr)) {
+                       /* Set the flat lock contention bit to let the owning thread */
+                       /* know that we want to be notified of unlocking.            */
+
+                       LOCK_SET_FLC_BIT(o);
+
+                       LOCK_LOG(("thread %d set flc bit on %p lr %p\n",
+                                       t->index, (void*) o, (void*) lr));
+
+                       /* try to lock the object */
+
+                       if (COMPARE_AND_SWAP_SUCCEEDS(&(o->monitorPtr), THIN_UNLOCKED, thinlock)) {
+                               /* we can inflate the lock ourselves */
+                               LOCK_LOG(("thread %d inflating lock of %p to lr %p\n",
+                                               t->index, (void*) o, (void*) lr));
+                               lock_inflate(t, o, lr);
+                       }
+                       else {
+                               /* wait until another thread sees the flc bit and notifies us of unlocking */
+                               LOCK_LOG(("thread %d waiting for notification on %p lr %p\n",
+                                               t->index, (void*) o, (void*) lr));
+                               lock_record_wait(t, lr, 0, 0);
+                       }
+               }
+
+               /* we own the inflated lock now */
 
                return;
        }
@@ -695,6 +934,33 @@ bool lock_monitor_exit(threadobject *t, java_objectheader *o)
                o->monitorPtr = THIN_UNLOCKED;
                /* memory barrier for thin locking */
                MEMORY_BARRIER();
+
+               /* check if there has been a flat lock contention on this object */
+
+               if (LOCK_TEST_FLC_BIT(o)) {
+                       lock_record_t *lr;
+
+                       LOCK_LOG(("thread %d saw flc bit on %p %s\n",
+                                       t->index, (void*) o, o->vftbl->class->name->text));
+
+                       /* there has been a contention on this thin lock */
+
+                       lr = lock_hashtable_get_lock_record(t, o);
+
+                       LOCK_LOG(("thread %d for %p got lr %p\n",
+                                       t->index, (void*) o, (void*) lr));
+
+                       lock_record_enter(t, lr);
+
+                       if (LOCK_TEST_FLC_BIT(o)) {
+                               /* notify a thread that it can try to inflate the lock now */
+
+                               lock_record_notify(t, lr, true);
+                       }
+
+                       lock_record_exit(t, lr);
+               }
+
                return true;
        }
 
@@ -781,56 +1047,28 @@ static void lock_record_remove_waiter(lock_record_t *lr, threadobject *t)
 }
 
 
-/* lock_monitor_wait ***********************************************************
+/* lock_record_wait ************************************************************
 
-   Wait on an object for a given (maximum) amount of time.
+   Wait on a lock record for a given (maximum) amount of time.
 
    IN:
       t............the current thread
-         o............the object
+         lr...........the lock record
          millis.......milliseconds of timeout
          nanos........nanoseconds of timeout
 
    PRE-CONDITION:
-      The current thread must be the owner of the object's monitor.
+      The current thread must be the owner of the lock record.
+         This is NOT checked by this function!
    
 *******************************************************************************/
 
-static void lock_monitor_wait(threadobject *t, java_objectheader *o, s8 millis, s4 nanos)
+static void lock_record_wait(threadobject *t, lock_record_t *lr, s8 millis, s4 nanos)
 {
-       ptrint         lockword;
-       lock_record_t *lr;
        lock_waiter_t *waiter;
        s4             lockcount;
        bool           wasinterrupted;
 
-       lockword = (ptrint) o->monitorPtr;
-
-       /* check if we own this monitor */
-       /* We don't have to worry about stale values here, as any stale value */
-       /* will fail this check.                                              */
-
-       if (IS_FAT_LOCK(lockword)) {
-
-               lr = GET_FAT_LOCK(lockword);
-
-               if (lr->owner != t) {
-                       *exceptionptr = new_illegalmonitorstateexception();
-                       return;
-               }
-       }
-       else {
-               /* it's a thin lock */
-
-               if (LOCK_WORD_WITHOUT_COUNT(lockword) != t->thinlock) {
-                       *exceptionptr = new_illegalmonitorstateexception();
-                       return;
-               }
-
-               /* inflate this lock */
-               lr = lock_inflate(t, o);
-       }
-
        /* { the thread t owns the fat lock record lr on the object o } */
 
        /* register us as waiter for this object */
@@ -847,8 +1085,7 @@ static void lock_monitor_wait(threadobject *t, java_objectheader *o, s8 millis,
        /* unlock this record */
 
        lr->count = 0;
-       lr->owner = NULL;
-       pthread_mutex_unlock(&(lr->mutex));
+       lock_record_exit(t, lr);
 
        /* wait until notified/interrupted/timed out */
 
@@ -856,11 +1093,7 @@ static void lock_monitor_wait(threadobject *t, java_objectheader *o, s8 millis,
 
        /* re-enter the monitor */
 
-       lock_monitor_enter(t, o);
-
-       /* assert that the lock record is still the same */
-
-       assert( GET_FAT_LOCK((ptrint) o->monitorPtr) == lr );
+       lock_record_enter(t, lr);
 
        /* remove us from the list of waiting threads */
 
@@ -877,26 +1110,25 @@ static void lock_monitor_wait(threadobject *t, java_objectheader *o, s8 millis,
 }
 
 
-/* lock_monitor_notify *********************************************************
+/* lock_monitor_wait ***********************************************************
 
-   Notify one thread or all threads waiting on the given object.
+   Wait on an object for a given (maximum) amount of time.
 
    IN:
       t............the current thread
          o............the object
-         one..........if true, only notify one thread
+         millis.......milliseconds of timeout
+         nanos........nanoseconds of timeout
 
    PRE-CONDITION:
       The current thread must be the owner of the object's monitor.
    
 *******************************************************************************/
 
-static void lock_monitor_notify(threadobject *t, java_objectheader *o, bool one)
+static void lock_monitor_wait(threadobject *t, java_objectheader *o, s8 millis, s4 nanos)
 {
-       ptrint lockword;
+       ptrint         lockword;
        lock_record_t *lr;
-       lock_waiter_t *waiter;
-       threadobject *waitingthread;
 
        lockword = (ptrint) o->monitorPtr;
 
@@ -922,11 +1154,39 @@ static void lock_monitor_notify(threadobject *t, java_objectheader *o, bool one)
                }
 
                /* inflate this lock */
-               lr = lock_inflate(t, o);
+               lr = lock_hashtable_get_lock_record(t, o);
+               lock_record_enter(t, lr);
+               lock_inflate(t, o, lr);
        }
 
        /* { the thread t owns the fat lock record lr on the object o } */
 
+       lock_record_wait(t, lr, millis, nanos);
+}
+
+
+/* lock_record_notify **********************************************************
+
+   Notify one thread or all threads waiting on the given lock record.
+
+   IN:
+      t............the current thread
+         lr...........the lock record
+         one..........if true, only notify one thread
+
+   PRE-CONDITION:
+      The current thread must be the owner of the lock record.
+         This is NOT checked by this function!
+   
+*******************************************************************************/
+
+static void lock_record_notify(threadobject *t, lock_record_t *lr, bool one)
+{
+       lock_waiter_t *waiter;
+       threadobject *waitingthread;
+
+       /* { the thread t owns the fat lock record lr on the object o } */
+
        /* for each waiter: */
 
        for (waiter = lr->waiters; waiter; waiter = waiter->next) {
@@ -949,6 +1209,60 @@ static void lock_monitor_notify(threadobject *t, java_objectheader *o, bool one)
 }
 
 
+/* lock_monitor_notify *********************************************************
+
+   Notify one thread or all threads waiting on the given object.
+
+   IN:
+      t............the current thread
+         o............the object
+         one..........if true, only notify one thread
+
+   PRE-CONDITION:
+      The current thread must be the owner of the object's monitor.
+   
+*******************************************************************************/
+
+static void lock_monitor_notify(threadobject *t, java_objectheader *o, bool one)
+{
+       ptrint lockword;
+       lock_record_t *lr;
+
+       lockword = (ptrint) o->monitorPtr;
+
+       /* check if we own this monitor */
+       /* We don't have to worry about stale values here, as any stale value */
+       /* will fail this check.                                              */
+
+       if (IS_FAT_LOCK(lockword)) {
+
+               lr = GET_FAT_LOCK(lockword);
+
+               if (lr->owner != t) {
+                       *exceptionptr = new_illegalmonitorstateexception();
+                       return;
+               }
+       }
+       else {
+               /* it's a thin lock */
+
+               if (LOCK_WORD_WITHOUT_COUNT(lockword) != t->thinlock) {
+                       *exceptionptr = new_illegalmonitorstateexception();
+                       return;
+               }
+
+               /* inflate this lock */
+               lr = lock_hashtable_get_lock_record(t, o);
+               lock_record_enter(t, lr);
+               lock_inflate(t, o, lr);
+       }
+
+       /* { the thread t owns the fat lock record lr on the object o } */
+
+       lock_record_notify(t, lr, one);
+}
+
+
 
 /*============================================================================*/
 /* INQUIRY FUNCIONS                                                           */
index 29c69a3f350b5350038cc966206ec193908376cb..93de86514696eaced55ee20cfc6b80a1dc466dcf 100644 (file)
 
    Contact: cacao@cacaojvm.org
 
-   Authors: Stefan Ring
+   Authors: Edwin Steiner
 
-   Changes: Christian Thalinger
-                       Edwin Steiner
+   Changes: 
 
    $Id: threads.h 4866 2006-05-01 21:40:38Z edwin $
 
@@ -48,6 +47,7 @@ typedef struct lock_record_t             lock_record_t;
 typedef struct lock_record_pool_header_t lock_record_pool_header_t;
 typedef struct lock_record_pool_t        lock_record_pool_t;
 typedef struct lock_waiter_t             lock_waiter_t;
+typedef struct lock_hashtable_t          lock_hashtable_t;
 
 
 /* lock_execution_env_t ********************************************************
@@ -82,11 +82,27 @@ struct lock_waiter_t {
 *******************************************************************************/
 
 struct lock_record_t {
+       java_objectheader   *obj;                /* object for which this lock is */
        struct threadobject *owner;              /* current owner of this monitor */
        s4                   count;              /* recursive lock count          */
        pthread_mutex_t      mutex;              /* mutex for synchronizing       */
        lock_waiter_t       *waiters;            /* list of threads waiting       */
        lock_record_t       *nextfree;           /* next in free list             */
+       lock_record_t       *hashlink;           /* next record in hash chain     */
+};
+
+
+/* lock_hashtable_t ************************************************************
+   The global hashtable mapping objects to lock records.
+
+*******************************************************************************/
+
+struct lock_hashtable_t {
+       pthread_mutex_t      mutex;       /* mutex for synch. access to the table */
+       u4                   size;        /* number of slots                      */
+       u4                   entries;     /* current number of entries            */
+       lock_record_t      **ptr;         /* the table of slots, uses ext. chain. */
 };
 
 
index dd6b02d27a83fe678256613fca22cbd3f00100be..01aa3c625e2bbc77232b7f654c9b7f33258d1db9 100644 (file)
@@ -33,7 +33,7 @@
             Joseph Wenninger
             Christian Thalinger
 
-   $Id: global.h 4921 2006-05-15 14:24:36Z twisti $
+   $Id: global.h 4937 2006-05-18 14:33:32Z edwin $
 
 */
 
@@ -199,6 +199,7 @@ struct java_objectheader {              /* header for all objects             */
        struct _vftbl            *vftbl;    /* pointer to virtual function table  */
 #if defined(ENABLE_THREADS)
        struct lock_record_t *monitorPtr;
+       ptrint                flcword;      /* word containing the FLC bit        */
 #endif
 };
 
index 4e0bb0d85a270e907790e796937db48c342def2a..f4cb5628f15440a5f8a347d031203952c8bd1b06 100644 (file)
@@ -32,7 +32,7 @@
             Christian Ullrich
             Edwin Steiner
 
-   $Id: codegen.c 4921 2006-05-15 14:24:36Z twisti $
+   $Id: codegen.c 4937 2006-05-18 14:33:32Z edwin $
 
 */
 
@@ -3853,8 +3853,9 @@ gen_method:
 #if defined(ENABLE_THREADS)
                        /* create a virtual java_objectheader */
 
-                       (void) dseg_addaddress(cd, lock_get_initial_lock_word());          /* monitorPtr */
-                       disp = dseg_addaddress(cd, NULL);                   /* vftbl      */
+                       (void) dseg_addaddress(cd, NULL);                         /* flcword    */
+                       (void) dseg_addaddress(cd, lock_get_initial_lock_word()); /* monitorPtr */
+                       disp = dseg_addaddress(cd, NULL);                         /* vftbl      */
 
                        M_LDA(REG_ITMP3, REG_PV, disp);
                        M_AST(REG_ITMP3, REG_SP, 4 * 8);
@@ -4376,8 +4377,9 @@ u1 *createnativestub(functionptr f, jitdata *jd, methoddesc *nmd)
 #if defined(ENABLE_THREADS)
                        /* create a virtual java_objectheader */
 
-                       (void) dseg_addaddress(cd, lock_get_initial_lock_word());          /* monitorPtr */
-                       disp = dseg_addaddress(cd, NULL);                   /* vftbl      */
+                       (void) dseg_addaddress(cd, NULL);                         /* flcword    */
+                       (void) dseg_addaddress(cd, lock_get_initial_lock_word()); /* monitorPtr */
+                       disp = dseg_addaddress(cd, NULL);                         /* vftbl      */
 
                        M_LDA(REG_ITMP3, REG_PV, disp);
                        M_AST(REG_ITMP3, REG_SP, 4 * 8);
index 9288991f4957b44145294cf96141aeef1f54f3fc..014a77c8edc366fc79502999b4c9a4f06fcfbc98 100644 (file)
@@ -31,7 +31,7 @@
             Christian Ullrich
                        Edwin Steiner
 
-   $Id: codegen.c 4921 2006-05-15 14:24:36Z twisti $
+   $Id: codegen.c 4937 2006-05-18 14:33:32Z edwin $
 
 */
 
@@ -5200,8 +5200,9 @@ gen_method:
                        /* move pointer to java_objectheader onto stack */
 
 #if defined(ENABLE_THREADS)
-                       (void) dseg_addaddress(cd, lock_get_initial_lock_word());          /* monitorPtr */
-                       off = dseg_addaddress(cd, NULL);                    /* vftbl      */
+                       (void) dseg_addaddress(cd, NULL);                         /* flcword    */
+                       (void) dseg_addaddress(cd, lock_get_initial_lock_word()); /* monitorPtr */
+                       off = dseg_addaddress(cd, NULL);                          /* vftbl      */
 
                        M_MOV_IMM(0, REG_ITMP3);
                        dseg_adddata(cd);
@@ -5674,8 +5675,9 @@ u1 *createnativestub(functionptr f, jitdata *jd, methoddesc *nmd)
 #if defined(ENABLE_THREADS)
                        /* create a virtual java_objectheader */
 
-                       (void) dseg_addaddress(cd, lock_get_initial_lock_word());          /* monitorPtr */
-                       disp = dseg_addaddress(cd, NULL);                   /* vftbl      */
+                       (void) dseg_addaddress(cd, NULL);                         /* flcword    */
+                       (void) dseg_addaddress(cd, lock_get_initial_lock_word()); /* monitorPtr */
+                       disp = dseg_addaddress(cd, NULL);                         /* vftbl      */
 
                        M_MOV_IMM(0, REG_ITMP3);
                        dseg_adddata(cd);
index 417b6667474675a17d616b9f562d8efca3687bec..db368192006f18ab7481430a6d9ee10bf1174a04 100644 (file)
@@ -35,7 +35,7 @@
    This module generates MIPS machine code for a sequence of
    intermediate code commands (ICMDs).
 
-   $Id: codegen.c 4921 2006-05-15 14:24:36Z twisti $
+   $Id: codegen.c 4937 2006-05-18 14:33:32Z edwin $
 
 */
 
@@ -3850,8 +3850,9 @@ gen_method:
 #if defined(ENABLE_THREADS)
                        /* create a virtual java_objectheader */
 
-                       (void) dseg_addaddress(cd, lock_get_initial_lock_word());          /* monitorPtr */
-                       disp = dseg_addaddress(cd, NULL);                   /* vftbl      */
+                       (void) dseg_addaddress(cd, NULL);                         /* flcword    */
+                       (void) dseg_addaddress(cd, lock_get_initial_lock_word()); /* monitorPtr */
+                       disp = dseg_addaddress(cd, NULL);                         /* vftbl      */
 
                        M_LDA(REG_ITMP3, REG_PV, disp);
                        M_AST(REG_ITMP3, REG_SP, 4 * 8);
@@ -4374,8 +4375,9 @@ u1 *createnativestub(functionptr f, jitdata *jd, methoddesc *nmd)
 #if defined(ENABLE_THREADS)
                        /* order reversed because of data segment layout */
 
-                       (void) dseg_addaddress(cd, lock_get_initial_lock_word());          /* monitorPtr */
-                       disp = dseg_addaddress(cd, NULL);                   /* vftbl      */
+                       (void) dseg_addaddress(cd, NULL);                         /* flcword    */
+                       (void) dseg_addaddress(cd, lock_get_initial_lock_word()); /* monitorPtr */
+                       disp = dseg_addaddress(cd, NULL);                         /* vftbl      */
 
                        M_LDA(REG_ITMP3, REG_PV, disp);
                        M_AST(REG_ITMP3, REG_SP, 4 * 8);
index 5dbca06f5c8ed0b56e226812893e73f6a4aa7dfc..57f99fdd29f9191caac0ef4d6fa8b8bac85b7eef 100644 (file)
@@ -31,7 +31,7 @@
             Christian Ullrich
             Edwin Steiner
 
-   $Id: codegen.c 4933 2006-05-17 12:10:25Z twisti $
+   $Id: codegen.c 4937 2006-05-18 14:33:32Z edwin $
 
 */
 
@@ -3575,8 +3575,9 @@ gen_method:
 #if defined(ENABLE_THREADS)
                        /* order reversed because of data segment layout */
 
-                       (void) dseg_addaddress(cd, lock_get_initial_lock_word());          /* monitorPtr */
-                       disp = dseg_addaddress(cd, NULL);                   /* vftbl      */
+                       (void) dseg_addaddress(cd, NULL);                         /* flcword    */
+                       (void) dseg_addaddress(cd, lock_get_initial_lock_word()); /* monitorPtr */
+                       disp = dseg_addaddress(cd, NULL);                         /* vftbl      */
 
                        M_LDA(REG_ITMP3, REG_PV, disp);
                        M_AST_INTERN(REG_ITMP3, REG_SP, 4 * 4);
@@ -4137,8 +4138,9 @@ u1 *createnativestub(functionptr f, jitdata *jd, methoddesc *nmd)
 #if defined(ENABLE_THREADS)
                        /* order reversed because of data segment layout */
 
-                       (void) dseg_addaddress(cd, lock_get_initial_lock_word());          /* monitorPtr */
-                       disp = dseg_addaddress(cd, NULL);                   /* vftbl      */
+                       (void) dseg_addaddress(cd, NULL);                         /* flcword    */
+                       (void) dseg_addaddress(cd, lock_get_initial_lock_word()); /* monitorPtr */
+                       disp = dseg_addaddress(cd, NULL);                         /* vftbl      */
 
                        M_LDA(REG_ITMP3, REG_PV, disp);
                        M_AST(REG_ITMP3, REG_SP, 4 * 4);
index 6d5b11b11dec479e9e43df8e0ddaad9f9bb35318..1910aaa3ac2aa575eaadf65cf693b065c3bd79d0 100644 (file)
@@ -30,7 +30,7 @@
    Changes: Christian Ullrich
             Edwin Steiner
 
-   $Id: codegen.c 4921 2006-05-15 14:24:36Z twisti $
+   $Id: codegen.c 4937 2006-05-18 14:33:32Z edwin $
 
 */
 
@@ -3926,8 +3926,9 @@ gen_method:
 #if defined(ENABLE_THREADS)
                        /* create a virtual java_objectheader */
 
-                       (void) dseg_addaddress(cd, lock_get_initial_lock_word());          /* monitorPtr */
-                       a = dseg_addaddress(cd, NULL);                      /* vftbl      */
+                       (void) dseg_addaddress(cd, NULL);                         /* flcword    */
+                       (void) dseg_addaddress(cd, lock_get_initial_lock_word()); /* monitorPtr */
+                       a = dseg_addaddress(cd, NULL);                            /* vftbl      */
 
                        emit_lea_membase_reg(cd, RIP, -(((ptrint) cd->mcodeptr + 7) - (ptrint) cd->mcodebase) + a, REG_ITMP3);
                        M_PUSH(REG_ITMP3);
@@ -4386,8 +4387,9 @@ u1 *createnativestub(functionptr f, jitdata *jd, methoddesc *nmd)
 #if defined(ENABLE_THREADS)
                        /* create a virtual java_objectheader */
 
-                       (void) dseg_addaddress(cd, lock_get_initial_lock_word());          /* monitorPtr */
-                       disp = dseg_addaddress(cd, NULL);                   /* vftbl      */
+                       (void) dseg_addaddress(cd, NULL);                         /* flcword    */
+                       (void) dseg_addaddress(cd, lock_get_initial_lock_word()); /* monitorPtr */
+                       disp = dseg_addaddress(cd, NULL);                         /* vftbl      */
 
                        emit_lea_membase_reg(cd, RIP, -(((ptrint) cd->mcodeptr + 7) - (ptrint) cd->mcodebase) + disp, REG_ITMP3);
                        M_PUSH(REG_ITMP3);