Boehm GC API update backport

Ivan Maidanski <[email protected]> Sat, 16 Jan 2016 15:19:35 +0300
Newsgroups gmane.comp.gcc.java.patches
Message-ID <[email protected]>
Hello,

Proposed 4 commits are code refactoring of boehm-gc (and libjava/boehm.cc, accordingly) to match API of recent BDWGC master ( https://github.com/ivmai/bdwgc ). This should simplify optional replacement of internal boehm-gcc with the external one.
All gcj tests pass.

Some of the benefits of using mainline boehm gc:
*  has no compiler warning
*  more targets supported (e.g. arm64)
*  no trouble with back-porting gc patches Similar thing was proposed for the Mono community -  https://github.com/mono/mono/pull/2247  (the patches were accepted recently)

References:
[1] The proposed patches in GCC unofficial git mirror fork -  https://github.com/ivmai/gcc/tree/match-bdwgc-api

--
Best regards,
Ivan
0001-Change-GC_set_free_space_divisor-prototy pe-in-boehm-.patch (application/x-patch, 3.6 KB)
From ba81d07864ebaba8a16afdf0e4fd9a6e22d64bee Mon Sep 17 00:00:00 2001
From: Ivan Maidanski <[email protected]>
Date: Thu, 3 Dec 2015 01:48:30 +0300
Subject: [PATCH 1/4] Change GC_set_free_space_divisor prototype in boehm-gc
 (code refactoring to match BDWGC v7 API)

boehm-gc/
    * include/gc.h (GC_set_free_space_divisor): Change return type from
    word to void.
    (GC_get_free_space_divisor): New function.
    * misc.c (GC_set_free_space_divisor): Decouple to setter and getter.

libjava/
    * boehm.cc (_Jv_SetGCFreeSpaceDivisor): Use GC_get_free_space_divisor
    to get old_div (before GC_set_free_space_divisor call).
---
 boehm-gc/ChangeLog    |  7 +++++++
 boehm-gc/include/gc.h |  6 +++---
 boehm-gc/misc.c       | 11 +++++++----
 libjava/ChangeLog     |  5 +++++
 libjava/boehm.cc      |  4 +++-
 5 files changed, 25 insertions(+), 8 deletions(-)

diff --git a/boehm-gc/ChangeLog b/boehm-gc/ChangeLog
index 365038e..1d86061 100644
--- a/boehm-gc/ChangeLog
+++ b/boehm-gc/ChangeLog
@@ -1,3 +1,10 @@
+2015-12-03  Ivan Maidanski  <[email protected]>
+
+	* include/gc.h (GC_set_free_space_divisor): Change return type from
+	word to void.
+	(GC_get_free_space_divisor): New function.
+	* misc.c (GC_set_free_space_divisor): Decouple to setter and getter.
+
 2015-10-09  David Malcolm  <[email protected]>
 
 	* testsuite/lib/boehm-gc.exp: Load multiline.exp before
diff --git a/boehm-gc/include/gc.h b/boehm-gc/include/gc.h
index 6b38f2d..d02dab2 100644
--- a/boehm-gc/include/gc.h
+++ b/boehm-gc/include/gc.h
@@ -803,9 +803,9 @@ typedef void (*GC_warn_proc) GC_PROTO((char *msg, GC_word arg));
 GC_API GC_warn_proc GC_set_warn_proc GC_PROTO((GC_warn_proc p));
     /* Returns old warning procedure.	*/
 
-GC_API GC_word GC_set_free_space_divisor GC_PROTO((GC_word value));
-    /* Set free_space_divisor.  See above for definition.	*/
-    /* Returns old value.					*/
+GC_API void GC_set_free_space_divisor GC_PROTO((GC_word value));
+GC_API GC_word GC_get_free_space_divisor GC_PROTO((void));
+    /* Set and get free_space_divisor.  See above for the definition.	*/
 	
 /* The following is intended to be used by a higher level	*/
 /* (e.g. Java-like) finalization facility.  It is expected	*/
diff --git a/boehm-gc/misc.c b/boehm-gc/misc.c
index 069c7d5..c1faed0 100644
--- a/boehm-gc/misc.c
+++ b/boehm-gc/misc.c
@@ -1048,15 +1048,18 @@ GC_warn_proc GC_current_warn_proc = GC_default_warn_proc;
 }
 
 # if defined(__STDC__) || defined(__cplusplus)
-    GC_word GC_set_free_space_divisor (GC_word value)
+    void GC_set_free_space_divisor (GC_word value)
 # else
-    GC_word GC_set_free_space_divisor (value)
+    void GC_set_free_space_divisor (value)
     GC_word value;
 # endif
 {
-    GC_word old = GC_free_space_divisor;
     GC_free_space_divisor = value;
-    return old;
+}
+
+GC_word GC_get_free_space_divisor GC_PROTO((void))
+{
+    return GC_free_space_divisor;
 }
 
 #ifndef PCR
diff --git a/libjava/ChangeLog b/libjava/ChangeLog
index 0d75195..954b1a1 100644
--- a/libjava/ChangeLog
+++ b/libjava/ChangeLog
@@ -1,3 +1,8 @@
+2015-12-03  Ivan Maidanski  <[email protected]>
+
+	* boehm.cc (_Jv_SetGCFreeSpaceDivisor): Use GC_get_free_space_divisor
+	to get old_div (before GC_set_free_space_divisor call).
+
 2015-07-24  Michael Darling  <[email protected]>
 
 	PR other/66259
diff --git a/libjava/boehm.cc b/libjava/boehm.cc
index 043fd00..34a6ead 100644
--- a/libjava/boehm.cc
+++ b/libjava/boehm.cc
@@ -468,7 +468,9 @@ _Jv_GCSetMaximumHeapSize (size_t size)
 int
 _Jv_SetGCFreeSpaceDivisor (int div)
 {
-  return (int)GC_set_free_space_divisor ((GC_word)div);
+  int old_div = (int)GC_get_free_space_divisor ();
+  GC_set_free_space_divisor ((GC_word)div);
+  return old_div;
 }
 
 void
-- 
2.1.4
0002-Move-extern-C-from-boehm.cc-to-boehm-gc- header-files.patch (application/x-patch, 8.3 KB)
From 965937dc482db1417ee3e00db6fe911216ab4b4d Mon Sep 17 00:00:00 2001
From: Ivan Maidanski <[email protected]>
Date: Sat, 5 Dec 2015 19:28:20 +0300
Subject: [PATCH 2/4] Move 'extern C' from boehm.cc to boehm-gc header files;
 avoid explicit include gc_local_alloc.h from boehm.cc; remove
 GC_enable/disable duplicate prototyping (code refactoring to match BDWGC v7
 API)

boehm-gc/
    * include/gc.h (GC_suspend_thread, GC_resume_thread,
    GC_is_thread_suspended): Move inside 'extern "C"' block.
    [GC_REDIRECT_TO_LOCAL]: Include gc_local_alloc.h outside 'extern "C"'
    block; do not include gc_local_alloc.h if gc.h is included from
    gc_gcj.h (so that GC_[LOCAL_]GCJ_MALLOC to be defined after other GCJ
    symbols).
    * include/gc_gcj.h [__cplusplus]: Wrap all declarations into
    'extern "C"' block.
    * include/gc_local_alloc.h [__cplusplus]: Likewise.
    * include/javaxfc.h [__cplusplus]: Likewise.
    * include/gc_gcj.h [GC_REDIRECT_TO_LOCAL]: Include gc_local_alloc.h.

libjava/
    * boehm.cc (GC_enable, GC_disable): Remove prototype (as declared in
    boehm-gc/include/gc.h).
    [THREAD_LOCAL_ALLOC] (GC_REDIRECT_TO_LOCAL): Define before include
    gc_gcj.h file.
    * boehm.cc: Remove 'extern "C"' for included boehm-gc/include header
    files (they are properly decorated inside now); remove include
    "gc_local_alloc.h" (as it is implicitly included now by
    boehm-gc/include/gc_gcj.h); include "gc_gcj.h" before any other
    boehm-gc header file (to let GC_GCJ_MALLOC be properly redefined to
    a thread-local allocator in boehm-gc/include/gc_local_alloc.h).
---
 boehm-gc/ChangeLog                | 14 ++++++++++++++
 boehm-gc/include/gc.h             | 22 ++++++++++++++--------
 boehm-gc/include/gc_gcj.h         | 12 ++++++++++++
 boehm-gc/include/gc_local_alloc.h |  8 ++++++++
 boehm-gc/include/gc_mark.h        |  9 ++++++++-
 boehm-gc/include/javaxfc.h        |  8 +++++++-
 libjava/ChangeLog                 | 13 +++++++++++++
 libjava/boehm.cc                  | 14 +++-----------
 8 files changed, 79 insertions(+), 21 deletions(-)

diff --git a/boehm-gc/ChangeLog b/boehm-gc/ChangeLog
index 1d86061..9988605 100644
--- a/boehm-gc/ChangeLog
+++ b/boehm-gc/ChangeLog
@@ -1,3 +1,17 @@
+2015-12-05  Ivan Maidanski  <[email protected]>
+
+	* include/gc.h (GC_suspend_thread, GC_resume_thread,
+	GC_is_thread_suspended): Move inside 'extern "C"' block.
+	[GC_REDIRECT_TO_LOCAL]: Include gc_local_alloc.h outside 'extern "C"'
+	block; do not include gc_local_alloc.h if gc.h is included from
+	gc_gcj.h (so that GC_[LOCAL_]GCJ_MALLOC to be defined after other GCJ
+	symbols).
+	* include/gc_gcj.h [__cplusplus]: Wrap all declarations into
+	'extern "C"' block.
+	* include/gc_local_alloc.h [__cplusplus]: Likewise.
+	* include/javaxfc.h [__cplusplus]: Likewise.
+	* include/gc_gcj.h [GC_REDIRECT_TO_LOCAL]: Include gc_local_alloc.h.
+
 2015-12-03  Ivan Maidanski  <[email protected]>
 
 	* include/gc.h (GC_set_free_space_divisor): Change return type from
diff --git a/boehm-gc/include/gc.h b/boehm-gc/include/gc.h
index d02dab2..f193065 100644
--- a/boehm-gc/include/gc.h
+++ b/boehm-gc/include/gc.h
@@ -1061,14 +1061,6 @@ GC_API void GC_register_has_static_roots_callback
 # include "gc_amiga_redirects.h"
 #endif
 
-#if defined(GC_REDIRECT_TO_LOCAL) && !defined(GC_LOCAL_ALLOC_H)
-#  include  "gc_local_alloc.h"
-#endif
-
-#ifdef __cplusplus
-    }  /* end of extern "C" */
-#endif
-
 /* External thread suspension support. These functions do not implement
  * suspension counts or any other higher-level abstraction. Threads which
  * have been suspended numerous times will resume with the very first call
@@ -1080,4 +1072,18 @@ GC_API void GC_suspend_thread GC_PROTO((pthread_t));
 GC_API void GC_resume_thread GC_PROTO((pthread_t));
 GC_API int GC_is_thread_suspended GC_PROTO((pthread_t));
 #endif
+
+#ifdef __cplusplus
+    } /* end of extern "C" */
+#endif
+
+#if defined(GC_REDIRECT_TO_LOCAL) && !defined(GC_LOCAL_ALLOC_H) \
+    && !defined(GC_GCJ_H)
+  /* In case of gc.h is included from gc_gcj.h file, gc_local_alloc.h	*/
+  /* should be included at the end of gc_gcj.h instead of gc.h to have	*/
+  /* all GCJ symbols defined before some of them are redefined to	*/
+  /* their thread-local counterparts.					*/
+# include "gc_local_alloc.h"
+#endif
+
 #endif /* _GC_H */
diff --git a/boehm-gc/include/gc_gcj.h b/boehm-gc/include/gc_gcj.h
index 5e79e27..b771734 100644
--- a/boehm-gc/include/gc_gcj.h
+++ b/boehm-gc/include/gc_gcj.h
@@ -44,6 +44,10 @@
 #   include "gc.h"
 #endif
 
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
 /* The following allocators signal an out of memory condition with	*/
 /* return GC_oom_fn(bytes);						*/
 
@@ -110,4 +114,12 @@ extern int GC_gcj_debug_kind;
 	GC_gcj_malloc_ignore_off_page(s,d)
 # endif
 
+#ifdef __cplusplus
+  } /* end of extern "C" */
+#endif
+
+#if defined(GC_REDIRECT_TO_LOCAL)
+# include "gc_local_alloc.h"
+#endif
+
 #endif /* GC_GCJ_H */
diff --git a/boehm-gc/include/gc_local_alloc.h b/boehm-gc/include/gc_local_alloc.h
index 1874c7b..e4fe205 100644
--- a/boehm-gc/include/gc_local_alloc.h
+++ b/boehm-gc/include/gc_local_alloc.h
@@ -49,6 +49,10 @@
 #   include "gc_gcj.h"
 #endif
 
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
 /* We assume ANSI C for this interface.	*/
 
 GC_PTR GC_local_malloc(size_t bytes);
@@ -86,4 +90,8 @@ GC_PTR GC_local_malloc_atomic(size_t bytes);
 #   endif
 # endif
 
+#ifdef __cplusplus
+  } /* end of extern "C" */
+#endif
+
 #endif /* GC_LOCAL_ALLOC_H */
diff --git a/boehm-gc/include/gc_mark.h b/boehm-gc/include/gc_mark.h
index 953bb74..7c92946 100644
--- a/boehm-gc/include/gc_mark.h
+++ b/boehm-gc/include/gc_mark.h
@@ -29,6 +29,10 @@
 #   include "gc.h"
 # endif
 
+# ifdef __cplusplus
+    extern "C" {
+# endif
+
 /* A client supplied mark procedure.  Returns new mark stack pointer.	*/
 /* Primary effect should be to push new entries on the mark stack.	*/
 /* Mark stack pointer values are passed and returned explicitly.	*/
@@ -199,5 +203,8 @@ void GC_register_describe_type_fn GC_PROTO((int kind, GC_describe_type_fn knd));
 				/* to be used when printing objects	*/
 				/* of a particular kind.		*/
 
-#endif  /* GC_MARK_H */
+# ifdef __cplusplus
+    } /* end of extern "C" */
+# endif
 
+#endif  /* GC_MARK_H */
diff --git a/boehm-gc/include/javaxfc.h b/boehm-gc/include/javaxfc.h
index 23e0100..669ba64 100644
--- a/boehm-gc/include/javaxfc.h
+++ b/boehm-gc/include/javaxfc.h
@@ -2,6 +2,10 @@
 #   include "gc.h"
 # endif
 
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
 /*
  * Invoke all remaining finalizers that haven't yet been run.
  * This is needed for strict compliance with the Java standard, 
@@ -18,4 +22,6 @@
  */
 void GC_finalize_all();
 
-
+#ifdef __cplusplus
+  } /* end of extern "C" */
+#endif
diff --git a/libjava/ChangeLog b/libjava/ChangeLog
index 954b1a1..d581c8f 100644
--- a/libjava/ChangeLog
+++ b/libjava/ChangeLog
@@ -1,3 +1,16 @@
+2015-12-05  Ivan Maidanski  <[email protected]>
+
+	* boehm.cc (GC_enable, GC_disable): Remove prototype (as declared in
+	boehm-gc/include/gc.h).
+	[THREAD_LOCAL_ALLOC] (GC_REDIRECT_TO_LOCAL): Define before include
+	gc_gcj.h file.
+	* boehm.cc: Remove 'extern "C"' for included boehm-gc/include header
+	files (they are properly decorated inside now); remove include
+	"gc_local_alloc.h" (as it is implicitly included now by
+	boehm-gc/include/gc_gcj.h); include "gc_gcj.h" before any other
+	boehm-gc header file (to let GC_GCJ_MALLOC be properly redefined to
+	a thread-local allocator in boehm-gc/include/gc_local_alloc.h).
+
 2015-12-03  Ivan Maidanski  <[email protected]>
 
 	* boehm.cc (_Jv_SetGCFreeSpaceDivisor): Use GC_get_free_space_divisor
diff --git a/libjava/boehm.cc b/libjava/boehm.cc
index 34a6ead..39563f0 100644
--- a/libjava/boehm.cc
+++ b/libjava/boehm.cc
@@ -38,8 +38,6 @@ details.  */
 #include <dlfcn.h>
 #endif
 
-extern "C"
-{
 #include <gc_config.h>
 
 // Set GC_DEBUG before including gc.h!
@@ -47,19 +45,13 @@ extern "C"
 # define GC_DEBUG
 #endif
 
-#include <gc_mark.h>
-#include <gc_gcj.h>
-#include <javaxfc.h>  // GC_finalize_all declaration.  
-
 #ifdef THREAD_LOCAL_ALLOC
 # define GC_REDIRECT_TO_LOCAL
-# include <gc_local_alloc.h>
 #endif
+#include <gc_gcj.h> // includes gc.h and gc_local_alloc.h
 
-  // From boehm's misc.c 
-  void GC_enable();
-  void GC_disable();
-};
+#include <gc_mark.h>
+#include <javaxfc.h>  // GC_finalize_all declaration.
 
 #define MAYBE_MARK(Obj, Top, Limit, Source)  \
 	Top=GC_MARK_AND_PUSH((GC_PTR) Obj, Top, Limit, (GC_PTR *) Source)
-- 
2.1.4
0004-Change-GC_-un-register_my_thread-prototy pes-in-boehm.patch (application/x-patch, 9.2 KB)
From 1dd69df15093a51485da80043d243e470d5ab9da Mon Sep 17 00:00:00 2001
From: Ivan Maidanski <[email protected]>
Date: Thu, 17 Dec 2015 00:51:21 +0300
Subject: [PATCH 4/4] Change GC_[un]register_my_thread prototypes in boehm-gc
 (code refactoring to match BDWGC v7 API)

boehm-gc/
    * include/gc.h (GC_DUPLICATE): New public macro.
    (GC_register_my_thread): Change prototype (accept GC_stack_base*).
    (GC_register_my_thread, GC_unregister_my_thread): Change prototype
    (return operation completion status); update comment.
    * pthread_support.c (GC_register_my_thread): Change prototype; change
    "sb" type to pointer; do not call GC_get_stack_base (it is called by
    GC_register_my_thread caller now); return GC_DUPLICATE or GC_SUCCESS.
    (GC_unregister_my_thread): Change prototype; return GC_SUCCESS.
    * win32_threads.c (GC_register_my_thread, GC_unregister_my_thread):
    New function (stub returning GC_DUPLICATE if threads are registered
    implicitly otherwise GC_UNIMPLEMENTED).

libjava/
    * boehm.cc (_Jv_GCAttachThread, _Jv_GCDetachThread): Do not test
    HAVE_PTHREAD_GETATTR_NP and GC_SOLARIS_THREADS macros, test
    GC_PTHREADS macro instead (i.e., invoke GC thread register/unregister
    for all multi-threaded targets); remove the relevant comment.
    (_Jv_GCAttachThread): Declare "sb" local variable; invoke
    GC_get_stack_base (pass obtained stack base to GC_register_my_thread);
    call JvFail with the appropriate message in case of GC_get_stack_base
    or GC_register_my_thread failure (but handle properly the case when
    GC_get_stack_base returns GC_UNIMPLEMENTED but the thread is already
    registered implicitly).
---
 boehm-gc/ChangeLog         | 14 ++++++++++++++
 boehm-gc/include/gc.h      | 15 +++++++--------
 boehm-gc/pthread_support.c | 17 +++++++----------
 boehm-gc/win32_threads.c   | 17 +++++++++++++++++
 libjava/ChangeLog          | 13 +++++++++++++
 libjava/boehm.cc           | 22 ++++++++++++++--------
 6 files changed, 72 insertions(+), 26 deletions(-)

diff --git a/boehm-gc/ChangeLog b/boehm-gc/ChangeLog
index 35bd442..4253b94 100644
--- a/boehm-gc/ChangeLog
+++ b/boehm-gc/ChangeLog
@@ -1,3 +1,17 @@
+2015-12-17  Ivan Maidanski  <[email protected]>
+
+	* include/gc.h (GC_DUPLICATE): New public macro.
+	(GC_register_my_thread): Change prototype (accept GC_stack_base*).
+	(GC_register_my_thread, GC_unregister_my_thread): Change prototype
+	(return operation completion status); update comment.
+	* pthread_support.c (GC_register_my_thread): Change prototype; change
+	"sb" type to pointer; do not call GC_get_stack_base (it is called by
+	GC_register_my_thread caller now); return GC_DUPLICATE or GC_SUCCESS.
+	(GC_unregister_my_thread): Change prototype; return GC_SUCCESS.
+	* win32_threads.c (GC_register_my_thread, GC_unregister_my_thread):
+	New function (stub returning GC_DUPLICATE if threads are registered
+	implicitly otherwise GC_UNIMPLEMENTED).
+
 2015-12-10  Ivan Maidanski  <[email protected]>
 
 	* AmigaOS.c (GC_get_stack_base): Rename to GC_get_main_stack_base.
diff --git a/boehm-gc/include/gc.h b/boehm-gc/include/gc.h
index 6ba20e6..99adedd 100644
--- a/boehm-gc/include/gc.h
+++ b/boehm-gc/include/gc.h
@@ -935,6 +935,7 @@ struct GC_stack_base {
 };
 
 #define GC_SUCCESS 0
+#define GC_DUPLICATE 1		/* Was already registered.		*/
 #define GC_UNIMPLEMENTED 3	/* Not yet implemented on the platform.	*/
 
 /* Attempt to fill in the GC_stack_base structure with the stack base	*/
@@ -954,15 +955,13 @@ GC_API int GC_get_stack_base GC_PROTO((struct GC_stack_base *));
 /* a thread can allocate garbage collected memory, or assign pointers	*/
 /* to the garbage collected heap.  Once registered, a thread will be	*/
 /* stopped during garbage collections.					*/
-GC_API void GC_register_my_thread GC_PROTO((void));
+/* Returns GC_SUCCESS on success, GC_DUPLICATE if already done. 	*/
+/* On some platforms it returns GC_UNIMPLEMENTED.			*/
+GC_API int GC_register_my_thread GC_PROTO((struct GC_stack_base *));
 
-/* Register the current thread, with the indicated stack base, as	*/
-/* a new thread whose stack(s) should be traced by the GC.  If a 	*/
-/* platform does not implicitly do so, this must be called before a	*/
-/* thread can allocate garbage collected memory, or assign pointers	*/
-/* to the garbage collected heap.  Once registered, a thread will be	*/
-/* stopped during garbage collections.					*/
-GC_API void GC_unregister_my_thread GC_PROTO((void));
+/* Unregister the current thread.					*/
+/* Returns GC_SUCCESS or GC_UNIMPLEMENTED.				*/
+GC_API int GC_unregister_my_thread GC_PROTO((void));
 
 /* This returns a list of objects, linked through their first		*/
 /* word.  Its use can greatly reduce lock contention problems, since	*/
diff --git a/boehm-gc/pthread_support.c b/boehm-gc/pthread_support.c
index e077abb..acb1a55 100644
--- a/boehm-gc/pthread_support.c
+++ b/boehm-gc/pthread_support.c
@@ -1170,15 +1170,10 @@ int GC_get_stack_base(struct GC_stack_base *sb)
 # endif
 }
 
-void GC_register_my_thread()
+int GC_register_my_thread(struct GC_stack_base *sb)
 {
   GC_thread me;
   pthread_t my_pthread;
-# if !defined(GC_DARWIN_THREADS) || defined(IA64)
-    struct GC_stack_base sb;
-    if (GC_get_stack_base(&sb) == GC_UNIMPLEMENTED)
-      ABORT("Can not determine stack base for attached thread");
-# endif
 
   my_pthread = pthread_self();
 #   ifdef DEBUG_THREADS
@@ -1195,7 +1190,7 @@ void GC_register_my_thread()
 #   ifdef DEBUG_THREADS
       GC_printf1("Attempt to re-attach known thread 0x%lx\n", my_pthread);
 #   endif
-      return;
+      return GC_DUPLICATE;
     }
 
   LOCK();
@@ -1208,7 +1203,7 @@ void GC_register_my_thread()
 #ifdef GC_DARWIN_THREADS
     me -> stop_info.mach_thread = mach_thread_self();
 #else
-    me -> stack_end = sb.mem_base;
+    me -> stack_end = sb -> mem_base;
     
 #   ifdef STACK_GROWS_DOWN
       me -> stop_info.stack_ptr = me -> stack_end - 0x10;
@@ -1218,16 +1213,17 @@ void GC_register_my_thread()
 #endif
 
 #   ifdef IA64
-      me -> backing_store_end = sb.reg_base;
+      me -> backing_store_end = sb -> reg_base;
 #   endif /* IA64 */
 
 #   if defined(THREAD_LOCAL_ALLOC) && !defined(DBG_HDRS_ALL)
         GC_init_thread_local(me);
 #   endif
   UNLOCK();
+  return GC_SUCCESS;
 }
 
-void GC_unregister_my_thread()
+int GC_unregister_my_thread GC_PROTO((void))
 {
   pthread_t my_pthread;
 
@@ -1238,6 +1234,7 @@ void GC_unregister_my_thread()
 #   endif
 
   GC_thread_exit_proc (0);
+  return GC_SUCCESS;
 }
 
 void * GC_start_routine(void * arg)
diff --git a/boehm-gc/win32_threads.c b/boehm-gc/win32_threads.c
index 354e5a7..a32bf8d 100644
--- a/boehm-gc/win32_threads.c
+++ b/boehm-gc/win32_threads.c
@@ -527,6 +527,23 @@ static DWORD WINAPI thread_start(LPVOID arg)
 
 #endif /* !CYGWIN32 */
 
+int GC_register_my_thread(struct GC_stack_base *sb)
+{
+#   if defined(GC_DLL) && !defined(CYGWIN32) && !defined(MSWINCE)
+	/* Registered by DllMain. */
+	return GC_DUPLICATE;
+#   else
+	/* TODO: Implement. */
+	return GC_UNIMPLEMENTED;
+#   endif
+}
+
+int GC_unregister_my_thread GC_PROTO((void))
+{
+    /* TODO: Implement. */
+    return GC_UNIMPLEMENTED;
+}
+
 #ifdef MSWINCE
 
 typedef struct {
diff --git a/libjava/ChangeLog b/libjava/ChangeLog
index d581c8f..5da8df1 100644
--- a/libjava/ChangeLog
+++ b/libjava/ChangeLog
@@ -1,3 +1,16 @@
+2015-12-17  Ivan Maidanski  <[email protected]>
+
+	* boehm.cc (_Jv_GCAttachThread, _Jv_GCDetachThread): Do not test
+	HAVE_PTHREAD_GETATTR_NP and GC_SOLARIS_THREADS macros, test
+	GC_PTHREADS macro instead (i.e., invoke GC thread register/unregister
+	for all multi-threaded targets); remove the relevant comment.
+	(_Jv_GCAttachThread): Declare "sb" local variable; invoke
+	GC_get_stack_base (pass obtained stack base to GC_register_my_thread);
+	call JvFail with the appropriate message in case of GC_get_stack_base
+	or GC_register_my_thread failure (but handle properly the case when
+	GC_get_stack_base returns GC_UNIMPLEMENTED but the thread is already
+	registered implicitly).
+
 2015-12-05  Ivan Maidanski  <[email protected]>
 
 	* boehm.cc (GC_enable, GC_disable): Remove prototype (as declared in
diff --git a/libjava/boehm.cc b/libjava/boehm.cc
index 39563f0..4ec91af 100644
--- a/libjava/boehm.cc
+++ b/libjava/boehm.cc
@@ -738,20 +738,26 @@ _Jv_IsThreadSuspended (_Jv_Thread_t *thread)
 void
 _Jv_GCAttachThread ()
 {
-  // The registration interface is only defined on posixy systems and
-  // only actually works if pthread_getattr_np is defined.
-  // FIXME: until gc7 it is simpler to disable this on solaris.
-#if defined(HAVE_PTHREAD_GETATTR_NP) && !defined(GC_SOLARIS_THREADS) \
-    && !defined(GC_WIN32_THREADS)
-  GC_register_my_thread ();
+#if defined(GC_PTHREADS) || defined(GC_WIN32_THREADS)
+  struct GC_stack_base sb;
+
+  if (GC_get_stack_base (&sb) == GC_UNIMPLEMENTED)
+    {
+      // Do not fail in case of implicitly registered threads.
+      sb.mem_base = &sb;
+      if (GC_register_my_thread (&sb) != GC_DUPLICATE)
+        JvFail ("Cannot determine stack base for attached thread");
+      return;
+    }
+  if (GC_register_my_thread (&sb) == GC_UNIMPLEMENTED)
+    JvFail ("Cannot attach thread");
 #endif
 }
 
 void
 _Jv_GCDetachThread ()
 {
-#if defined(HAVE_PTHREAD_GETATTR_NP) && !defined(GC_SOLARIS_THREADS) \
-    && !defined(GC_WIN32_THREADS)
+#if defined(GC_PTHREADS) || defined(GC_WIN32_THREADS)
   GC_unregister_my_thread ();
 #endif
 }
-- 
2.1.4
0003-Change-GC_get_-thread-main_-stack_base-p rototypes.patch (application/x-patch, 16 KB)
From 8bc263a68ac3d99c2ce80acc4bdfb9b37d2ecfd5 Mon Sep 17 00:00:00 2001
From: Ivan Maidanski <[email protected]>
Date: Thu, 10 Dec 2015 21:46:54 +0300
Subject: [PATCH 3/4] Change GC_get_[thread/main_]stack_base prototypes (code
 refactoring to match BDWGC v7 API)

GC_get_stack_base renamed to GC_get_main_stack_base;
ptr_t GC_get_thread_stack_base() public prototype changed to
int GC_get_stack_base(struct GC_stack_base*);
GC_get_stack_base now defined for all targets (but returns
GC_UNIMPLEMENTED if no implementation for the target).

boehm-gc/
    * AmigaOS.c (GC_get_stack_base): Rename to GC_get_main_stack_base.
    * include/private/gc_priv.h (GC_get_stack_base): Likewise.
    * include/gc.h (struct GC_stack_base): New public type.
    (GC_SUCCESS, GC_UNIMPLEMENTED): New public macro.
    (GC_get_thread_stack_base): Replace with
    int GC_get_stack_base(struct GC_stack_base*); declare even in
    a single-threaded case; refine comment.
    * misc.c (GC_init_inner): Rename GC_get_stack_base to
    GC_get_main_stack_base.
    (GC_init_inner): Replace GC_get_thread_stack_base to
    GC_get_stack_base.
    * win32_threads.c [CYGWIN32] (GC_get_thread_stack_base): Likewise.
    * os_dep.c [MSWIN32 || MSWINCE || BEOS || OS2] (GC_get_stack_base):
    Accommodate to GC_get_stack_base prototype change.
    * win32_threads.c (GC_new_thread): Likewise.
    * os_dep.c (HAVE_GET_STACK_BASE): Define in every case when
    target-specific GC_get_stack_base is defined (including for cases
    when GC_get_stack_base is pthread_support.c or win32_threads.c).
    (GC_get_stack_base): Rename to GC_get_main_stack_base (except for
    Win32, WinCE, BeOS and OS/2).
    (GET_MAIN_STACKBASE_SPECIAL): Define in every case when
    target-specific GC_get_main_stack_base is defined.
    [!HAVE_GET_STACK_BASE] (GC_get_stack_base): Define with the default
    implementation.
    [!GET_MAIN_STACKBASE_SPECIAL] (GC_get_main_stack_base): Likewise.
    * pthread_support.c (GC_get_thread_stack_base): Replace to
    GC_get_stack_base; set reg_base for IA64.
    [!GC_DARWIN_THREADS] (GC_register_my_thread): Call GC_get_stack_base
    instead of GC_get_thread_stack_base and GC_save_regs_in_stack.
---
 boehm-gc/AmigaOS.c                 |  4 +--
 boehm-gc/ChangeLog                 | 32 +++++++++++++++++++
 boehm-gc/include/gc.h              | 20 ++++++++++--
 boehm-gc/include/private/gc_priv.h |  2 +-
 boehm-gc/misc.c                    |  8 +++--
 boehm-gc/os_dep.c                  | 63 ++++++++++++++++++++++++++++++++------
 boehm-gc/pthread_support.c         | 30 ++++++++++--------
 boehm-gc/win32_threads.c           | 14 +++++----
 8 files changed, 139 insertions(+), 34 deletions(-)

diff --git a/boehm-gc/AmigaOS.c b/boehm-gc/AmigaOS.c
index f4024a7..b76f446 100644
--- a/boehm-gc/AmigaOS.c
+++ b/boehm-gc/AmigaOS.c
@@ -40,7 +40,7 @@
    Find the base of the stack.
 ******************************************************************/
 
-ptr_t GC_get_stack_base()
+ptr_t GC_get_main_stack_base()
 {
     struct Process *proc = (struct Process*)SysBase->ThisTask;
  
@@ -58,7 +58,7 @@ ptr_t GC_get_stack_base()
 }
 
 #if 0 /* old version */
-ptr_t GC_get_stack_base()
+ptr_t GC_get_main_stack_base()
 {
     extern struct WBStartup *_WBenchMsg;
     extern long __base;
diff --git a/boehm-gc/ChangeLog b/boehm-gc/ChangeLog
index 9988605..35bd442 100644
--- a/boehm-gc/ChangeLog
+++ b/boehm-gc/ChangeLog
@@ -1,3 +1,35 @@
+2015-12-10  Ivan Maidanski  <[email protected]>
+
+	* AmigaOS.c (GC_get_stack_base): Rename to GC_get_main_stack_base.
+	* include/private/gc_priv.h (GC_get_stack_base): Likewise.
+	* include/gc.h (struct GC_stack_base): New public type.
+	(GC_SUCCESS, GC_UNIMPLEMENTED): New public macro.
+	(GC_get_thread_stack_base): Replace with
+	int GC_get_stack_base(struct GC_stack_base*); declare even in
+	a single-threaded case; refine comment.
+	* misc.c (GC_init_inner): Rename GC_get_stack_base to
+	GC_get_main_stack_base.
+	(GC_init_inner): Replace GC_get_thread_stack_base to
+	GC_get_stack_base.
+	* win32_threads.c [CYGWIN32] (GC_get_thread_stack_base): Likewise.
+	* os_dep.c [MSWIN32 || MSWINCE || BEOS || OS2] (GC_get_stack_base):
+	Accommodate to GC_get_stack_base prototype change.
+	* win32_threads.c (GC_new_thread): Likewise.
+	* os_dep.c (HAVE_GET_STACK_BASE): Define in every case when
+	target-specific GC_get_stack_base is defined (including for cases
+	when GC_get_stack_base is pthread_support.c or win32_threads.c).
+	(GC_get_stack_base): Rename to GC_get_main_stack_base (except for
+	Win32, WinCE, BeOS and OS/2).
+	(GET_MAIN_STACKBASE_SPECIAL): Define in every case when
+	target-specific GC_get_main_stack_base is defined.
+	[!HAVE_GET_STACK_BASE] (GC_get_stack_base): Define with the default
+	implementation.
+	[!GET_MAIN_STACKBASE_SPECIAL] (GC_get_main_stack_base): Likewise.
+	* pthread_support.c (GC_get_thread_stack_base): Replace to
+	GC_get_stack_base; set reg_base for IA64.
+	[!GC_DARWIN_THREADS] (GC_register_my_thread): Call GC_get_stack_base
+	instead of GC_get_thread_stack_base and GC_save_regs_in_stack.
+
 2015-12-05  Ivan Maidanski  <[email protected]>
 
 	* include/gc.h (GC_suspend_thread, GC_resume_thread,
diff --git a/boehm-gc/include/gc.h b/boehm-gc/include/gc.h
index f193065..6ba20e6 100644
--- a/boehm-gc/include/gc.h
+++ b/boehm-gc/include/gc.h
@@ -926,6 +926,24 @@ GC_API void (*GC_is_visible_print_proc)
 # include "gc_pthread_redirects.h"
 #endif
 
+/* Structure representing the base of a thread stack.			*/
+struct GC_stack_base {
+    void * mem_base; /* Base of memory stack. */
+#   if defined(__ia64) || defined(__ia64__) || defined(_M_IA64)
+	void * reg_base; /* Base of separate register stack. */
+#   endif
+};
+
+#define GC_SUCCESS 0
+#define GC_UNIMPLEMENTED 3	/* Not yet implemented on the platform.	*/
+
+/* Attempt to fill in the GC_stack_base structure with the stack base	*/
+/* for this thread.  This appears to be required to implement anything	*/
+/* like the JNI AttachCurrentThread in an environment in which new	*/
+/* threads are not automatically registered with the collector. 	*/
+/* Returns GC_SUCCESS or GC_UNIMPLEMENTED.				*/
+GC_API int GC_get_stack_base GC_PROTO((struct GC_stack_base *));
+
 # if defined(PCR) || defined(GC_SOLARIS_THREADS) || \
      defined(GC_PTHREADS) || defined(GC_WIN32_THREADS)
    	/* Any flavor of threads except SRC_M3.	*/
@@ -946,8 +964,6 @@ GC_API void GC_register_my_thread GC_PROTO((void));
 /* stopped during garbage collections.					*/
 GC_API void GC_unregister_my_thread GC_PROTO((void));
 
-GC_API GC_PTR GC_get_thread_stack_base GC_PROTO((void));
-
 /* This returns a list of objects, linked through their first		*/
 /* word.  Its use can greatly reduce lock contention problems, since	*/
 /* the allocation lock can be acquired and released many fewer times.	*/
diff --git a/boehm-gc/include/private/gc_priv.h b/boehm-gc/include/private/gc_priv.h
index 4dbfa7d..a6fda46 100644
--- a/boehm-gc/include/private/gc_priv.h
+++ b/boehm-gc/include/private/gc_priv.h
@@ -1493,7 +1493,7 @@ GC_bool GC_register_main_static_data GC_PROTO((void));
 		/* dynamic library registration.			*/
   
 /* Machine dependent startup routines */
-ptr_t GC_get_stack_base GC_PROTO((void));	/* Cold end of stack */
+ptr_t GC_get_main_stack_base GC_PROTO((void));	/* Cold end of stack */
 #ifdef IA64
   ptr_t GC_get_register_stack_base GC_PROTO((void));
   					/* Cold end of register stack.	*/
diff --git a/boehm-gc/misc.c b/boehm-gc/misc.c
index c1faed0..0f4edff 100644
--- a/boehm-gc/misc.c
+++ b/boehm-gc/misc.c
@@ -677,10 +677,14 @@ void GC_init_inner()
         # if defined(GC_PTHREADS) && ! defined(GC_SOLARIS_THREADS)
 	/* Use thread_stack_base if available, as GC could be initialized from
 	   a thread that is not the "main" thread.  */
-	GC_stackbottom = GC_get_thread_stack_base();
+	  struct GC_stack_base sb;
+	  sb.mem_base = NULL;
+	  (void)GC_get_stack_base(&sb);
+		/* In case of failure, mem_base remains NULL.		*/
+	  GC_stackbottom = sb.mem_base;
 	# endif
 	if (GC_stackbottom == 0)
-	  GC_stackbottom = GC_get_stack_base();
+	  GC_stackbottom = GC_get_main_stack_base();
 #       if (defined(LINUX) || defined(HPUX)) && defined(IA64)
 	  GC_register_stackbottom = GC_get_register_stack_base();
 #       endif
diff --git a/boehm-gc/os_dep.c b/boehm-gc/os_dep.c
index 60cbc2b..f8da082 100644
--- a/boehm-gc/os_dep.c
+++ b/boehm-gc/os_dep.c
@@ -639,42 +639,53 @@ word GC_get_writable_length(ptr_t p, ptr_t *base)
     return(buf.RegionSize);
 }
 
-ptr_t GC_get_stack_base()
+int GC_get_stack_base(struct GC_stack_base *sb)
 {
     int dummy;
     ptr_t sp = (ptr_t)(&dummy);
     ptr_t trunc_sp = (ptr_t)((word)sp & ~(GC_page_size - 1));
     word size = GC_get_writable_length(trunc_sp, 0);
    
-    return(trunc_sp + size);
+    sb -> mem_base = trunc_sp + size;
+    return GC_SUCCESS;
 }
+#   define HAVE_GET_STACK_BASE
 
+# elif defined(CYGWIN32) && defined(GC_WIN32_THREADS)
+
+    /* GC_get_stack_base() is defined in win32_threads.c.	*/
+#   define HAVE_GET_STACK_BASE
 
 # endif /* MS Windows */
 
 # ifdef BEOS
 # include <kernel/OS.h>
-ptr_t GC_get_stack_base(){
+int GC_get_stack_base(struct GC_stack_base *sb)
+{
 	thread_info th;
 	get_thread_info(find_thread(NULL),&th);
-	return th.stack_end;
+	sb -> mem_base = th.stack_end;
+	return GC_SUCCESS;
 }
+#   define HAVE_GET_STACK_BASE
 # endif /* BEOS */
 
 
 # ifdef OS2
 
-ptr_t GC_get_stack_base()
+int GC_get_stack_base(struct GC_stack_base *sb)
 {
     PTIB ptib;
     PPIB ppib;
     
     if (DosGetInfoBlocks(&ptib, &ppib) != NO_ERROR) {
     	GC_err_printf0("DosGetInfoBlocks failed\n");
-    	ABORT("DosGetInfoBlocks failed\n");
+	return GC_UNIMPLEMENTED;
     }
-    return((ptr_t)(ptib -> tib_pstacklimit));
+    sb -> mem_base = (void *)(ptib -> tib_pstacklimit);
+    return GC_SUCCESS;
 }
+#   define HAVE_GET_STACK_BASE
 
 # endif /* OS2 */
 
@@ -682,6 +693,7 @@ ptr_t GC_get_stack_base()
 #   define GC_AMIGA_SB
 #   include "AmigaOS.c"
 #   undef GC_AMIGA_SB
+#   define GET_MAIN_STACKBASE_SPECIAL
 # endif /* AMIGA */
 
 # if defined(NEED_FIND_LIMIT) || defined(UNIX_LIKE)
@@ -819,10 +831,11 @@ ptr_t GC_get_stack_base()
 # endif
 
 #if defined(ECOS) || defined(NOSYS)
-  ptr_t GC_get_stack_base()
+  ptr_t GC_get_main_stack_base GC_PROTO((void))
   {
     return STACKBOTTOM;
   }
+# define GET_MAIN_STACKBASE_SPECIAL
 #endif
 
 #ifdef HPUX_STACKBOTTOM
@@ -1059,7 +1072,7 @@ ptr_t GC_get_stack_base()
 #if !defined(BEOS) && !defined(AMIGA) && !defined(MSWIN32) \
     && !defined(MSWINCE) && !defined(OS2) && !defined(NOSYS) && !defined(ECOS)
 
-ptr_t GC_get_stack_base()
+ptr_t GC_get_main_stack_base GC_PROTO((void))
 {
 #   if defined(HEURISTIC1) || defined(HEURISTIC2) || \
        defined(LINUX_STACKBOTTOM) || defined(FREEBSD_STACKBOTTOM) || \
@@ -1118,9 +1131,41 @@ ptr_t GC_get_stack_base()
     	return(result);
 #   endif /* STACKBOTTOM */
 }
+#   define GET_MAIN_STACKBASE_SPECIAL
 
 # endif /* ! AMIGA, !OS 2, ! MS Windows, !BEOS, !NOSYS, !ECOS */
 
+#if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \
+    && !defined(GC_WIN32_THREADS)
+    /* GC_get_stack_base() is defined in pthread_support.c.	*/
+#   define HAVE_GET_STACK_BASE
+#endif
+
+#ifndef HAVE_GET_STACK_BASE
+    int GC_get_stack_base(struct GC_stack_base *sb)
+    {
+#     if defined(GET_MAIN_STACKBASE_SPECIAL) && !defined(THREADS) \
+	 && !defined(IA64)
+	sb->mem_base = GC_get_main_stack_base();
+	return GC_SUCCESS;
+#     else
+	return GC_UNIMPLEMENTED;
+#     endif
+    }
+#endif /* !HAVE_GET_STACK_BASE */
+
+#ifndef GET_MAIN_STACKBASE_SPECIAL
+  /* This is always called from the main thread.  Default implementation. */
+  ptr_t GC_get_main_stack_base GC_PROTO((void))
+  {
+    struct GC_stack_base sb;
+
+    if (GC_get_stack_base(&sb) != GC_SUCCESS)
+      ABORT("GC_get_stack_base failed");
+    return (ptr_t)sb.mem_base;
+  }
+#endif /* !GET_MAIN_STACKBASE_SPECIAL */
+
 /*
  * Register static data segment(s) as roots.
  * If more data segments are added later then they need to be registered
diff --git a/boehm-gc/pthread_support.c b/boehm-gc/pthread_support.c
index 6d8f020..e077abb 100644
--- a/boehm-gc/pthread_support.c
+++ b/boehm-gc/pthread_support.c
@@ -1127,7 +1127,7 @@ WRAP_FUNC(pthread_detach)(pthread_t thread)
 
 GC_bool GC_in_thread_creation = FALSE;
 
-GC_PTR GC_get_thread_stack_base()
+int GC_get_stack_base(struct GC_stack_base *sb)
 {  
 # ifdef HAVE_PTHREAD_GETATTR_NP
   pthread_t my_pthread;
@@ -1141,7 +1141,7 @@ GC_PTR GC_get_thread_stack_base()
 #   ifdef DEBUG_THREADS
       GC_printf0("Can not determine stack base for attached thread");
 #   endif
-      return 0;
+      return GC_UNIMPLEMENTED;
     }
   pthread_attr_getstack (&attr, (void **) &stack_addr, &stack_size);
   pthread_attr_destroy (&attr);
@@ -1151,16 +1151,22 @@ GC_PTR GC_get_thread_stack_base()
 #   endif
 
 #   ifdef STACK_GROWS_DOWN
-      return stack_addr + stack_size;
+      sb -> mem_base = stack_addr + stack_size;
 #   else
-      return stack_addr;
+      sb -> mem_base = stack_addr;
 #   endif
+#   ifdef IA64
+      sb -> reg_base = (void*)(GC_save_regs_in_stack() & ~(GC_page_size - 1));
+	/* This is not 100% convincing.  We should also read this	*/
+	/* from /proc, but the hook to do so isn't there yet.		*/
+#   endif
+    return GC_SUCCESS;
 
 # else
 #   ifdef DEBUG_THREADS
 	GC_printf0("Can not determine stack base for attached thread");
 #   endif
-  return 0;
+    return GC_UNIMPLEMENTED;
 # endif
 }
 
@@ -1168,6 +1174,11 @@ void GC_register_my_thread()
 {
   GC_thread me;
   pthread_t my_pthread;
+# if !defined(GC_DARWIN_THREADS) || defined(IA64)
+    struct GC_stack_base sb;
+    if (GC_get_stack_base(&sb) == GC_UNIMPLEMENTED)
+      ABORT("Can not determine stack base for attached thread");
+# endif
 
   my_pthread = pthread_self();
 #   ifdef DEBUG_THREADS
@@ -1197,9 +1208,7 @@ void GC_register_my_thread()
 #ifdef GC_DARWIN_THREADS
     me -> stop_info.mach_thread = mach_thread_self();
 #else
-    me -> stack_end = GC_get_thread_stack_base();    
-    if (me -> stack_end == 0)
-      GC_abort("Can not determine stack base for attached thread");
+    me -> stack_end = sb.mem_base;
     
 #   ifdef STACK_GROWS_DOWN
       me -> stop_info.stack_ptr = me -> stack_end - 0x10;
@@ -1209,10 +1218,7 @@ void GC_register_my_thread()
 #endif
 
 #   ifdef IA64
-      me -> backing_store_end = (ptr_t)
-			(GC_save_regs_in_stack() & ~(GC_page_size - 1));
-      /* This is also < 100% convincing.  We should also read this 	*/
-      /* from /proc, but the hook to do so isn't there yet.		*/
+      me -> backing_store_end = sb.reg_base;
 #   endif /* IA64 */
 
 #   if defined(THREAD_LOCAL_ALLOC) && !defined(DBG_HDRS_ALL)
diff --git a/boehm-gc/win32_threads.c b/boehm-gc/win32_threads.c
index 2de1c69..354e5a7 100644
--- a/boehm-gc/win32_threads.c
+++ b/boehm-gc/win32_threads.c
@@ -80,6 +80,7 @@ extern LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info);
  */
 static GC_thread GC_new_thread(void) {
   int i;
+  struct GC_stack_base sb;
   /* It appears to be unsafe to acquire a lock here, since this	*/
   /* code is apparently not preeemptible on some systems.	*/
   /* (This is based on complaints, not on Microsoft's official	*/
@@ -131,11 +132,11 @@ static GC_thread GC_new_thread(void) {
 	GC_printf1("Last error code: %lx\n", last_error);
 	ABORT("DuplicateHandle failed");
   }
-  thread_table[i].stack_base = GC_get_stack_base();
+  if (GC_get_stack_base(&sb) == GC_UNIMPLEMENTED)
+    ABORT("Failed to find stack base in GC_new_thread");
+  thread_table[i].stack_base = sb.mem_base;
   /* Up until this point, GC_push_all_stacks considers this thread	*/
   /* invalid.								*/
-  if (thread_table[i].stack_base == NULL) 
-    ABORT("Failed to find stack base in GC_new_thread");
   /* Up until this point, this entry is viewed as reserved but invalid	*/
   /* by GC_delete_thread.						*/
   thread_table[i].id = GetCurrentThreadId();
@@ -757,14 +758,15 @@ int GC_pthread_detach(pthread_t thread)
     return result;
 }
 
-GC_PTR GC_get_thread_stack_base()
+int GC_get_stack_base(struct GC_stack_base *sb)
 {
 #ifdef __x86_64__
-  return ((NT_TIB*)NtCurrentTeb())->StackBase;
+  sb -> mem_base = ((NT_TIB*)NtCurrentTeb())->StackBase;
 #else
   extern GC_PTR _tlsbase __asm__ ("%fs:4");
-  return _tlsbase;
+  sb -> mem_base = _tlsbase;
 #endif
+  return GC_SUCCESS;
 }
 
 #else /* !CYGWIN32 */
-- 
2.1.4