Bugzilla Bug 63049: 64-bit Solaris does not need the libultrasparc4.so
authorwtc%netscape.com
Sun, 24 Jun 2001 01:39:51 +0000
changeset 1970 92ca2c6fa1606fb03c547c2a3debbdf495b1a387
parent 1969 612af6f1f18387d28b4d6a152486515d47f898cc
child 1971 aaa7fc36c341476cd5f72bacfa57d3787f398924
push idunknown
push userunknown
push dateunknown
bugs63049
Bugzilla Bug 63049: 64-bit Solaris does not need the libultrasparc4.so (-f libatomic.so) filter library. Modified files: configure configure.in _solaris.h pr/src/md/unix/Makefile solaris.c. Added file: os_SunOS_sparcv9.s.
configure
configure.in
pr/include/md/_solaris.h
pr/src/md/unix/Makefile.in
pr/src/md/unix/os_SunOS_sparcv9.s
pr/src/md/unix/solaris.c
--- a/configure
+++ b/configure
@@ -4375,19 +4375,23 @@ EOF
             cat >> confdefs.h <<\EOF
 #define _LARGEFILE64_SOURCE 1
 EOF
 
         fi
         ;;
     esac
     if test "$OS_TEST" = "sun4u"; then
-        ULTRASPARC_LIBRARY=ultrasparc
-        ULTRASPARC_FILTER_LIBRARY=libatomic.so
-        DSO_LDOPTS="$DSO_LDOPTS -f "'$(ULTRASPARC_FILTER_LIBRARY)'
+        # 64-bit Solaris requires SPARC V9 architecture, so the following
+        # is not needed.
+        if test -z "$USE_64"; then
+            ULTRASPARC_LIBRARY=ultrasparc
+            ULTRASPARC_FILTER_LIBRARY=libatomic.so
+            DSO_LDOPTS="$DSO_LDOPTS -f "'$(ULTRASPARC_FILTER_LIBRARY)'
+        fi
     fi
     ;;
 
 *-sco-sysv5*)
     cat >> confdefs.h <<\EOF
 #define XP_UNIX 1
 EOF
 
@@ -4548,22 +4552,22 @@ EOF
 
     ;;
    
 esac
 
 if test -z "$SKIP_LIBRARY_CHECKS"; then
 
 echo $ac_n "checking for dlopen""... $ac_c" 1>&6
-echo "configure:4557: checking for dlopen" >&5
+echo "configure:4561: checking for dlopen" >&5
 if eval "test \"`echo '$''{'ac_cv_func_dlopen'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 4562 "configure"
+#line 4566 "configure"
 #include "confdefs.h"
 /* System header to define __stub macros and hopefully few prototypes,
     which can conflict with char dlopen(); below.  */
 #include <assert.h>
 /* Override any gcc2 internal prototype to avoid an error.  */
 /* We use char because int might match the return type of a gcc2
     builtin and then its argument prototype would still apply.  */
 char dlopen();
@@ -4576,17 +4580,17 @@ int main() {
 #if defined (__stub_dlopen) || defined (__stub___dlopen)
 choke me
 #else
 dlopen();
 #endif
 
 ; return 0; }
 EOF
-if { (eval echo configure:4585: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:4589: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_func_dlopen=yes"
 else
   echo "configure: failed program was:" >&5
   cat conftest.$ac_ext >&5
   rm -rf conftest*
   eval "ac_cv_func_dlopen=no"
 fi
@@ -4595,36 +4599,36 @@ fi
 
 if eval "test \"`echo '$ac_cv_func_'dlopen`\" = yes"; then
   echo "$ac_t""yes" 1>&6
   :
 else
   echo "$ac_t""no" 1>&6
 
     echo $ac_n "checking for dlopen in -ldl""... $ac_c" 1>&6
-echo "configure:4604: checking for dlopen in -ldl" >&5
+echo "configure:4608: checking for dlopen in -ldl" >&5
 ac_lib_var=`echo dl'_'dlopen | sed 'y%./+-%__p_%'`
 if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   ac_save_LIBS="$LIBS"
 LIBS="-ldl  $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 4612 "configure"
+#line 4616 "configure"
 #include "confdefs.h"
 /* Override any gcc2 internal prototype to avoid an error.  */
 /* We use char because int might match the return type of a gcc2
     builtin and then its argument prototype would still apply.  */
 char dlopen();
 
 int main() {
 dlopen()
 ; return 0; }
 EOF
-if { (eval echo configure:4623: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:4627: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_lib_$ac_lib_var=yes"
 else
   echo "configure: failed program was:" >&5
   cat conftest.$ac_ext >&5
   rm -rf conftest*
   eval "ac_cv_lib_$ac_lib_var=no"
 fi
@@ -4642,23 +4646,23 @@ fi
 
 fi
 
 
 
 
 if test $ac_cv_prog_gcc = yes; then
     echo $ac_n "checking whether ${CC-cc} needs -traditional""... $ac_c" 1>&6
-echo "configure:4651: checking whether ${CC-cc} needs -traditional" >&5
+echo "configure:4655: checking whether ${CC-cc} needs -traditional" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_gcc_traditional'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
     ac_pattern="Autoconf.*'x'"
   cat > conftest.$ac_ext <<EOF
-#line 4657 "configure"
+#line 4661 "configure"
 #include "confdefs.h"
 #include <sgtty.h>
 Autoconf TIOCGETP
 EOF
 if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
   egrep "$ac_pattern" >/dev/null 2>&1; then
   rm -rf conftest*
   ac_cv_prog_gcc_traditional=yes
@@ -4666,17 +4670,17 @@ else
   rm -rf conftest*
   ac_cv_prog_gcc_traditional=no
 fi
 rm -f conftest*
 
 
   if test $ac_cv_prog_gcc_traditional = no; then
     cat > conftest.$ac_ext <<EOF
-#line 4675 "configure"
+#line 4679 "configure"
 #include "confdefs.h"
 #include <termio.h>
 Autoconf TCGETA
 EOF
 if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
   egrep "$ac_pattern" >/dev/null 2>&1; then
   rm -rf conftest*
   ac_cv_prog_gcc_traditional=yes
@@ -4690,22 +4694,22 @@ echo "$ac_t""$ac_cv_prog_gcc_traditional
   if test $ac_cv_prog_gcc_traditional = yes; then
     CC="$CC -traditional"
   fi
 fi
 
 for ac_func in lchown strerror
 do
 echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
-echo "configure:4699: checking for $ac_func" >&5
+echo "configure:4703: checking for $ac_func" >&5
 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 4704 "configure"
+#line 4708 "configure"
 #include "confdefs.h"
 /* System header to define __stub macros and hopefully few prototypes,
     which can conflict with char $ac_func(); below.  */
 #include <assert.h>
 /* Override any gcc2 internal prototype to avoid an error.  */
 /* We use char because int might match the return type of a gcc2
     builtin and then its argument prototype would still apply.  */
 char $ac_func();
@@ -4718,17 +4722,17 @@ int main() {
 #if defined (__stub_$ac_func) || defined (__stub___$ac_func)
 choke me
 #else
 $ac_func();
 #endif
 
 ; return 0; }
 EOF
-if { (eval echo configure:4727: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:4731: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_func_$ac_func=yes"
 else
   echo "configure: failed program was:" >&5
   cat conftest.$ac_ext >&5
   rm -rf conftest*
   eval "ac_cv_func_$ac_func=no"
 fi
@@ -4749,17 +4753,17 @@ done
 
 
 
 
 
 
 
 echo $ac_n "checking for pthread_create in -lpthreads""... $ac_c" 1>&6
-echo "configure:4758: checking for pthread_create in -lpthreads" >&5
+echo "configure:4762: checking for pthread_create in -lpthreads" >&5
 echo "
     #include <pthread.h> 
     void *foo(void *v) { int a = 1;  } 
     int main() { 
         pthread_t t;
         if (!pthread_create(&t, 0, &foo, 0)) {
             pthread_join(t, 0);
         }
@@ -4771,17 +4775,17 @@ echo "
     rm -f dummy.c dummy${ac_exeext} ;
     if test "$_res" = "0"; then
         echo "$ac_t""yes" 1>&6
         _HAVE_PTHREADS=1 _PTHREAD_LDFLAGS="-lpthreads"
     else
         echo "$ac_t""no" 1>&6
         
 echo $ac_n "checking for pthread_create in -lpthread""... $ac_c" 1>&6
-echo "configure:4780: checking for pthread_create in -lpthread" >&5
+echo "configure:4784: checking for pthread_create in -lpthread" >&5
 echo "
     #include <pthread.h> 
     void *foo(void *v) { int a = 1;  } 
     int main() { 
         pthread_t t;
         if (!pthread_create(&t, 0, &foo, 0)) {
             pthread_join(t, 0);
         }
@@ -4793,17 +4797,17 @@ echo "
     rm -f dummy.c dummy${ac_exeext} ;
     if test "$_res" = "0"; then
         echo "$ac_t""yes" 1>&6
         _HAVE_PTHREADS=1 _PTHREAD_LDFLAGS="-lpthread"
     else
         echo "$ac_t""no" 1>&6
         
 echo $ac_n "checking for pthread_create in -lc_r""... $ac_c" 1>&6
-echo "configure:4802: checking for pthread_create in -lc_r" >&5
+echo "configure:4806: checking for pthread_create in -lc_r" >&5
 echo "
     #include <pthread.h> 
     void *foo(void *v) { int a = 1;  } 
     int main() { 
         pthread_t t;
         if (!pthread_create(&t, 0, &foo, 0)) {
             pthread_join(t, 0);
         }
@@ -4815,17 +4819,17 @@ echo "
     rm -f dummy.c dummy${ac_exeext} ;
     if test "$_res" = "0"; then
         echo "$ac_t""yes" 1>&6
         _HAVE_PTHREADS=1 _PTHREAD_LDFLAGS="-lc_r"
     else
         echo "$ac_t""no" 1>&6
         
 echo $ac_n "checking for pthread_create in -lc""... $ac_c" 1>&6
-echo "configure:4824: checking for pthread_create in -lc" >&5
+echo "configure:4828: checking for pthread_create in -lc" >&5
 echo "
     #include <pthread.h> 
     void *foo(void *v) { int a = 1;  } 
     int main() { 
         pthread_t t;
         if (!pthread_create(&t, 0, &foo, 0)) {
             pthread_join(t, 0);
         }
@@ -4965,33 +4969,33 @@ EOF
     fi
 fi
 
 
 if test -n "$USE_PTHREADS"; then
       rm -f conftest*
    ac_cv_have_dash_pthread=no
    echo $ac_n "checking whether ${CC-cc} accepts -pthread""... $ac_c" 1>&6
-echo "configure:4974: checking whether ${CC-cc} accepts -pthread" >&5
+echo "configure:4978: checking whether ${CC-cc} accepts -pthread" >&5
    echo 'int main() { return 0; }' | cat > conftest.c
    ${CC-cc} -pthread -o conftest conftest.c > conftest.out 2>&1
    if test $? -eq 0; then
 	if test -z "`egrep -i '(unrecognize|unknown)' conftest.out | grep pthread`" && test -z "`egrep -i '(error|incorrect)' conftest.out`" ; then
 	    ac_cv_have_dash_pthread=yes
 	    CFLAGS="$CFLAGS -pthread"
 	    CXXFLAGS="$CXXFLAGS -pthread"
 	fi
     fi
     rm -f conftest*
     echo "$ac_t""$ac_cv_have_dash_pthread" 1>&6
 
 			    ac_cv_have_dash_pthreads=no
     if test "$ac_cv_have_dash_pthread" = "no"; then
 	    echo $ac_n "checking whether ${CC-cc} accepts -pthreads""... $ac_c" 1>&6
-echo "configure:4990: checking whether ${CC-cc} accepts -pthreads" >&5
+echo "configure:4994: checking whether ${CC-cc} accepts -pthreads" >&5
     	echo 'int main() { return 0; }' | cat > conftest.c
 	    ${CC-cc} -pthreads -o conftest conftest.c > conftest.out 2>&1
     	if test $? -eq 0; then
 	    	if test -z "`egrep -i '(unrecognize|unknown)' conftest.out | grep pthreads`" && test -z "`egrep -i '(error|incorrect)' conftest.out`" ; then
 			    ac_cv_have_dash_pthreads=yes
 			    CFLAGS="$CFLAGS -pthreads"
 			    CXXFLAGS="$CXXFLAGS -pthreads"
 		    fi
@@ -5199,17 +5203,19 @@ EOF
         cat >> confdefs.h <<\EOF
 #define HAVE_POINTER_LOCALTIME_R 1
 EOF
 
         if test "$OS_TEST" = "i86pc"; then
             PR_MD_ASFILES=os_SunOS_x86.s
         else
             PR_MD_ASFILES=os_SunOS.s
-            if test -z "$USE_64"; then
+            if test -n "$USE_64"; then
+                PR_MD_ASFILES="$PR_MD_ASFILES os_SunOS_sparcv9.s"
+            else
                 PR_MD_ASFILES="$PR_MD_ASFILES os_SunOS_32.s"
             fi
         fi
     fi
     ;;
 esac
 
 OS_LIBS="$_PTHREAD_LDFLAGS $OS_LIBS"
--- a/configure.in
+++ b/configure.in
@@ -1592,19 +1592,23 @@ mips-sony-newsos*)
         # But gcc 2.7.2.x fails to define _LARGEFILE64_SOURCE by default.
         # The native compiler, gcc 2.8.x, and egcs don't have this problem.
         if test -n "$GNU_CC"; then
             AC_DEFINE(_LARGEFILE64_SOURCE)
         fi
         ;;
     esac
     if test "$OS_TEST" = "sun4u"; then
-        ULTRASPARC_LIBRARY=ultrasparc
-        ULTRASPARC_FILTER_LIBRARY=libatomic.so
-        DSO_LDOPTS="$DSO_LDOPTS -f "'$(ULTRASPARC_FILTER_LIBRARY)'
+        # 64-bit Solaris requires SPARC V9 architecture, so the following
+        # is not needed.
+        if test -z "$USE_64"; then
+            ULTRASPARC_LIBRARY=ultrasparc
+            ULTRASPARC_FILTER_LIBRARY=libatomic.so
+            DSO_LDOPTS="$DSO_LDOPTS -f "'$(ULTRASPARC_FILTER_LIBRARY)'
+        fi
     fi
     ;;
 
 *-sco-sysv5*)
     AC_DEFINE(XP_UNIX)
     AC_DEFINE(UNIXWARE)
     AC_DEFINE(SVR4)
     AC_DEFINE(SYSV)
@@ -2076,17 +2080,19 @@ case "$target" in
     fi
     if test -z "$USE_NSPR_THREADS"; then
         AC_DEFINE(_REENTRANT)
         AC_DEFINE(HAVE_POINTER_LOCALTIME_R)
         if test "$OS_TEST" = "i86pc"; then
             PR_MD_ASFILES=os_SunOS_x86.s
         else
             PR_MD_ASFILES=os_SunOS.s
-            if test -z "$USE_64"; then
+            if test -n "$USE_64"; then
+                PR_MD_ASFILES="$PR_MD_ASFILES os_SunOS_sparcv9.s"
+            else
                 PR_MD_ASFILES="$PR_MD_ASFILES os_SunOS_32.s"
             fi
         fi
     fi
     ;;
 esac
 
 OS_LIBS="$_PTHREAD_LDFLAGS $OS_LIBS"
--- a/pr/include/md/_solaris.h
+++ b/pr/include/md/_solaris.h
@@ -65,18 +65,20 @@
  *
  * Sparc v8 does not have instructions to efficiently implement
  * atomic increment/decrement operations.  In the local threads
  * only and pthreads versions, we use the default atomic routine
  * implementation in pratom.c.  The obsolete global threads only
  * version uses a global mutex_t to implement the atomic routines
  * in solaris.c, which is actually equivalent to the default
  * implementation.
+ *
+ * 64-bit Solaris requires sparc v9, which has atomic instructions.
  */
-#if defined(i386) || defined(_PR_GLOBAL_THREADS_ONLY)
+#if defined(i386) || defined(_PR_GLOBAL_THREADS_ONLY) || defined(IS_64)
 #define _PR_HAVE_ATOMIC_OPS
 #endif
 
 #if defined(_PR_GLOBAL_THREADS_ONLY) || defined(_PR_PTHREADS)
 /*
  * We have assembly language implementation of atomic
  * stacks for the 32-bit sparc and x86 architectures only.
  */
--- a/pr/src/md/unix/Makefile.in
+++ b/pr/src/md/unix/Makefile.in
@@ -61,45 +61,53 @@ endif
 CSRCS += $(PR_MD_CSRCS)
 ASFILES += $(PR_MD_ASFILES)
 
 TARGETS = $(OBJS)
 
 ifeq ($(OS_ARCH),SunOS)
 	ifneq ($(OS_RELEASE),4.1.3_U1)
 		ifeq ($(OS_TEST),sun4u)
+		ifdef USE_64
+			ULTRASPARC_ASFILES = os_SunOS_sparcv9.s
+			ULTRASPARC_ASOBJS = $(addprefix $(OBJDIR)/,$(ULTRASPARC_ASFILES:.s=.$(OBJ_SUFFIX)))
+		else
 			LIBRARY_NAME = $(ULTRASPARC_LIBRARY)
 			LIBRARY_VERSION = $(MOD_MAJOR_VERSION)
-			ULTRASPARC_ASFILES = os_$(OS_ARCH)_ultrasparc.s
+			ULTRASPARC_ASFILES = os_SunOS_ultrasparc.s
 			ULTRASPARC_ASOBJS = $(addprefix $(OBJDIR)/,$(ULTRASPARC_ASFILES:.s=.$(OBJ_SUFFIX)))
 			TARGETS		+= $(ULTRASPARC_ASOBJS) $(SHARED_LIBRARY)
 			RELEASE_LIBS = $(SHARED_LIBRARY)
 		endif
+		endif
 	endif
 endif
 
 INCLUDES = -I$(dist_includedir) -I$(topsrcdir)/pr/include -I$(topsrcdir)/pr/include/private
 
 DEFINES	+= -D_NSPR_BUILD_
 
 include $(topsrcdir)/config/rules.mk
 
 export:: $(TARGETS)
 
 ifeq ($(OS_ARCH),SunOS)
 ifneq ($(OS_RELEASE),4.1.3_U1)
 ifeq ($(OS_TEST),sun4u)
+
+ifdef USE_64
+$(ULTRASPARC_ASOBJS): $(ULTRASPARC_ASFILES)
+	/usr/ccs/bin/as -o $@ -K PIC -P -D_ASM -D__STDC__=0 -xarch=v9 $<
+else
 $(SHARED_LIBRARY): $(ULTRASPARC_ASOBJS)
 	$(LD) -G -z text -o $@ $(ULTRASPARC_ASOBJS)
-	$(INSTALL) -m 444 $(SHARED_LIBRARY) $(dist_libdir)
+	$(INSTALL) -m 444 $@ $(dist_libdir)
 
 $(ULTRASPARC_ASOBJS): $(ULTRASPARC_ASFILES)
-ifeq ($(USE_64),1)
-	/usr/ccs/bin/as -o $@ -K PIC -P -D_ASM -D__STDC__=0 -xarch=v9 $<
-else
 	/usr/ccs/bin/as -o $@ -K PIC -P -D_ASM -D__STDC__=0 -xarch=v8plus $<
-endif
 
 clean::
 	rm -rf $(ULTRASPARC_ASOBJS)
 endif
+
 endif
 endif
+endif
new file mode 100644
--- /dev/null
+++ b/pr/src/md/unix/os_SunOS_sparcv9.s
@@ -0,0 +1,201 @@
+! -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+! 
+! The contents of this file are subject to the Mozilla Public
+! License Version 1.1 (the "License"); you may not use this file
+! except in compliance with the License. You may obtain a copy of
+! the License at http://www.mozilla.org/MPL/
+! 
+! Software distributed under the License is distributed on an "AS
+! IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+! implied. See the License for the specific language governing
+! rights and limitations under the License.
+! 
+! The Original Code is the Netscape Portable Runtime (NSPR).
+! 
+! The Initial Developer of the Original Code is Netscape
+! Communications Corporation.  Portions created by Netscape are 
+! Copyright (C) 1998-2000 Netscape Communications Corporation.  All
+! Rights Reserved.
+! 
+! Contributor(s):
+! 
+! Alternatively, the contents of this file may be used under the
+! terms of the GNU General Public License Version 2 or later (the
+! "GPL"), in which case the provisions of the GPL are applicable 
+! instead of those above.  If you wish to allow use of your 
+! version of this file only under the terms of the GPL and not to
+! allow others to use your version of this file under the MPL,
+! indicate your decision by deleting the provisions above and
+! replace them with the notice and other provisions required by
+! the GPL.  If you do not delete the provisions above, a recipient
+! may use your version of this file under either the MPL or the
+! GPL.
+! 
+
+!
+!  atomic increment, decrement and swap routines for V8+ sparc (ultrasparc)
+!  using CAS (compare-and-swap) atomic instructions
+!
+!  this MUST be compiled with an ultrasparc-aware assembler
+!
+!  standard asm linkage macros; this module must be compiled
+!  with the -P option (use C preprocessor)
+
+#include <sys/asm_linkage.h>
+
+!  ======================================================================
+!
+!  Perform the sequence a = a + 1 atomically with respect to other
+!  fetch-and-adds to location a in a wait-free fashion.
+!
+!  usage : val = PR_AtomicIncrement(address)
+!  return: current value (you'd think this would be old val)
+!
+!  -----------------------
+!  Note on REGISTER USAGE:
+!  as this is a LEAF procedure, a new stack frame is not created;
+!  we use the caller's stack frame so what would normally be %i (input)
+!  registers are actually %o (output registers).  Also, we must not
+!  overwrite the contents of %l (local) registers as they are not
+!  assumed to be volatile during calls.
+!
+!  So, the registers used are:
+!     %o0  [input]   - the address of the value to increment
+!     %o1  [local]   - work register
+!     %o2  [local]   - work register
+!     %o3  [local]   - work register
+!  -----------------------
+
+        ENTRY(_MD_AtomicIncrement)      ! standard assembler/ELF prologue
+
+retryAI:
+        ld      [%o0], %o2              ! set o2 to the current value
+        add     %o2, 0x1, %o3           ! calc the new value
+        mov     %o3, %o1                ! save the return value
+        cas     [%o0], %o2, %o3         ! atomically set if o0 hasn't changed
+        cmp     %o2, %o3                ! see if we set the value
+        bne     retryAI                 ! if not, try again
+        nop                             ! empty out the branch pipeline
+        retl                            ! return back to the caller
+        mov     %o1, %o0                ! set the return code to the new value
+
+        SET_SIZE(_MD_AtomicIncrement)   ! standard assembler/ELF epilogue
+
+!
+!  end
+!
+!  ======================================================================
+!
+
+!  ======================================================================
+!
+!  Perform the sequence a = a - 1 atomically with respect to other
+!  fetch-and-decs to location a in a wait-free fashion.
+!
+!  usage : val = PR_AtomicDecrement(address)
+!  return: current value (you'd think this would be old val)
+!
+!  -----------------------
+!  Note on REGISTER USAGE:
+!  as this is a LEAF procedure, a new stack frame is not created;
+!  we use the caller's stack frame so what would normally be %i (input)
+!  registers are actually %o (output registers).  Also, we must not
+!  overwrite the contents of %l (local) registers as they are not
+!  assumed to be volatile during calls.
+!
+!  So, the registers used are:
+!     %o0  [input]   - the address of the value to increment
+!     %o1  [local]   - work register
+!     %o2  [local]   - work register
+!     %o3  [local]   - work register
+!  -----------------------
+
+        ENTRY(_MD_AtomicDecrement)      ! standard assembler/ELF prologue
+
+retryAD:
+        ld      [%o0], %o2              ! set o2 to the current value
+        sub     %o2, 0x1, %o3           ! calc the new value
+        mov     %o3, %o1                ! save the return value
+        cas     [%o0], %o2, %o3         ! atomically set if o0 hasn't changed
+        cmp     %o2, %o3                ! see if we set the value
+        bne     retryAD                 ! if not, try again
+        nop                             ! empty out the branch pipeline
+        retl                            ! return back to the caller
+        mov     %o1, %o0                ! set the return code to the new value
+
+        SET_SIZE(_MD_AtomicDecrement)   ! standard assembler/ELF epilogue
+
+!
+!  end
+!
+!  ======================================================================
+!
+
+!  ======================================================================
+!
+!  Perform the sequence a = b atomically with respect to other
+!  fetch-and-stores to location a in a wait-free fashion.
+!
+!  usage : old_val = PR_AtomicSet(address, newval)
+!
+!  -----------------------
+!  Note on REGISTER USAGE:
+!  as this is a LEAF procedure, a new stack frame is not created;
+!  we use the caller's stack frame so what would normally be %i (input)
+!  registers are actually %o (output registers).  Also, we must not
+!  overwrite the contents of %l (local) registers as they are not
+!  assumed to be volatile during calls.
+!
+!  So, the registers used are:
+!     %o0  [input]   - the address of the value to increment
+!     %o1  [input]   - the new value to set for [%o0]
+!     %o2  [local]   - work register
+!     %o3  [local]   - work register
+!  -----------------------
+
+        ENTRY(_MD_AtomicSet)            ! standard assembler/ELF prologue
+
+retryAS:
+        ld      [%o0], %o2              ! set o2 to the current value
+        mov     %o1, %o3                ! set up the new value
+        cas     [%o0], %o2, %o3         ! atomically set if o0 hasn't changed
+        cmp     %o2, %o3                ! see if we set the value
+        bne     retryAS                 ! if not, try again
+        nop                             ! empty out the branch pipeline
+        retl                            ! return back to the caller
+        mov     %o3, %o0                ! set the return code to the prev value
+
+        SET_SIZE(_MD_AtomicSet)         ! standard assembler/ELF epilogue
+
+!
+!  end
+!
+!  ======================================================================
+!
+
+!  ======================================================================
+!
+!  Perform the sequence a = a + b atomically with respect to other
+!  fetch-and-adds to location a in a wait-free fashion.
+!
+!  usage : newval = PR_AtomicAdd(address, val)
+!  return: the value after addition
+!
+        ENTRY(_MD_AtomicAdd)      ! standard assembler/ELF prologue
+
+retryAA:
+        ld      [%o0], %o2              ! set o2 to the current value
+        add     %o2, %o1, %o3           ! calc the new value
+        mov     %o3, %o4                ! save the return value
+        cas     [%o0], %o2, %o3         ! atomically set if o0 hasn't changed
+        cmp     %o2, %o3                ! see if we set the value
+        bne     retryAA                 ! if not, try again
+        nop                             ! empty out the branch pipeline
+        retl                            ! return back to the caller
+        mov     %o4, %o0                ! set the return code to the new value
+
+        SET_SIZE(_MD_AtomicAdd)    		! standard assembler/ELF epilogue
+
+!
+!  end
+!
--- a/pr/src/md/unix/solaris.c
+++ b/pr/src/md/unix/solaris.c
@@ -80,17 +80,17 @@ void _MD_EarlyInit(void)
 
 PRWord *_MD_HomeGCRegisters(PRThread *t, PRIntn isCurrent, PRIntn *np)
 {
 	*np = 0;
 	return NULL;
 }
 #endif /* _PR_PTHREADS */
 
-#if !defined(i386)
+#if !defined(i386) && !defined(IS_64)
 #if defined(_PR_HAVE_ATOMIC_OPS)
 /* NOTE:
  * SPARC v9 (Ultras) do have an atomic test-and-set operation.  But
  * SPARC v8 doesn't.  We should detect in the init if we are running on
  * v8 or v9, and then use assembly where we can.
  *
  * This code uses the Solaris threads API.  It can be used in both the
  * pthreads and Solaris threads versions of nspr20 because "POSIX threads