Index: method-wbetl.cc
===================================================================
--- method-wbetl.cc	(revision 161331)
+++ method-wbetl.cc	(working copy)
@@ -90,6 +90,7 @@ class wbetl_dispatch : public gtm_dispat
   virtual void rollback();
   virtual void reinit();
   virtual void fini();
+  virtual bool trydropreference (void *, size_t);
 };
 
 /* Check if W is one of our write locks.  */
@@ -131,6 +132,8 @@ wbetl_dispatch::validate ()
 	{
 	  w_entry *w = (w_entry *) gtm_stmlock_get_addr (l);
 
+	  // If someone has locked us, it better be by someone in the
+	  // current thread.
 	  if (!local_w_entry_p (w))
 	    return false;
 	}
@@ -521,6 +524,83 @@ wbetl_dispatch::fini ()
   delete this;
 }
 
+/* Attempt to drop any internal references to PTR.  Return TRUE if successful.
+
+   This is an adaptation of the transactional memcpy function.
+
+   What we do here is flush out the current transactional content of
+   PTR to real memory, and remove the write mask bits associated with
+   it so future commits will ignore this piece of memory.  */
+
+bool
+wbetl_dispatch::trydropreference (void *ptr, size_t size)
+{
+  if (size == 0)
+    return true;
+
+  if (!validate ())
+    return false;
+
+  uintptr_t isrc = (uintptr_t)ptr;
+  // The position in the source cacheline where *PTR starts.
+  uintptr_t sofs = isrc & (CACHELINE_SIZE - 1);
+  gtm_cacheline *src
+    = reinterpret_cast<gtm_cacheline *>(isrc & -CACHELINE_SIZE);
+  unsigned char *dst = (unsigned char *)ptr;
+  gtm_dispatch::mask_pair pair;
+
+  // If we're trying to drop a reference, we should already have a
+  // write lock on it.  If we don't have one, there's no work to do.
+  if (!gtm_stmlock_owned_p (*gtm_get_stmlock (src)))
+    return true;
+
+  // We copy the data in three stages:
+
+  // (a) Copy stray bytes at the beginning that are smaller than a
+  // cacheline.
+  if (sofs != 0)
+    {
+      size_t sleft = CACHELINE_SIZE - sofs;
+      size_t min = (size <= sleft ? size : sleft);
+
+      // WaW will give us the current locked entry.
+      pair = this->write_lock (src, WaW);
+
+      // *jedi mind wave*...these aren't the droids you're looking for.
+      *pair.mask &= ~((((gtm_cacheline_mask)1 << min) - 1) << sofs);
+
+      memcpy (dst, &pair.line->b[sofs], min);
+      dst += min;
+      src++;
+      size -= min;
+    }
+
+  // (b) Copy subsequent cacheline sized chunks.
+  while (size >= CACHELINE_SIZE)
+    {
+      pair = this->write_lock(src, WaW);
+      *pair.mask = 0;
+      memcpy (dst, src, CACHELINE_SIZE);
+      dst += CACHELINE_SIZE;
+      src++;
+      size -= CACHELINE_SIZE;
+    }
+
+  // (c) Copy anything left over.
+  if (size != 0)
+    {
+      pair = this->write_lock(src, WaW);
+      *pair.mask &= ~(((gtm_cacheline_mask)1 << size) - 1);
+      memcpy (dst, pair.line, size);
+    }
+
+  // No need to drop locks, since we're going to abort the transaction
+  // anyhow.
+
+  return true;
+}
+
+
 wbetl_dispatch::wbetl_dispatch ()
   : gtm_dispatch (false, false)
 {
Index: method-readonly.cc
===================================================================
--- method-readonly.cc	(revision 161318)
+++ method-readonly.cc	(working copy)
@@ -42,6 +42,7 @@ class readonly_dispatch : public gtm_dis
   virtual void rollback();
   virtual void reinit();
   virtual void fini();
+  virtual bool trydropreference (void *ptr, size_t size) { return true; }
 };
 
 inline
Index: alloc_c.cc
===================================================================
--- alloc_c.cc	(revision 161326)
+++ alloc_c.cc	(working copy)
@@ -61,9 +61,11 @@ _ITM_free (void *ptr)
 
 __attribute__((transaction_pure))
 void ITM_REGPARM
-_ITM_dropReferences (const void *ptr, size_t len)
+_ITM_dropReferences (void *ptr, size_t len)
 {
   gtm_transaction *tx = gtm_tx();
+  if (!gtm_disp()->trydropreference (ptr, len))
+    tx->restart (RESTART_VALIDATE_READ);
   tx->drop_references_local (ptr, len);
   tx->drop_references_allocations (ptr);
 }
Index: libitm.h
===================================================================
--- libitm.h	(revision 161326)
+++ libitm.h	(working copy)
@@ -153,7 +153,7 @@ extern void _ITM_addUserUndoAction(_ITM_
 extern int _ITM_getThreadnum(void) ITM_REGPARM;
 
 __attribute__((transaction_pure))
-extern void _ITM_dropReferences (const void *, size_t) ITM_REGPARM;
+extern void _ITM_dropReferences (void *, size_t) ITM_REGPARM;
 
 
 /* The following typedefs exist to make the macro expansions below work
Index: method-serial.cc
===================================================================
--- method-serial.cc	(revision 161318)
+++ method-serial.cc	(working copy)
@@ -64,6 +64,7 @@ class serial_dispatch : public gtm_dispa
   virtual void rollback() { abort(); }
   virtual void reinit() { }
   virtual void fini() { }
+  virtual bool trydropreference (void *ptr, size_t size) { return true; }
 };
 
 } // anon namespace
Index: testsuite/libitm.c/dropref-2.c
===================================================================
--- testsuite/libitm.c/dropref-2.c	(revision 0)
+++ testsuite/libitm.c/dropref-2.c	(revision 0)
@@ -0,0 +1,35 @@
+#include <stdlib.h>
+#include <libitm.h>
+
+/* Test that _ITM_dropReferences() forces a commit of given chunk.  */
+
+unsigned char pp[100];
+
+int main()
+{
+  int i;
+
+  for(i=0; i < 100; ++i)
+    pp[i]=0x22;
+
+  __transaction {
+    for(i=0; i < 100; ++i)
+      pp[i]=0x33;
+
+    /* This should write-through pp[0..49]...  */
+    _ITM_dropReferences (pp, 50);
+
+    /* ...while this should revert everything but pp[0..49].  */
+    __transaction_cancel;
+  }
+
+  for(i=0; i < 50; ++i)
+    if (pp[i] != 0x33)
+      abort();
+
+  for(i=50; i < 100; ++i)
+    if (pp[i] != 0x22)
+      abort();
+
+  return 0;
+}
Index: libitm_i.h
===================================================================
--- libitm_i.h	(revision 161326)
+++ libitm_i.h	(working copy)
@@ -114,6 +114,7 @@ struct gtm_dispatch
   virtual bool trycommit() = 0;
   virtual void rollback() = 0;
   virtual void reinit() = 0;
+  virtual bool trydropreference(void *, size_t) = 0;
 
   // Use fini instead of dtor to support a static subclasses that uses
   // a unique object and so we don't want to destroy it from common code.
