summaryrefslogtreecommitdiff
path: root/tools/setjmp_t.c
blob: c2f19d84d1a66465d8a17dea35d393fe2c958ef9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
/*
 * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
 *
 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
 * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
 *
 * Permission is hereby granted to use or copy this program
 * for any purpose, provided the above notices are retained on all copies.
 * Permission to modify the code and to distribute modified code is granted,
 * provided the above notices are retained, and a notice that the code was
 * modified is included with the above copyright notice.
 */

/* Check whether setjmp actually saves registers in jmp_buf. */
/* If it doesn't, the generic mark_regs code won't work.     */
/* Compilers vary as to whether they will put x in a         */
/* (callee-save) register without -O.  The code is           */
/* contrived such that any decent compiler should put x in   */
/* a callee-save register with -O.  Thus it is               */
/* recommended that this be run optimized.  (If the machine  */
/* has no callee-save registers, then the generic code is    */
/* safe, but this will not be noticed by this piece of       */
/* code.)  This test appears to be far from perfect.         */

#include <stdio.h>
#include <setjmp.h>
#include <string.h>

#include "private/gc_priv.h"

#ifdef OS2
# define INCL_DOSERRORS
# define INCL_DOSFILEMGR
# define INCL_DOSMISC
# include <os2.h>

  /* Similar to that in os_dep.c but use fprintf() to report a failure. */
  /* GETPAGESIZE() macro is defined to os2_getpagesize().               */
  static int os2_getpagesize(void)
  {
    ULONG result[1];

    if (DosQuerySysInfo(QSV_PAGE_SIZE, QSV_PAGE_SIZE,
                        (void *)result, sizeof(ULONG)) != NO_ERROR) {
        fprintf(stderr, "DosQuerySysInfo failed\n");
        result[0] = 4096;
    }
    return (int)result[0];
  }

#elif defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
  static int win32_getpagesize(void)
  {
    SYSTEM_INFO sysinfo;
    GetSystemInfo(&sysinfo);
    return sysinfo.dwPageSize;
  }
# define GETPAGESIZE() win32_getpagesize()
#endif

struct a_s {
  char a_a;
  char * a_b;
} a;

word nested_sp(void)
{
# if GC_GNUC_PREREQ(4, 0)
    return (word)__builtin_frame_address(0);
# else
    volatile word sp;
    sp = (word)(&sp);
    return sp;
# endif
}

/* To prevent nested_sp inlining. */
word (*volatile nested_sp_fn)(void) = nested_sp;

int g(int x);

#if defined(CPPCHECK) || !defined(__cplusplus)
  const char *a_str = "a";
#else
# define a_str "a"
#endif

int main(void)
{
    volatile word sp;
    unsigned ps = GETPAGESIZE();
    JMP_BUF b;
#   if !defined(__cplusplus) || __cplusplus < 201703L /* before c++17 */
      register
#   endif
      int x = (int)strlen(a_str); /* 1, slightly disguised */
    static volatile int y = 0;

    sp = (word)(&sp);
    printf("This appears to be a %s running %s\n", MACH_TYPE, OS_TYPE);
#   if defined(CPPCHECK)
      (void)nested_sp(); /* to workaround a bug in cppcheck */
#   endif
    if (nested_sp_fn() < sp) {
      printf("Stack appears to grow down, which is the default.\n");
      printf("A good guess for STACKBOTTOM on this machine is 0x%lx.\n",
             ((unsigned long)sp + ps) & ~(ps-1));
    } else {
      printf("Stack appears to grow up.\n");
      printf("Define STACK_GROWS_UP in gc_priv.h\n");
      printf("A good guess for STACKBOTTOM on this machine is 0x%lx.\n",
             ((unsigned long)sp + ps) & ~(ps-1));
    }
    printf("Note that this may vary between machines of ostensibly\n");
    printf("the same architecture (e.g. Sun 3/50s and 3/80s).\n");
    printf("On many machines the value is not fixed.\n");
    printf("A good guess for ALIGNMENT on this machine is %lu.\n",
           (unsigned long)((word)(&(a.a_b)) - (word)(&a)));

    printf("The following is a very dubious test of one root marking"
           " strategy.\n");
    printf("Results may not be accurate/useful:\n");
    /* Encourage the compiler to keep x in a callee-save register */
    x = 2*x-1;
    printf("\n");
    x = 2*x-1;
    (void)SETJMP(b);
    if (y == 1) {
      if (x == 2) {
        printf("setjmp-based generic mark_regs code probably won't work.\n");
        printf("But we rarely try that anymore.  If you have getcontect()\n");
        printf("this probably doesn't matter.\n");
      } else if (x == 1) {
          printf("setjmp-based register marking code may work.\n");
      } else {
          printf("Very strange setjmp implementation.\n");
      }
    }
    y++;
    x = 2;
    if (y == 1) LONGJMP(b, 1);
    printf("Some GC internal configuration stuff: \n");
    printf("\tWORDSZ = %lu, ALIGNMENT = %d, GC_GRANULE_BYTES = %d\n",
           (unsigned long)WORDSZ, ALIGNMENT, GC_GRANULE_BYTES);
    printf("\tUsing one mark ");
#   if defined(USE_MARK_BYTES)
      printf("byte");
#   else
      printf("bit");
#   endif
    printf(" per ");
#   if defined(MARK_BIT_PER_OBJ)
      printf("object.\n");
#   elif defined(MARK_BIT_PER_GRANULE)
      printf("granule.\n");
#   endif
#   ifdef THREAD_LOCAL_ALLOC
      printf("Thread local allocation enabled.\n");
#   endif
#   ifdef PARALLEL_MARK
      printf("Parallel marking enabled.\n");
#   endif
    (void)g(x);
    return 0;
}

int g(int x)
{
    return x;
}