1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4// ===========================================================================
5// File: palclr.h
6//
7// Various macros and constants that are necessary to make the CLR portable.
8//
9
10// ===========================================================================
11
12
13#if !defined(FEATURE_PAL)
14
15#ifndef __PALCLR_H__
16#define __PALCLR_H__
17
18// This macro is used to standardize the wide character string literals between UNIX and Windows.
19// Unix L"" is UTF32, and on windows it's UTF16. Because of built-in assumptions on the size
20// of string literals, it's important to match behaviour between Unix and Windows. Unix will be defined
21// as u"" (char16_t)
22#ifdef PLATFORM_UNIX
23#define W(str) u##str
24#else // PLATFORM_UNIX
25#define W(str) L##str
26#endif // PLATFORM_UNIX
27
28#include <windef.h>
29
30#if !defined(_DEBUG_IMPL) && defined(_DEBUG) && !defined(DACCESS_COMPILE)
31#define _DEBUG_IMPL 1
32#endif
33
34//
35// CPP_ASSERT() can be used within a class definition, to perform a
36// compile-time assertion involving private names within the class.
37//
38// MS compiler doesn't allow redefinition of the typedef within a template.
39// gcc doesn't allow redefinition of the typedef within a class, though
40// it does at file scope.
41#define CPP_ASSERT(n, e) typedef char __C_ASSERT__##n[(e) ? 1 : -1];
42
43
44// PORTABILITY_ASSERT and PORTABILITY_WARNING macros are meant to be used to
45// mark places in the code that needs attention for portability. The usual
46// usage pattern is:
47//
48// int get_scratch_register() {
49// #if defined(_TARGET_X86_)
50// return eax;
51// #elif defined(_TARGET_AMD64_)
52// return rax;
53// #elif defined(_TARGET_ARM_)
54// return r0;
55// #else
56// PORTABILITY_ASSERT("scratch register");
57// return 0;
58// #endif
59// }
60//
61// PORTABILITY_ASSERT is meant to be used inside functions/methods. It can
62// introduce compile-time and/or run-time errors.
63// PORTABILITY_WARNING is meant to be used outside functions/methods. It can
64// introduce compile-time errors or warnings only.
65//
66// People starting new ports will first define these to just cause run-time
67// errors. Once they fix all the places that need attention for portability,
68// they can define PORTABILITY_ASSERT and PORTABILITY_WARNING to cause
69// compile-time errors to make sure that they haven't missed anything.
70//
71// If it is reasonably possible all codepaths containing PORTABILITY_ASSERT
72// should be compilable (e.g. functions should return NULL or something if
73// they are expected to return a value).
74//
75// The message in these two macros should not contain any keywords like TODO
76// or NYI. It should be just the brief description of the problem.
77
78#if defined(_TARGET_X86_)
79// Finished ports - compile-time errors
80#define PORTABILITY_WARNING(message) NEED_TO_PORT_THIS_ONE(NEED_TO_PORT_THIS_ONE)
81#define PORTABILITY_ASSERT(message) NEED_TO_PORT_THIS_ONE(NEED_TO_PORT_THIS_ONE)
82#else
83// Ports in progress - run-time asserts only
84#define PORTABILITY_WARNING(message)
85#define PORTABILITY_ASSERT(message) _ASSERTE(false && message)
86#endif
87
88#define DIRECTORY_SEPARATOR_CHAR_A '\\'
89#define DIRECTORY_SEPARATOR_STR_A "\\"
90#define DIRECTORY_SEPARATOR_CHAR_W W('\\')
91#define DIRECTORY_SEPARATOR_STR_W W("\\")
92
93#define PATH_SEPARATOR_CHAR_W W(';')
94#define PATH_SEPARATOR_STR_W W(";")
95
96#define VOLUME_SEPARATOR_CHAR_W W(':')
97
98// PAL Macros
99// Not all compilers support fully anonymous aggregate types, so the
100// PAL provides names for those types. To allow existing definitions of
101// those types to continue to work, we provide macros that should be
102// used to reference fields within those types.
103
104#ifndef DECIMAL_SCALE
105#define DECIMAL_SCALE(dec) ((dec).scale)
106#endif
107
108#ifndef DECIMAL_SIGN
109#define DECIMAL_SIGN(dec) ((dec).sign)
110#endif
111
112#ifndef DECIMAL_SIGNSCALE
113#define DECIMAL_SIGNSCALE(dec) ((dec).signscale)
114#endif
115
116#ifndef DECIMAL_LO32
117#define DECIMAL_LO32(dec) ((dec).Lo32)
118#endif
119
120#ifndef DECIMAL_MID32
121#define DECIMAL_MID32(dec) ((dec).Mid32)
122#endif
123
124#ifndef DECIMAL_HI32
125#define DECIMAL_HI32(dec) ((dec).Hi32)
126#endif
127
128#ifndef DECIMAL_LO64_GET
129#define DECIMAL_LO64_GET(dec) ((dec).Lo64)
130#endif
131
132#ifndef DECIMAL_LO64_SET
133#define DECIMAL_LO64_SET(dec,value) {(dec).Lo64 = value; }
134#endif
135
136#ifndef IMAGE_RELOC_FIELD
137#define IMAGE_RELOC_FIELD(img, f) ((img).f)
138#endif
139
140#ifndef IMAGE_IMPORT_DESC_FIELD
141#define IMAGE_IMPORT_DESC_FIELD(img, f) ((img).f)
142#endif
143
144#define IMAGE_RDE_ID(img) ((img)->Id)
145
146#define IMAGE_RDE_NAME(img) ((img)->Name)
147
148#define IMAGE_RDE_OFFSET(img) ((img)->OffsetToData)
149
150#ifndef IMAGE_RDE_NAME_FIELD
151#define IMAGE_RDE_NAME_FIELD(img, f) ((img)->f)
152#endif
153
154#define IMAGE_RDE_OFFSET_FIELD(img, f) ((img)->f)
155
156#ifndef IMAGE_FE64_FIELD
157#define IMAGE_FE64_FIELD(img, f) ((img).f)
158#endif
159
160#ifndef IMPORT_OBJ_HEADER_FIELD
161#define IMPORT_OBJ_HEADER_FIELD(obj, f) ((obj).f)
162#endif
163
164#ifndef IMAGE_COR20_HEADER_FIELD
165#define IMAGE_COR20_HEADER_FIELD(obj, f) ((obj).f)
166#endif
167
168
169// PAL Numbers
170// Used to ensure cross-compiler compatibility when declaring large
171// integer constants. 64-bit integer constants should be wrapped in the
172// declarations listed here.
173//
174// Each of the #defines here is wrapped to avoid conflicts with pal.h.
175
176#if defined(_MSC_VER)
177
178// MSVC's way of declaring large integer constants
179// If you define these in one step, without the _HELPER macros, you
180// get extra whitespace when composing these with other concatenating macros.
181#ifndef I64
182#define I64_HELPER(x) x ## i64
183#define I64(x) I64_HELPER(x)
184#endif
185
186#ifndef UI64
187#define UI64_HELPER(x) x ## ui64
188#define UI64(x) UI64_HELPER(x)
189#endif
190
191#else
192
193// GCC's way of declaring large integer constants
194// If you define these in one step, without the _HELPER macros, you
195// get extra whitespace when composing these with other concatenating macros.
196#ifndef I64
197#define I64_HELPER(x) x ## LL
198#define I64(x) I64_HELPER(x)
199#endif
200
201#ifndef UI64
202#define UI64_HELPER(x) x ## ULL
203#define UI64(x) UI64_HELPER(x)
204#endif
205
206#endif
207
208
209// PAL SEH
210// Macros for portable exception handling. The Win32 SEH is emulated using
211// these macros and setjmp/longjmp on Unix
212//
213// Usage notes:
214//
215// - The filter has to be a function taking two parameters:
216// LONG MyFilter(PEXCEPTION_POINTERS *pExceptionInfo, PVOID pv)
217//
218// - It is not possible to directly use the local variables in the filter.
219// All the local information that the filter has to need to know about should
220// be passed through pv parameter
221//
222// - Do not use goto to jump out of the PAL_TRY block
223// (jumping out of the try block is not a good idea even on Win32, because of
224// it causes stack unwind)
225//
226// - It is not possible to directly use the local variables in the try block.
227// All the local information that the filter has to need to know about should
228// be passed through pv parameter
229//
230//
231// Simple examples:
232//
233// struct Param { ... local variables used in try block and filter ... } param;
234// PAL_TRY(Param *, pParam, &param) { // read as: Param *pParam = &param;
235// ....
236// } PAL_FINALLY {
237// ....
238// }
239// PAL_ENDTRY
240//
241//
242// struct Param { ... local variables used in try block and filter ... } param;
243// PAL_TRY(Param *, pParam, &param) {
244// ....
245// } PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
246// ....
247// }
248// PAL_ENDTRY
249//
250//
251// LONG MyFilter(PEXCEPTION_POINTERS *pExceptionInfo, PVOID pv)
252// {
253// ...
254// }
255// PAL_TRY(void *, unused, NULL) {
256// ....
257// } PAL_EXCEPT_FILTER(MyFilter) {
258// ....
259// }
260// PAL_ENDTRY
261//
262//
263// Complex example:
264//
265// struct MyParams
266// {
267// ...
268// } params;
269//
270// PAL_TRY(MyParams *, pMyParamsOuter, &params) {
271// PAL_TRY(MyParams *, pMyParamsInnter, pMyParamsOuter) {
272// ...
273// if (error) goto Done;
274// ...
275// Done: ;
276// } PAL_EXCEPT_FILTER(OtherFilter) {
277// ...
278// }
279// PAL_ENDTRY
280// }
281// PAL_FINALLY {
282// }
283// PAL_ENDTRY
284//
285
286#include "staticcontract.h"
287
288#define HardwareExceptionHolder
289
290// Note: PAL_SEH_RESTORE_GUARD_PAGE is only ever defined in clrex.h, so we only restore guard pages automatically
291// when these macros are used from within the VM.
292#define PAL_SEH_RESTORE_GUARD_PAGE
293
294#define PAL_TRY_NAKED \
295 { \
296 bool __exHandled; __exHandled = false; \
297 DWORD __exCode; __exCode = 0; \
298 SCAN_EHMARKER(); \
299 __try \
300 { \
301 SCAN_EHMARKER_TRY();
302
303#define PAL_EXCEPT_NAKED(Disposition) \
304 } \
305 __except(__exCode = GetExceptionCode(), Disposition) \
306 { \
307 __exHandled = true; \
308 SCAN_EHMARKER_CATCH(); \
309 PAL_SEH_RESTORE_GUARD_PAGE
310
311#define PAL_EXCEPT_FILTER_NAKED(pfnFilter, param) \
312 } \
313 __except(__exCode = GetExceptionCode(), \
314 pfnFilter(GetExceptionInformation(), param)) \
315 { \
316 __exHandled = true; \
317 SCAN_EHMARKER_CATCH(); \
318 PAL_SEH_RESTORE_GUARD_PAGE
319
320#define PAL_FINALLY_NAKED \
321 } \
322 __finally \
323 { \
324
325#define PAL_ENDTRY_NAKED \
326 } \
327 PAL_ENDTRY_NAKED_DBG \
328 } \
329
330
331#if defined(_DEBUG) && !defined(DACCESS_COMPILE)
332//
333// In debug mode, compile the try body as a method of a local class.
334// This way, the compiler will check that the body is not directly
335// accessing any local variables and arguments.
336//
337#define PAL_TRY(__ParamType, __paramDef, __paramRef) \
338{ \
339 __ParamType __param = __paramRef; \
340 __ParamType __paramToPassToFilter = __paramRef; \
341 class __Body \
342 { \
343 public: \
344 static void Run(__ParamType __paramDef) \
345 { \
346 PAL_TRY_HANDLER_DBG_BEGIN
347
348// PAL_TRY implementation that abstracts usage of COMPILER_INSTANCE*, which is used by
349// JIT64. On Windows, we dont need to do anything special as we dont have nested classes/methods
350// as on PAL.
351#define PAL_TRY_CI(__ParamType, __paramDef, __paramRef) \
352{ \
353 struct __HandlerData { \
354 __ParamType __param; \
355 COMPILER_INSTANCE *__ciPtr; \
356 }; \
357 __HandlerData handlerData; \
358 handlerData.__param = __paramRef; \
359 handlerData.__ciPtr = ciPtr; \
360 __HandlerData* __param = &handlerData; \
361 __ParamType __paramToPassToFilter = __paramRef; \
362 class __Body \
363 { \
364 public: \
365 static void Run(__HandlerData* __pHandlerData) \
366 { \
367 PAL_TRY_HANDLER_DBG_BEGIN \
368 COMPILER_INSTANCE *ciPtr = __pHandlerData->__ciPtr; \
369 __ParamType __paramDef = __pHandlerData->__param;
370
371
372#define PAL_TRY_FOR_DLLMAIN(__ParamType, __paramDef, __paramRef, __reason) \
373{ \
374 __ParamType __param = __paramRef; \
375 __ParamType __paramToPassToFilter = __paramRef; \
376 class __Body \
377 { \
378 public: \
379 static void Run(__ParamType __paramDef) \
380 { \
381 PAL_TRY_HANDLER_DBG_BEGIN_DLLMAIN(__reason)
382
383#define PAL_EXCEPT(Disposition) \
384 PAL_TRY_HANDLER_DBG_END \
385 } \
386 }; \
387 PAL_TRY_NAKED \
388 __Body::Run(__param); \
389 PAL_EXCEPT_NAKED(Disposition)
390
391#define PAL_EXCEPT_FILTER(pfnFilter) \
392 PAL_TRY_HANDLER_DBG_END \
393 } \
394 }; \
395 PAL_TRY_NAKED \
396 __Body::Run(__param); \
397 PAL_EXCEPT_FILTER_NAKED(pfnFilter, __paramToPassToFilter)
398
399#define PAL_FINALLY \
400 PAL_TRY_HANDLER_DBG_END \
401 } \
402 }; \
403 PAL_TRY_NAKED \
404 __Body::Run(__param); \
405 PAL_FINALLY_NAKED
406
407#define PAL_ENDTRY \
408 PAL_ENDTRY_NAKED \
409}
410
411#else // _DEBUG
412
413#define PAL_TRY(__ParamType, __paramDef, __paramRef) \
414{ \
415 __ParamType __param = __paramRef; \
416 __ParamType __paramDef = __param; \
417 PAL_TRY_NAKED \
418 PAL_TRY_HANDLER_DBG_BEGIN
419
420// PAL_TRY implementation that abstracts usage of COMPILER_INSTANCE*, which is used by
421// JIT64. On Windows, we dont need to do anything special as we dont have nested classes/methods
422// as on PAL.
423#define PAL_TRY_CI(__ParamType, __paramDef, __paramRef) PAL_TRY(__ParamType, __paramDef, __paramRef)
424
425#define PAL_TRY_FOR_DLLMAIN(__ParamType, __paramDef, __paramRef, __reason) \
426{ \
427 __ParamType __param = __paramRef; \
428 __ParamType __paramDef; __paramDef = __param; \
429 PAL_TRY_NAKED \
430 PAL_TRY_HANDLER_DBG_BEGIN_DLLMAIN(__reason)
431
432#define PAL_EXCEPT(Disposition) \
433 PAL_TRY_HANDLER_DBG_END \
434 PAL_EXCEPT_NAKED(Disposition)
435
436#define PAL_EXCEPT_FILTER(pfnFilter) \
437 PAL_TRY_HANDLER_DBG_END \
438 PAL_EXCEPT_FILTER_NAKED(pfnFilter, __param)
439
440#define PAL_FINALLY \
441 PAL_TRY_HANDLER_DBG_END \
442 PAL_FINALLY_NAKED
443
444#define PAL_ENDTRY \
445 PAL_ENDTRY_NAKED \
446 }
447
448#endif // _DEBUG
449
450// Executes the handler if the specified exception code matches
451// the one in the exception. Otherwise, returns EXCEPTION_CONTINUE_SEARCH.
452#define PAL_EXCEPT_IF_EXCEPTION_CODE(dwExceptionCode) PAL_EXCEPT((GetExceptionCode() == dwExceptionCode)?EXCEPTION_EXECUTE_HANDLER:EXCEPTION_CONTINUE_SEARCH)
453
454#define PAL_CPP_TRY try
455#define PAL_CPP_ENDTRY
456#define PAL_CPP_THROW(type, obj) do { SCAN_THROW_MARKER; throw obj; } while (false)
457#define PAL_CPP_RETHROW do { SCAN_THROW_MARKER; throw; } while (false)
458#define PAL_CPP_CATCH_DERIVED(type, obj) catch (type * obj)
459#define PAL_CPP_CATCH_ALL catch (...)
460#define PAL_CPP_CATCH_EXCEPTION_NOARG catch (Exception *)
461
462
463// SELECTANY macro is intended to prevent duplication of static const
464// arrays declared in .h files in binary modules.
465// The problem is that const variables have static internal linkage
466// in C++. That means that if a const variable is declared in a .h file
467// the compiler will emit it into every translation unit that uses that .h file.
468// That will cause duplication of the data when those translation units
469// are linked into a binary module.
470// SELECTANY declares a variable as extern to give it external linkage
471// and it provides __declspec(selectany) to instruct the linker to merge
472// duplicate external const static data copies into one.
473//
474#if defined(SOURCE_FORMATTING)
475#define SELECTANY extern
476#else
477#define SELECTANY extern __declspec(selectany)
478#endif
479#if defined(SOURCE_FORMATTING)
480#define __annotation(x)
481#endif
482
483
484#if defined(_DEBUG_IMPL) && !defined(JIT_BUILD) && !defined(JIT64_BUILD) && !defined(CROSS_COMPILE) && !defined(_TARGET_ARM_) // @ARMTODO: no contracts for speed
485#define PAL_TRY_HANDLER_DBG_BEGIN \
486 BOOL ___oldOkayToThrowValue = FALSE; \
487 SO_INFRASTRUCTURE_CODE(BOOL ___oldSOTolerantState = FALSE;) \
488 ClrDebugState *___pState = ::GetClrDebugState(); \
489 __try \
490 { \
491 ___oldOkayToThrowValue = ___pState->IsOkToThrow(); \
492 SO_INFRASTRUCTURE_CODE(___oldSOTolerantState = ___pState->IsSOTolerant();) \
493 ___pState->SetOkToThrow(); \
494 PAL_ENTER_THROWS_REGION;
495
496// Special version that avoids touching the debug state after doing work in a DllMain for process or thread detach.
497#define PAL_TRY_HANDLER_DBG_BEGIN_DLLMAIN(_reason) \
498 BOOL ___oldOkayToThrowValue = FALSE; \
499 SO_INFRASTRUCTURE_CODE(BOOL ___oldSOTolerantState = FALSE;) \
500 ClrDebugState *___pState = NULL; \
501 if (_reason != DLL_PROCESS_ATTACH) \
502 ___pState = CheckClrDebugState(); \
503 __try \
504 { \
505 if (___pState) \
506 { \
507 ___oldOkayToThrowValue = ___pState->IsOkToThrow(); \
508 SO_INFRASTRUCTURE_CODE(___oldSOTolerantState = ___pState->IsSOTolerant();) \
509 ___pState->SetOkToThrow(); \
510 } \
511 if ((_reason == DLL_PROCESS_DETACH) || (_reason == DLL_THREAD_DETACH)) \
512 { \
513 ___pState = NULL; \
514 } \
515 PAL_ENTER_THROWS_REGION;
516
517#define PAL_TRY_HANDLER_DBG_END \
518 PAL_LEAVE_THROWS_REGION \
519 } \
520 __finally \
521 { \
522 if (___pState != NULL) \
523 { \
524 _ASSERTE(___pState == CheckClrDebugState()); \
525 ___pState->SetOkToThrow( ___oldOkayToThrowValue ); \
526 SO_INFRASTRUCTURE_CODE(___pState->SetSOTolerance( ___oldSOTolerantState );) \
527 } \
528 }
529
530#define PAL_ENDTRY_NAKED_DBG \
531 if (__exHandled) \
532 { \
533 RESTORE_SO_TOLERANCE_STATE; \
534 } \
535
536#else
537#define PAL_TRY_HANDLER_DBG_BEGIN ANNOTATION_TRY_BEGIN;
538#define PAL_TRY_HANDLER_DBG_BEGIN_DLLMAIN(_reason) ANNOTATION_TRY_BEGIN;
539#define PAL_TRY_HANDLER_DBG_END ANNOTATION_TRY_END;
540#define PAL_ENDTRY_NAKED_DBG
541#endif // defined(ENABLE_CONTRACTS_IMPL) && !defined(JIT64_BUILD)
542
543
544#if !BIGENDIAN
545// For little-endian machines, do nothing
546#define VAL16(x) x
547#define VAL32(x) x
548#define VAL64(x) x
549#define SwapString(x)
550#define SwapStringLength(x, y)
551#define SwapGuid(x)
552#endif // !BIGENDIAN
553
554#ifdef _MSC_VER
555// Get Unaligned values from a potentially unaligned object
556#define GET_UNALIGNED_16(_pObject) (*(UINT16 UNALIGNED *)(_pObject))
557#define GET_UNALIGNED_32(_pObject) (*(UINT32 UNALIGNED *)(_pObject))
558#define GET_UNALIGNED_64(_pObject) (*(UINT64 UNALIGNED *)(_pObject))
559
560// Set Value on an potentially unaligned object
561#define SET_UNALIGNED_16(_pObject, _Value) (*(UNALIGNED UINT16 *)(_pObject)) = (UINT16)(_Value)
562#define SET_UNALIGNED_32(_pObject, _Value) (*(UNALIGNED UINT32 *)(_pObject)) = (UINT32)(_Value)
563#define SET_UNALIGNED_64(_pObject, _Value) (*(UNALIGNED UINT64 *)(_pObject)) = (UINT64)(_Value)
564
565// Get Unaligned values from a potentially unaligned object and swap the value
566#define GET_UNALIGNED_VAL16(_pObject) VAL16(GET_UNALIGNED_16(_pObject))
567#define GET_UNALIGNED_VAL32(_pObject) VAL32(GET_UNALIGNED_32(_pObject))
568#define GET_UNALIGNED_VAL64(_pObject) VAL64(GET_UNALIGNED_64(_pObject))
569
570// Set a swap Value on an potentially unaligned object
571#define SET_UNALIGNED_VAL16(_pObject, _Value) SET_UNALIGNED_16(_pObject, VAL16((UINT16)_Value))
572#define SET_UNALIGNED_VAL32(_pObject, _Value) SET_UNALIGNED_32(_pObject, VAL32((UINT32)_Value))
573#define SET_UNALIGNED_VAL64(_pObject, _Value) SET_UNALIGNED_64(_pObject, VAL64((UINT64)_Value))
574#endif
575
576#ifdef _WIN64
577#define VALPTR(x) VAL64(x)
578#define GET_UNALIGNED_PTR(x) GET_UNALIGNED_64(x)
579#define GET_UNALIGNED_VALPTR(x) GET_UNALIGNED_VAL64(x)
580#define SET_UNALIGNED_PTR(p,x) SET_UNALIGNED_64(p,x)
581#define SET_UNALIGNED_VALPTR(p,x) SET_UNALIGNED_VAL64(p,x)
582#else
583#define VALPTR(x) VAL32(x)
584#define GET_UNALIGNED_PTR(x) GET_UNALIGNED_32(x)
585#define GET_UNALIGNED_VALPTR(x) GET_UNALIGNED_VAL32(x)
586#define SET_UNALIGNED_PTR(p,x) SET_UNALIGNED_32(p,x)
587#define SET_UNALIGNED_VALPTR(p,x) SET_UNALIGNED_VAL32(p,x)
588#endif
589
590#define MAKEDLLNAME_W(name) name W(".dll")
591#define MAKEDLLNAME_A(name) name ".dll"
592
593#ifdef UNICODE
594#define MAKEDLLNAME(x) MAKEDLLNAME_W(x)
595#else
596#define MAKEDLLNAME(x) MAKEDLLNAME_A(x)
597#endif
598
599#if !defined(MAX_LONGPATH)
600#define MAX_LONGPATH 260 /* max. length of full pathname */
601#endif
602#if !defined(MAX_PATH_FNAME)
603#define MAX_PATH_FNAME MAX_PATH /* max. length of full pathname */
604#endif
605
606#define __clr_reserved __reserved
607
608#endif // __PALCLR_H__
609
610#include "palclr_win.h"
611
612#endif // !defined(FEATURE_PAL)
613