jscript: Added Object function invocation implementation.
[wine] / libs / port / interlocked.c
1 /*
2  * interlocked functions
3  *
4  * Copyright 1996 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23 #include <assert.h>
24
25 #ifdef __i386__
26
27 #if defined(_MSC_VER)
28
29 __declspec(naked) int interlocked_cmpxchg( int *dest, int xchg, int compare )
30 {
31     __asm mov eax, 12[esp];
32     __asm mov ecx, 8[esp];
33     __asm mov edx, 4[esp];
34     __asm lock cmpxchg [edx], ecx;
35     __asm ret;
36 }
37
38 __declspec(naked) void *interlocked_cmpxchg_ptr( void **dest, void *xchg, void *compare )
39 {
40     __asm mov eax, 12[esp];
41     __asm mov ecx, 8[esp];
42     __asm mov edx, 4[esp];
43     __asm lock cmpxchg [edx], ecx;
44     __asm ret;
45 }
46
47 __declspec(naked) __int64 interlocked_cmpxchg64( __int64 *dest, __int64 xchg, __int64 compare)
48 {
49     __asm push ebx;
50     __asm push esi;
51     __asm mov esi, 12[esp];
52     __asm mov ebx, 16[esp];
53     __asm mov ecx, 20[esp];
54     __asm mov eax, 24[esp];
55     __asm mov edx, 28[esp];
56     __asm lock cmpxchg8b [esi];
57     __asm pop esi;
58     __asm pop ebx;
59     __asm ret;
60 }
61
62 __declspec(naked) int interlocked_xchg( int *dest, int val )
63 {
64     __asm mov eax, 8[esp];
65     __asm mov edx, 4[esp];
66     __asm lock xchg [edx], eax;
67     __asm ret;
68 }
69
70 __declspec(naked) void *interlocked_xchg_ptr( void **dest, void *val )
71 {
72     __asm mov eax, 8[esp];
73     __asm mov edx, 4[esp];
74     __asm lock xchg [edx], eax;
75     __asm ret;
76 }
77
78 __declspec(naked) int interlocked_xchg_add( int *dest, int incr )
79 {
80     __asm mov eax, 8[esp];
81     __asm mov edx, 4[esp];
82     __asm lock xadd [edx], eax;
83     __asm ret;
84 }
85
86 #else
87 /* use gcc compatible asm code as default for __i386__ */
88
89 __ASM_GLOBAL_FUNC(interlocked_cmpxchg,
90                   "movl 12(%esp),%eax\n\t"
91                   "movl 8(%esp),%ecx\n\t"
92                   "movl 4(%esp),%edx\n\t"
93                   "lock; cmpxchgl %ecx,(%edx)\n\t"
94                   "ret")
95 __ASM_GLOBAL_FUNC(interlocked_cmpxchg_ptr,
96                   "movl 12(%esp),%eax\n\t"
97                   "movl 8(%esp),%ecx\n\t"
98                   "movl 4(%esp),%edx\n\t"
99                   "lock; cmpxchgl %ecx,(%edx)\n\t"
100                   "ret")
101  __ASM_GLOBAL_FUNC(interlocked_cmpxchg64,
102                    "push %ebx\n\t"
103                    __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
104                    __ASM_CFI(".cfi_rel_offset %ebx,0\n\t")
105                    "push %esi\n\t"
106                    __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
107                    __ASM_CFI(".cfi_rel_offset %esi,0\n\t")
108                    "movl 12(%esp),%esi\n\t"
109                    "movl 16(%esp),%ebx\n\t"
110                    "movl 20(%esp),%ecx\n\t"
111                    "movl 24(%esp),%eax\n\t"
112                    "movl 28(%esp),%edx\n\t"
113                    "lock; cmpxchg8b (%esi)\n\t"
114                    "pop %esi\n\t"
115                    __ASM_CFI(".cfi_same_value %esi\n\t")
116                    __ASM_CFI(".cfi_adjust_cfa_offset -4\n\t")
117                    "pop %ebx\n\t"
118                    __ASM_CFI(".cfi_same_value %ebx\n\t")
119                    __ASM_CFI(".cfi_adjust_cfa_offset -4\n\t")
120                    "ret")
121 __ASM_GLOBAL_FUNC(interlocked_xchg,
122                   "movl 8(%esp),%eax\n\t"
123                   "movl 4(%esp),%edx\n\t"
124                   "lock; xchgl %eax,(%edx)\n\t"
125                   "ret")
126 __ASM_GLOBAL_FUNC(interlocked_xchg_ptr,
127                   "movl 8(%esp),%eax\n\t"
128                   "movl 4(%esp),%edx\n\t"
129                   "lock; xchgl %eax,(%edx)\n\t"
130                   "ret")
131 __ASM_GLOBAL_FUNC(interlocked_xchg_add,
132                   "movl 8(%esp),%eax\n\t"
133                   "movl 4(%esp),%edx\n\t"
134                   "lock; xaddl %eax,(%edx)\n\t"
135                   "ret")
136
137 #endif
138
139 #elif defined(__x86_64__)
140
141 __ASM_GLOBAL_FUNC(interlocked_cmpxchg,
142                   "mov %edx, %eax\n\t"
143                   "lock cmpxchgl %esi,(%rdi)\n\t"
144                   "ret")
145 __ASM_GLOBAL_FUNC(interlocked_cmpxchg_ptr,
146                   "mov %rdx, %rax\n\t"
147                   "lock cmpxchgq %rsi,(%rdi)\n\t"
148                   "ret")
149 __ASM_GLOBAL_FUNC(interlocked_cmpxchg64,
150                   "mov %rdx, %rax\n\t"
151                   "lock cmpxchgq %rsi,(%rdi)\n\t"
152                   "ret")
153 __ASM_GLOBAL_FUNC(interlocked_xchg,
154                   "mov %esi, %eax\n\t"
155                   "lock xchgl %eax, (%rdi)\n\t"
156                   "ret")
157 __ASM_GLOBAL_FUNC(interlocked_xchg_ptr,
158                   "mov %rsi, %rax\n\t"
159                   "lock xchgq %rax,(%rdi)\n\t"
160                   "ret")
161 __ASM_GLOBAL_FUNC(interlocked_xchg_add,
162                   "mov %esi, %eax\n\t"
163                   "lock xaddl %eax, (%rdi)\n\t"
164                   "ret")
165 __ASM_GLOBAL_FUNC(interlocked_cmpxchg128,
166                   "push %rbx\n\t"
167                    ".cfi_adjust_cfa_offset 8\n\t"
168                    ".cfi_rel_offset %rbx,0\n\t"
169                   "mov %rcx,%r8\n\t"  /* compare */
170                   "mov %rdx,%rbx\n\t" /* xchg_low */
171                   "mov %rsi,%rcx\n\t" /* xchg_high */
172                   "mov 0(%r8),%rax\n\t"
173                   "mov 8(%r8),%rdx\n\t"
174                   "lock cmpxchg16b (%rdi)\n\t"
175                   "mov %rax,0(%r8)\n\t"
176                   "mov %rdx,8(%r8)\n\t"
177                   "setz %al\n\t"
178                   "pop %rbx\n\t"
179                    ".cfi_adjust_cfa_offset -8\n\t"
180                    ".cfi_same_value %rbx\n\t"
181                   "ret")
182
183 #elif defined(__powerpc__)
184 void* interlocked_cmpxchg_ptr( void **dest, void* xchg, void* compare)
185 {
186     void *ret = 0;
187     void *scratch;
188     __asm__ __volatile__(
189         "0:    lwarx %0,0,%2\n"
190         "      xor. %1,%4,%0\n"
191         "      bne 1f\n"
192         "      stwcx. %3,0,%2\n"
193         "      bne- 0b\n"
194         "      isync\n"
195         "1:    "
196         : "=&r"(ret), "=&r"(scratch)
197         : "r"(dest), "r"(xchg), "r"(compare)
198         : "cr0","memory");
199     return ret;
200 }
201
202 __int64 interlocked_cmpxchg64( __int64 *dest, __int64 xchg, __int64 compare)
203 {
204     /* FIXME: add code */
205     assert(0);
206 }
207
208 int interlocked_cmpxchg( int *dest, int xchg, int compare)
209 {
210     int ret = 0;
211     int scratch;
212     __asm__ __volatile__(
213         "0:    lwarx %0,0,%2\n"
214         "      xor. %1,%4,%0\n"
215         "      bne 1f\n"
216         "      stwcx. %3,0,%2\n"
217         "      bne- 0b\n"
218         "      isync\n"
219         "1:    "
220         : "=&r"(ret), "=&r"(scratch)
221         : "r"(dest), "r"(xchg), "r"(compare)
222         : "cr0","memory","r0");
223     return ret;
224 }
225
226 int interlocked_xchg_add( int *dest, int incr )
227 {
228     int ret = 0;
229     int zero = 0;
230     __asm__ __volatile__(
231         "0:    lwarx %0, %3, %1\n"
232         "      add %0, %2, %0\n"
233         "      stwcx. %0, %3, %1\n"
234         "      bne- 0b\n"
235         "      isync\n"
236         : "=&r" (ret)
237         : "r"(dest), "r"(incr), "r"(zero)
238         : "cr0", "memory", "r0"
239     );
240     return ret-incr;
241 }
242
243 int interlocked_xchg( int* dest, int val )
244 {
245     int ret = 0;
246     __asm__ __volatile__(
247         "0:    lwarx %0,0,%1\n"
248         "      stwcx. %2,0,%1\n"
249         "      bne- 0b\n"
250         "      isync\n"
251         : "=&r"(ret)
252         : "r"(dest), "r"(val)
253         : "cr0","memory","r0");
254     return ret;
255 }
256
257 void* interlocked_xchg_ptr( void** dest, void* val )
258 {
259     void *ret = NULL;
260     __asm__ __volatile__(
261         "0:    lwarx %0,0,%1\n"
262         "      stwcx. %2,0,%1\n"
263         "      bne- 0b\n"
264         "      isync\n"
265         : "=&r"(ret)
266         : "r"(dest), "r"(val)
267         : "cr0","memory","r0");
268     return ret;
269 }
270
271 #elif defined(__sparc__) && defined(__sun__)
272
273 /*
274  * As the earlier Sparc processors lack necessary atomic instructions,
275  * I'm simply falling back to the library-provided _lwp_mutex routines
276  * to ensure mutual exclusion in a way appropriate for the current
277  * architecture.
278  *
279  * FIXME:  If we have the compare-and-swap instruction (Sparc v9 and above)
280  *         we could use this to speed up the Interlocked operations ...
281  */
282 #include <synch.h>
283 static lwp_mutex_t interlocked_mutex = DEFAULTMUTEX;
284
285 int interlocked_cmpxchg( int *dest, int xchg, int compare )
286 {
287     _lwp_mutex_lock( &interlocked_mutex );
288     if (*dest == compare) *dest = xchg;
289     else compare = *dest;
290     _lwp_mutex_unlock( &interlocked_mutex );
291     return compare;
292 }
293
294 void *interlocked_cmpxchg_ptr( void **dest, void *xchg, void *compare )
295 {
296     _lwp_mutex_lock( &interlocked_mutex );
297     if (*dest == compare) *dest = xchg;
298     else compare = *dest;
299     _lwp_mutex_unlock( &interlocked_mutex );
300     return compare;
301 }
302
303 __int64 interlocked_cmpxchg64( __int64 *dest, __int64 xchg, __int64 compare )
304 {
305     _lwp_mutex_lock( &interlocked_mutex );
306     if (*dest == compare) *dest = xchg;
307     else compare = *dest;
308     _lwp_mutex_unlock( &interlocked_mutex );
309     return compare;
310 }
311
312 int interlocked_xchg( int *dest, int val )
313 {
314     int retv;
315     _lwp_mutex_lock( &interlocked_mutex );
316     retv = *dest;
317     *dest = val;
318     _lwp_mutex_unlock( &interlocked_mutex );
319     return retv;
320 }
321
322 void *interlocked_xchg_ptr( void **dest, void *val )
323 {
324     void *retv;
325     _lwp_mutex_lock( &interlocked_mutex );
326     retv = *dest;
327     *dest = val;
328     _lwp_mutex_unlock( &interlocked_mutex );
329     return retv;
330 }
331
332 int interlocked_xchg_add( int *dest, int incr )
333 {
334     int retv;
335     _lwp_mutex_lock( &interlocked_mutex );
336     retv = *dest;
337     *dest += incr;
338     _lwp_mutex_unlock( &interlocked_mutex );
339     return retv;
340 }
341
342 #elif defined(__ALPHA__) && defined(__GNUC__)
343
344 __ASM_GLOBAL_FUNC(interlocked_cmpxchg,
345                   "L0cmpxchg:\n\t"
346                   "ldl_l $0,0($16)\n\t"
347                   "cmpeq $0,$18,$1\n\t"
348                   "beq   $1,L1cmpxchg\n\t"
349                   "mov   $17,$0\n\t"
350                   "stl_c $0,0($16)\n\t"
351                   "beq   $0,L0cmpxchg\n\t"
352                   "mov   $18,$0\n"
353                   "L1cmpxchg:\n\t"
354                   "mb")
355
356 __ASM_GLOBAL_FUNC(interlocked_cmpxchg_ptr,
357                   "L0cmpxchg_ptr:\n\t"
358                   "ldq_l $0,0($16)\n\t"
359                   "cmpeq $0,$18,$1\n\t"
360                   "beq   $1,L1cmpxchg_ptr\n\t"
361                   "mov   $17,$0\n\t"
362                   "stq_c $0,0($16)\n\t"
363                   "beq   $0,L0cmpxchg_ptr\n\t"
364                   "mov   $18,$0\n"
365                   "L1cmpxchg_ptr:\n\t"
366                   "mb")
367
368 __int64 interlocked_cmpxchg64(__int64 *dest, __int64 xchg, __int64 compare)
369 {
370     /* FIXME: add code */
371     assert(0);
372 }
373
374 __ASM_GLOBAL_FUNC(interlocked_xchg,
375                   "L0xchg:\n\t"
376                   "ldl_l $0,0($16)\n\t"
377                   "mov   $17,$1\n\t"
378                   "stl_c $1,0($16)\n\t"
379                   "beq   $1,L0xchg\n\t"
380                   "mb")
381
382 __ASM_GLOBAL_FUNC(interlocked_xchg_ptr,
383                   "L0xchg_ptr:\n\t"
384                   "ldq_l $0,0($16)\n\t"
385                   "mov   $17,$1\n\t"
386                   "stq_c $1,0($16)\n\t"
387                   "beq   $1,L0xchg_ptr\n\t"
388                   "mb")
389
390 __ASM_GLOBAL_FUNC(interlocked_xchg_add,
391                   "L0xchg_add:\n\t"
392                   "ldl_l $0,0($16)\n\t"
393                   "addl  $0,$17,$1\n\t"
394                   "stl_c $1,0($16)\n\t"
395                   "beq   $1,L0xchg_add\n\t"
396                   "mb")
397
398 #else
399 # error You must implement the interlocked* functions for your CPU
400 #endif