Wed, 31 Dec 2014 06:55:46 +0100
Added tag TORBROWSER_REPLICA for changeset 6474c204b198
michael@0 | 1 | ! -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- |
michael@0 | 2 | ! |
michael@0 | 3 | ! This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 4 | ! License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 5 | ! file, You can obtain one at http://mozilla.org/MPL/2.0/. |
michael@0 | 6 | |
michael@0 | 7 | ! |
michael@0 | 8 | ! atomic increment, decrement and swap routines for V8+ sparc (ultrasparc) |
michael@0 | 9 | ! using CAS (compare-and-swap) atomic instructions |
michael@0 | 10 | ! |
michael@0 | 11 | ! this MUST be compiled with an ultrasparc-aware assembler |
michael@0 | 12 | ! |
michael@0 | 13 | ! standard asm linkage macros; this module must be compiled |
michael@0 | 14 | ! with the -P option (use C preprocessor) |
michael@0 | 15 | |
michael@0 | 16 | #include <sys/asm_linkage.h> |
michael@0 | 17 | |
michael@0 | 18 | ! ====================================================================== |
michael@0 | 19 | ! |
michael@0 | 20 | ! Perform the sequence a = a + 1 atomically with respect to other |
michael@0 | 21 | ! fetch-and-adds to location a in a wait-free fashion. |
michael@0 | 22 | ! |
michael@0 | 23 | ! usage : val = PR_AtomicIncrement(address) |
michael@0 | 24 | ! return: current value (you'd think this would be old val) |
michael@0 | 25 | ! |
michael@0 | 26 | ! ----------------------- |
michael@0 | 27 | ! Note on REGISTER USAGE: |
michael@0 | 28 | ! as this is a LEAF procedure, a new stack frame is not created; |
michael@0 | 29 | ! we use the caller's stack frame so what would normally be %i (input) |
michael@0 | 30 | ! registers are actually %o (output registers). Also, we must not |
michael@0 | 31 | ! overwrite the contents of %l (local) registers as they are not |
michael@0 | 32 | ! assumed to be volatile during calls. |
michael@0 | 33 | ! |
michael@0 | 34 | ! So, the registers used are: |
michael@0 | 35 | ! %o0 [input] - the address of the value to increment |
michael@0 | 36 | ! %o1 [local] - work register |
michael@0 | 37 | ! %o2 [local] - work register |
michael@0 | 38 | ! %o3 [local] - work register |
michael@0 | 39 | ! ----------------------- |
michael@0 | 40 | |
michael@0 | 41 | ENTRY(_MD_AtomicIncrement) ! standard assembler/ELF prologue |
michael@0 | 42 | |
michael@0 | 43 | retryAI: |
michael@0 | 44 | ld [%o0], %o2 ! set o2 to the current value |
michael@0 | 45 | add %o2, 0x1, %o3 ! calc the new value |
michael@0 | 46 | mov %o3, %o1 ! save the return value |
michael@0 | 47 | cas [%o0], %o2, %o3 ! atomically set if o0 hasn't changed |
michael@0 | 48 | cmp %o2, %o3 ! see if we set the value |
michael@0 | 49 | bne retryAI ! if not, try again |
michael@0 | 50 | nop ! empty out the branch pipeline |
michael@0 | 51 | retl ! return back to the caller |
michael@0 | 52 | mov %o1, %o0 ! set the return code to the new value |
michael@0 | 53 | |
michael@0 | 54 | SET_SIZE(_MD_AtomicIncrement) ! standard assembler/ELF epilogue |
michael@0 | 55 | |
michael@0 | 56 | ! |
michael@0 | 57 | ! end |
michael@0 | 58 | ! |
michael@0 | 59 | ! ====================================================================== |
michael@0 | 60 | ! |
michael@0 | 61 | |
michael@0 | 62 | ! ====================================================================== |
michael@0 | 63 | ! |
michael@0 | 64 | ! Perform the sequence a = a - 1 atomically with respect to other |
michael@0 | 65 | ! fetch-and-decs to location a in a wait-free fashion. |
michael@0 | 66 | ! |
michael@0 | 67 | ! usage : val = PR_AtomicDecrement(address) |
michael@0 | 68 | ! return: current value (you'd think this would be old val) |
michael@0 | 69 | ! |
michael@0 | 70 | ! ----------------------- |
michael@0 | 71 | ! Note on REGISTER USAGE: |
michael@0 | 72 | ! as this is a LEAF procedure, a new stack frame is not created; |
michael@0 | 73 | ! we use the caller's stack frame so what would normally be %i (input) |
michael@0 | 74 | ! registers are actually %o (output registers). Also, we must not |
michael@0 | 75 | ! overwrite the contents of %l (local) registers as they are not |
michael@0 | 76 | ! assumed to be volatile during calls. |
michael@0 | 77 | ! |
michael@0 | 78 | ! So, the registers used are: |
michael@0 | 79 | ! %o0 [input] - the address of the value to increment |
michael@0 | 80 | ! %o1 [local] - work register |
michael@0 | 81 | ! %o2 [local] - work register |
michael@0 | 82 | ! %o3 [local] - work register |
michael@0 | 83 | ! ----------------------- |
michael@0 | 84 | |
michael@0 | 85 | ENTRY(_MD_AtomicDecrement) ! standard assembler/ELF prologue |
michael@0 | 86 | |
michael@0 | 87 | retryAD: |
michael@0 | 88 | ld [%o0], %o2 ! set o2 to the current value |
michael@0 | 89 | sub %o2, 0x1, %o3 ! calc the new value |
michael@0 | 90 | mov %o3, %o1 ! save the return value |
michael@0 | 91 | cas [%o0], %o2, %o3 ! atomically set if o0 hasn't changed |
michael@0 | 92 | cmp %o2, %o3 ! see if we set the value |
michael@0 | 93 | bne retryAD ! if not, try again |
michael@0 | 94 | nop ! empty out the branch pipeline |
michael@0 | 95 | retl ! return back to the caller |
michael@0 | 96 | mov %o1, %o0 ! set the return code to the new value |
michael@0 | 97 | |
michael@0 | 98 | SET_SIZE(_MD_AtomicDecrement) ! standard assembler/ELF epilogue |
michael@0 | 99 | |
michael@0 | 100 | ! |
michael@0 | 101 | ! end |
michael@0 | 102 | ! |
michael@0 | 103 | ! ====================================================================== |
michael@0 | 104 | ! |
michael@0 | 105 | |
michael@0 | 106 | ! ====================================================================== |
michael@0 | 107 | ! |
michael@0 | 108 | ! Perform the sequence a = b atomically with respect to other |
michael@0 | 109 | ! fetch-and-stores to location a in a wait-free fashion. |
michael@0 | 110 | ! |
michael@0 | 111 | ! usage : old_val = PR_AtomicSet(address, newval) |
michael@0 | 112 | ! |
michael@0 | 113 | ! ----------------------- |
michael@0 | 114 | ! Note on REGISTER USAGE: |
michael@0 | 115 | ! as this is a LEAF procedure, a new stack frame is not created; |
michael@0 | 116 | ! we use the caller's stack frame so what would normally be %i (input) |
michael@0 | 117 | ! registers are actually %o (output registers). Also, we must not |
michael@0 | 118 | ! overwrite the contents of %l (local) registers as they are not |
michael@0 | 119 | ! assumed to be volatile during calls. |
michael@0 | 120 | ! |
michael@0 | 121 | ! So, the registers used are: |
michael@0 | 122 | ! %o0 [input] - the address of the value to increment |
michael@0 | 123 | ! %o1 [input] - the new value to set for [%o0] |
michael@0 | 124 | ! %o2 [local] - work register |
michael@0 | 125 | ! %o3 [local] - work register |
michael@0 | 126 | ! ----------------------- |
michael@0 | 127 | |
michael@0 | 128 | ENTRY(_MD_AtomicSet) ! standard assembler/ELF prologue |
michael@0 | 129 | |
michael@0 | 130 | retryAS: |
michael@0 | 131 | ld [%o0], %o2 ! set o2 to the current value |
michael@0 | 132 | mov %o1, %o3 ! set up the new value |
michael@0 | 133 | cas [%o0], %o2, %o3 ! atomically set if o0 hasn't changed |
michael@0 | 134 | cmp %o2, %o3 ! see if we set the value |
michael@0 | 135 | bne retryAS ! if not, try again |
michael@0 | 136 | nop ! empty out the branch pipeline |
michael@0 | 137 | retl ! return back to the caller |
michael@0 | 138 | mov %o3, %o0 ! set the return code to the prev value |
michael@0 | 139 | |
michael@0 | 140 | SET_SIZE(_MD_AtomicSet) ! standard assembler/ELF epilogue |
michael@0 | 141 | |
michael@0 | 142 | ! |
michael@0 | 143 | ! end |
michael@0 | 144 | ! |
michael@0 | 145 | ! ====================================================================== |
michael@0 | 146 | ! |
michael@0 | 147 | |
michael@0 | 148 | ! ====================================================================== |
michael@0 | 149 | ! |
michael@0 | 150 | ! Perform the sequence a = a + b atomically with respect to other |
michael@0 | 151 | ! fetch-and-adds to location a in a wait-free fashion. |
michael@0 | 152 | ! |
michael@0 | 153 | ! usage : newval = PR_AtomicAdd(address, val) |
michael@0 | 154 | ! return: the value after addition |
michael@0 | 155 | ! |
michael@0 | 156 | ENTRY(_MD_AtomicAdd) ! standard assembler/ELF prologue |
michael@0 | 157 | |
michael@0 | 158 | retryAA: |
michael@0 | 159 | ld [%o0], %o2 ! set o2 to the current value |
michael@0 | 160 | add %o2, %o1, %o3 ! calc the new value |
michael@0 | 161 | mov %o3, %o4 ! save the return value |
michael@0 | 162 | cas [%o0], %o2, %o3 ! atomically set if o0 hasn't changed |
michael@0 | 163 | cmp %o2, %o3 ! see if we set the value |
michael@0 | 164 | bne retryAA ! if not, try again |
michael@0 | 165 | nop ! empty out the branch pipeline |
michael@0 | 166 | retl ! return back to the caller |
michael@0 | 167 | mov %o4, %o0 ! set the return code to the new value |
michael@0 | 168 | |
michael@0 | 169 | SET_SIZE(_MD_AtomicAdd) ! standard assembler/ELF epilogue |
michael@0 | 170 | |
michael@0 | 171 | ! |
michael@0 | 172 | ! end |
michael@0 | 173 | ! |