Merge remote-tracking branch 'redux/master' into sh4-pool
[tamarin-stm.git] / platform / win32 / win32-platform.h
blob89d809465adcedc47443c54eb65f31baf38799ab
1 /* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
2 /* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
3 /* -*- tab-width: 4 -*- */
4 /* ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
15 * License.
17 * The Original Code is [Open Source Virtual Machine.].
19 * The Initial Developer of the Original Code is
20 * Adobe System Incorporated.
21 * Portions created by the Initial Developer are Copyright (C) 1993-2006
22 * the Initial Developer. All Rights Reserved.
24 * Contributor(s):
25 * Adobe AS3 Team
27 * Alternatively, the contents of this file may be used under the terms of
28 * either the GNU General Public License Version 2 or later (the "GPL"), or
29 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
41 #ifndef __avmplus_win32_platform__
42 #define __avmplus_win32_platform__
44 #include <stdarg.h>
46 /**
47 * We have avmplus.vcproj compiled with the /W4 warning level
48 * which is quite picky. Disable warnings we don't care about.
50 #ifdef _MSC_VER
51 #pragma warning(disable:4946) // reinterpret_cast used between related classes (bugzilla 615964)
52 #pragma warning(disable:4127) // conditional expression is constant - appears to be compiler noise primarily
53 #pragma warning(disable:4201) // nonstandard extension used : nameless struct/union
54 #pragma warning(disable:4251) // X needs to have dll-interface to be used by clients of class Y
55 #pragma warning(disable:4310) // cast truncates constant value
56 #pragma warning(disable:4511) // can't generate copy ctor
57 #pragma warning(disable:4512) // assignment operator could not be generated
58 #pragma warning(disable:4611) // interaction between '_setjmp' and C++ object destruction is non-portable
59 #pragma warning(disable:4725) // instruction may be inaccurate on some Pentiums
61 // enable some that are off even in /W4 mode, but are still handy
62 #pragma warning(default:4242) // 'identifier' : conversion from 'type1' to 'type2', possible loss of data
63 #pragma warning(default:4263) // 'function' : member function does not override any base class virtual member function
64 #pragma warning(default:4264) // 'virtual_function' : no override available for virtual member function from base 'class'; function is hidden
65 #pragma warning(default:4265) // 'class' : class has virtual functions, but destructor is not virtual
66 #pragma warning(default:4266) // 'function' : no override available for virtual member function from base 'type'; function is hidden
67 #pragma warning(default:4296) // expression is always true (false) (Generally, an unsigned variable was used in a comparison operation with zero.)
68 #pragma warning(default:4905) // wide string literal cast to 'LPSTR'
69 #pragma warning(default:4906) // string literal cast to 'LPWSTR'
71 // some that might be useful to turn on someday, but would require too much twiddly code tweaking right now
72 // #pragma warning(error:4820) // 'bytes' bytes padding added after construct 'member_name' (MSFT system headers generate zillions of these, sadly)
74 /**
75 * Disable PREfast analysis warnings that complain about legitimate usage.
77 #ifdef _PREFAST_
78 // These are triggered by the use of named constants for configuration purposes.
79 // There is nothing wrong with using these in preference to preprocessor conditionalization.
80 #pragma warning(disable:6237) // (<zero> && <expression>) is always zero
81 #pragma warning(disable:6239) // (<non-zero constant> && <expression>) always evaluates to the result of <expression>
83 // This needs to be fixed, but reflects our generally cavalier treatment of stack overflow
84 #pragma warning(disable:6255) // _alloca indicates failure by raising a stack overflow exception
85 #endif
86 #endif // _MSC_VER
88 #define VMPI_memcpy ::memcpy
89 #define VMPI_memset ::memset
90 #define VMPI_memcmp ::memcmp
91 #define VMPI_memmove ::memmove
92 #define VMPI_memchr ::memchr
93 #define VMPI_strcmp ::strcmp
94 #define VMPI_strcat ::strcat
95 #define VMPI_strchr ::strchr
96 #define VMPI_strrchr ::strrchr
97 #define VMPI_strcpy ::strcpy
98 #define VMPI_strlen ::strlen
99 #define VMPI_strncat ::strncat
100 #define VMPI_strncmp ::strncmp
101 #define VMPI_strncpy ::strncpy
102 #define VMPI_strtol ::strtol
103 #define VMPI_strstr ::strstr
105 #define VMPI_sprintf ::sprintf
106 #define VMPI_sscanf ::sscanf
108 // Print rest args into s according to format. The size of s is n. A NUL
109 // terminator is always written. Returns the number of characters written,
110 // not including the NUL. (Hence the return value is always 0..n-1.)
112 int VMPI_snprintf(char *s, size_t n, const char *format, ...);
114 // As for VMPI_snprintf but with an argument list instead of rest args.
116 int VMPI_vsnprintf(char *s, size_t n, const char *format, va_list args);
118 #define VMPI_atoi ::atoi
119 // these aren't prefixed b/c off winmo/pcre problems with ? : expressions
120 #define VMPI_tolower tolower
121 #define VMPI_islower islower
122 #define VMPI_toupper toupper
123 #define VMPI_isupper isupper
124 #define VMPI_isdigit isdigit
125 #define VMPI_isalnum isalnum
126 #define VMPI_isxdigit isxdigit
127 #define VMPI_isspace isspace
128 #define VMPI_isgraph isgraph
129 #define VMPI_isprint isprint
130 #define VMPI_ispunct ispunct
131 #define VMPI_iscntrl iscntrl
132 #define VMPI_isalpha isalpha
133 #ifdef UNDER_CE
134 #define VMPI_abort() ::TerminateProcess(GetCurrentProcess(), 0)
135 #else
136 #define VMPI_abort ::abort
137 #endif
139 #define VMPI_exit ::exit
141 #include <stddef.h>
142 #include <memory.h>
143 #include <string.h>
144 #include <stdio.h>
145 #include <stdlib.h>
146 #include <stdarg.h>
147 #include <math.h>
149 #include <ctype.h>
150 #include <limits.h>
152 #include <windows.h>
153 #include <malloc.h>
155 #if defined(UNDER_CE)
156 // winmo complains if we try to include <new> and it complains if someone else includes new before us so...
157 #ifndef __PLACEMENT_NEW_INLINE
158 #define __PLACEMENT_NEW_INLINE
159 inline void* operator new(size_t, void* p) { return p; }
160 #endif
161 #else
162 // others want the system new
163 #include <new>
164 #endif
166 #ifdef _ARM_
167 // Windows Mobile doesn't provide intptr_t or uintptr_t
168 typedef __int32 intptr_t;
169 typedef unsigned __int32 uintptr_t;
170 #endif
172 typedef void *maddr_ptr;
174 // Set up a jmp_buf suitable for VMPI_longjmpNoUnwind.
175 //#define VMPI_setjmpNoUnwind ::setjmp
177 // Jump to an active jmp_buf that was set up by VMPI_setjmpNoUnwind.
178 // Under no circumstances may C++ destructors be unwound during the
179 // jump (MSVC likes to do this by default).
180 //#define VMPI_longjmpNoUnwind ::longjmp
182 #ifdef VMCFG_64BIT
183 #include <setjmpex.h>
184 extern "C"
186 _int64 __cdecl longjmp64(jmp_buf jmpbuf, _int64 arg);
188 #define VMPI_setjmpNoUnwind ::setjmp
189 #define VMPI_longjmpNoUnwind ::longjmp64
190 #else
191 #include <setjmp.h>
192 #define VMPI_setjmpNoUnwind ::setjmp
193 #define VMPI_longjmpNoUnwind ::longjmp
194 #endif
196 #ifndef UNDER_CE
197 // Newer versions of the Windows SDK set up the intrinsics slightly differently
198 // than VC8. Only include intrin.h if the SDK doesn't declare it.
199 #ifndef InterlockedBitTestAndSet
200 #include <intrin.h>
201 #endif
202 #include <emmintrin.h>
204 #ifdef VMCFG_VTUNE
205 #include "JITProfiling.h"
206 #endif
207 #endif
209 // Windows doesn't support inttypes.h or most C99 types directly
210 typedef __int8 int8_t;
211 typedef __int16 int16_t;
212 typedef __int32 int32_t;
213 typedef __int64 int64_t;
214 typedef unsigned __int8 uint8_t;
215 typedef unsigned __int16 uint16_t;
216 typedef unsigned __int32 uint32_t;
217 typedef unsigned __int64 uint64_t;
219 // This must come after all the include files
220 #if defined _MSC_VER && !defined DEBUG
221 #pragma intrinsic(memcmp)
222 #pragma intrinsic(memcpy)
223 #pragma intrinsic(memset)
224 #pragma intrinsic(strlen)
225 #pragma intrinsic(strcpy)
226 #pragma intrinsic(strcat)
227 #endif
229 #if _MSC_VER
230 #define REALLY_INLINE __forceinline
231 #define FASTCALL __fastcall
232 #elif __GNUC__
233 #define FASTCALL __attribute__((fastcall))
234 #else
235 #define FASTCALL
236 #endif
238 #if defined(_MSC_VER)
239 #define AVMPLUS_ALIGN8(type) __declspec(align(8)) type
240 #define AVMPLUS_ALIGN16(type) __declspec(align(16)) type
241 #elif defined(__GNUC__)
242 #define AVMPLUS_ALIGN8(type) type __attribute__ ((aligned (8)))
243 #define AVMPLUS_ALIGN16(type) type __attribute__ ((aligned (16)))
244 #else
245 #error "Unrecognized compiler"
246 #endif
248 #if defined(_MSC_VER) && _MSC_VER < 1400 && defined(VMCFG_NANOJIT)
249 #define NJ_NO_VARIADIC_MACROS
250 #endif
253 * Type defintion for an opaque data type representing platform-defined spin lock
254 * @see VMPI_lockInit(), VMPI_lockAcquire()
256 struct vmpi_spin_lock_t
258 volatile LONG lock;
261 REALLY_INLINE void VMPI_lockInit(vmpi_spin_lock_t* lock)
263 lock->lock = 0;
266 REALLY_INLINE void VMPI_lockDestroy(vmpi_spin_lock_t* lock)
268 lock->lock = 0;
271 REALLY_INLINE bool VMPI_lockAcquire(vmpi_spin_lock_t *lock)
273 int tries = 0;
274 while (::InterlockedCompareExchange((LPLONG)&lock->lock, 1, 0) != 0)
276 ++tries;
277 // We used to reset to zero if we got to 100. This resets to 0 at 64 instead, with no branch.
278 tries &= 63;
279 // if tries == 0, we just rolled over 64, so we Sleep(1) to give other threads a chance to run... otherwise we Sleep(0)
280 ::Sleep(tries == 0);
282 return true;
285 REALLY_INLINE bool VMPI_lockRelease(vmpi_spin_lock_t *lock)
287 ::InterlockedExchange((LPLONG)&lock->lock, 0);
288 return true;
291 REALLY_INLINE bool VMPI_lockTestAndAcquire(vmpi_spin_lock_t *lock)
293 return ::InterlockedCompareExchange((LPLONG)&lock->lock, 1, 0) == 0;
296 REALLY_INLINE int32_t VMPI_atomicIncAndGet32WithBarrier(volatile int32_t* value)
298 #ifdef UNDER_CE
299 return InterlockedIncrement(const_cast<LONG*>((volatile LONG*)value)); // Barrier semantics are not actually documented
300 #else
301 return InterlockedIncrement((volatile LONG*)value);
302 #endif
305 REALLY_INLINE int32_t VMPI_atomicIncAndGet32(volatile int32_t* value)
307 // No barrier-less version is available
308 return VMPI_atomicIncAndGet32WithBarrier(value);
311 REALLY_INLINE int32_t VMPI_atomicDecAndGet32WithBarrier(volatile int32_t* value)
313 #ifdef UNDER_CE
314 return InterlockedDecrement(const_cast<LONG*>((volatile LONG*)value)); // Barrier semantics are not actually documented
315 #else
316 return InterlockedDecrement((volatile LONG*)value);
317 #endif
320 REALLY_INLINE int32_t VMPI_atomicDecAndGet32(volatile int32_t* value)
322 // No barrier-less version is available
323 return VMPI_atomicDecAndGet32WithBarrier(value);
326 REALLY_INLINE bool VMPI_compareAndSwap32WithBarrier(int32_t oldValue, int32_t newValue, volatile int32_t* address)
328 #ifdef UNDER_CE
329 return InterlockedCompareExchange(const_cast<LONG*>((volatile LONG*)address), newValue, oldValue) == oldValue; // Barrier semantics are not actually documented
330 #else
331 return InterlockedCompareExchange((volatile LONG*)address, newValue, oldValue) == oldValue;
332 #endif
335 REALLY_INLINE bool VMPI_compareAndSwap32(int32_t oldValue, int32_t newValue, volatile int32_t* address)
337 return VMPI_compareAndSwap32WithBarrier(oldValue, newValue, address);
340 REALLY_INLINE void VMPI_memoryBarrier()
342 // FIXME: bug 609820 Memory barrier (fence) for win32
344 // void MemoryBarrier(void) is only available >= Vista
345 // This is a temp solution until we have a x86 asm version.
346 volatile int32_t dummy;
347 VMPI_atomicIncAndGet32WithBarrier(&dummy);
351 * Threads waiting on a conditional variable are recorded in a list
352 * of WaitingThread structs.
354 struct WaitingThread {
355 WaitingThread* next;
356 DWORD threadID;
357 bool notified;
361 * A condition variable is implemented as a linked list of waiting threads.
362 * The variable itself needs to record only the head and the tail of the list.
364 struct vmpi_condvar_t {
365 WaitingThread* head;
366 WaitingThread* tail;
369 typedef DWORD vmpi_thread_t;
370 typedef CRITICAL_SECTION vmpi_mutex_t;
371 typedef LPVOID vmpi_thread_arg_t; // Argument type for thread start function
372 typedef DWORD vmpi_thread_rtn_t; // Return type for thread start function
373 typedef LPTHREAD_START_ROUTINE vmpi_thread_start_t;
375 struct vmpi_thread_attr_t {
376 size_t stackSize;
377 size_t guardSize;
378 int priority;
381 #define VMPI_THREAD_START_CC WINAPI
383 REALLY_INLINE bool VMPI_recursiveMutexInit(vmpi_mutex_t* mutex)
385 InitializeCriticalSection(mutex);
386 return true;
389 REALLY_INLINE bool VMPI_recursiveMutexDestroy(vmpi_mutex_t* mutex)
391 DeleteCriticalSection(mutex);
392 return true;
395 REALLY_INLINE bool VMPI_recursiveMutexTryLock(vmpi_mutex_t* mutex)
397 return TryEnterCriticalSection(mutex) != 0;
400 REALLY_INLINE void VMPI_recursiveMutexLock(vmpi_mutex_t* mutex)
402 EnterCriticalSection(mutex);
405 REALLY_INLINE void VMPI_recursiveMutexUnlock(vmpi_mutex_t* mutex)
407 LeaveCriticalSection(mutex);
410 REALLY_INLINE bool VMPI_condVarInit(vmpi_condvar_t* condvar)
412 condvar->head = NULL;
413 condvar->tail = NULL;
414 return true;
417 REALLY_INLINE bool VMPI_condVarDestroy(vmpi_condvar_t* condvar)
419 (void)condvar;
420 return true;
423 REALLY_INLINE vmpi_thread_t VMPI_currentThread()
425 return (vmpi_thread_t) (uintptr_t)GetCurrentThreadId();
428 REALLY_INLINE bool VMPI_tlsSetValue(uintptr_t tlsId, void* value)
430 return TlsSetValue((DWORD)tlsId, value) == TRUE;
433 REALLY_INLINE void* VMPI_tlsGetValue(uintptr_t tlsId)
435 return TlsGetValue((DWORD)tlsId);
438 REALLY_INLINE void VMPI_threadYield()
440 #ifdef UNDER_CE
441 Sleep(1);
442 #else
443 SwitchToThread();
444 #endif
447 #endif // __avmplus_win32_platform__