1 /*
2 * Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
3 *
4 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
5 * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
6 *
7 * Permission is hereby granted to use or copy this program
8 * for any purpose, provided the above notices are retained on all copies.
9 * Permission to modify the code and to distribute modified code is granted,
10 * provided the above notices are retained, and a notice that the code was
11 * modified is included with the above copyright notice.
12 */
13 14 /*
15 * Check whether `setjmp` actually saves registers in `jmp_buf`.
16 * If it does not, the generic code in `GC_with_callee_saves_pushed`
17 * will not work. Compilers vary as to whether they will put `x` in
18 * a (callee-save) register without `-O` flag. The code is contrived
19 * such that any decent compiler should put `x` in a callee-save register
20 * with `-O` flag. Thus it is recommended that this be run optimized.
21 * (If the machine has no callee-save registers, then the generic code
22 * is safe, but this will not be noticed by this piece of code.)
23 * This test appears to be far from perfect.
24 */
25 26 #define NOT_GCBUILD
27 #include "private/gc_priv.h"
28 29 #include <string.h>
30 31 #ifdef OS2
32 # define INCL_DOSERRORS
33 # define INCL_DOSFILEMGR
34 # define INCL_DOSMISC
35 # include <os2.h>
36 37 /*
38 * Similar to that in `os_dep.c` file but use `fprintf` to report a failure.
39 * `GETPAGESIZE()` macro is defined to `os2_getpagesize()`.
40 */
41 static int
42 os2_getpagesize(void)
43 {
44 ULONG result[1];
45 46 if (DosQuerySysInfo(QSV_PAGE_SIZE, QSV_PAGE_SIZE, (void *)result,
47 sizeof(ULONG))
48 != NO_ERROR) {
49 fprintf(stderr, "DosQuerySysInfo failed\n");
50 result[0] = 4096;
51 }
52 return (int)result[0];
53 }
54 55 #elif defined(ANY_MSWIN)
56 static int
57 win32_getpagesize(void)
58 {
59 SYSTEM_INFO sysinfo;
60 GetSystemInfo(&sysinfo);
61 return sysinfo.dwPageSize;
62 }
63 # define GETPAGESIZE() win32_getpagesize()
64 #endif
65 66 struct a_s {
67 char a_a;
68 char *a_b;
69 } a;
70 71 GC_ATTR_NOINLINE
72 static word
73 nested_sp(void)
74 {
75 volatile ptr_t sp;
76 77 STORE_APPROX_SP_TO(sp);
78 return ADDR(sp);
79 }
80 81 /* To prevent `nested_sp` inlining. */
82 word (*volatile nested_sp_fn)(void) = nested_sp;
83 84 int g(int x);
85 86 #if (defined(CPPCHECK) || !defined(__cplusplus)) && !defined(WASI)
87 const char *a_str = "a";
88 #else
89 # define a_str "a"
90 #endif
91 92 int
93 main(void)
94 {
95 volatile ptr_t sp;
96 unsigned ps = GETPAGESIZE();
97 #ifndef WASI
98 JMP_BUF b;
99 # if (!defined(__cplusplus) || __cplusplus < 201703L /* before c++17 */) \
100 && (!defined(__GNUC__) || defined(__OPTIMIZE__))
101 register
102 # endif
103 int x
104 = (int)strlen(a_str); /*< 1, slightly disguised */
105 static volatile int y = 0;
106 #endif
107 108 STORE_APPROX_SP_TO(sp);
109 printf("This appears to be a %s running %s\n", MACH_TYPE, OS_TYPE);
110 #if defined(CPPCHECK)
111 (void)nested_sp(); /*< to workaround a bug in cppcheck */
112 #endif
113 if (nested_sp_fn() < ADDR(sp)) {
114 printf("Stack appears to grow down, which is the default.\n");
115 printf("A good guess for STACKBOTTOM on this machine is 0x%lx.\n",
116 ((unsigned long)ADDR(sp) + ps) & ~(unsigned long)(ps - 1));
117 } else {
118 printf("Stack appears to grow up.\n");
119 printf("Define STACK_GROWS_UP in gc_priv.h\n");
120 /* Note: `sp` is rounded down. */
121 printf("A good guess for STACKBOTTOM on this machine is 0x%lx.\n",
122 (unsigned long)ADDR(sp) & ~(unsigned long)(ps - 1));
123 }
124 printf("Note that this may vary between machines of ostensibly\n");
125 printf("the same architecture (e.g. Sun 3/50s and 3/80s).\n");
126 printf("On many machines the value is not fixed.\n");
127 printf("A good guess for ALIGNMENT on this machine is %lu.\n",
128 (unsigned long)(ADDR(&a.a_b) - ADDR(&a)));
129 #ifndef WASI
130 printf("The following is a very dubious test of one root marking"
131 " strategy.\n");
132 printf("Results may not be accurate/useful:\n");
133 /* Encourage the compiler to keep `x` in a callee-save register. */
134 x = 2 * x - 1;
135 printf("\n");
136 x = 2 * x - 1;
137 (void)SETJMP(b);
138 if (y == 1) {
139 if (x == 2) {
140 printf("setjmp-based generic mark_regs code probably won't work.\n");
141 printf("But we rarely try that anymore. If you have getcontect()\n");
142 printf("this probably doesn't matter.\n");
143 } else if (x == 1) {
144 printf("setjmp-based register marking code may work.\n");
145 } else {
146 printf("Very strange setjmp implementation.\n");
147 }
148 }
149 y++;
150 x = 2;
151 if (y == 1)
152 LONGJMP(b, 1);
153 #endif
154 printf("Some GC internal configuration stuff: \n");
155 printf("\tWORDSZ = %lu, ALIGNMENT = %d, GC_GRANULE_BYTES = %d\n",
156 (unsigned long)CPP_WORDSZ, ALIGNMENT, GC_GRANULE_BYTES);
157 printf("\tUsing one mark ");
158 #ifdef USE_MARK_BYTES
159 printf("byte");
160 #else
161 printf("bit");
162 #endif
163 #ifdef MARK_BIT_PER_OBJ
164 printf(" per object.\n");
165 #else
166 printf(" per granule.\n");
167 #endif
168 #ifdef THREAD_LOCAL_ALLOC
169 printf("Thread-local allocation enabled.\n");
170 #endif
171 #ifdef PARALLEL_MARK
172 printf("Parallel marking enabled.\n");
173 #endif
174 #ifdef WASI
175 (void)g(0);
176 #else
177 (void)g(x);
178 #endif
179 return 0;
180 }
181 182 int
183 g(int x)
184 {
185 return x;
186 }
187