Upgrade Boehm GC to 7.2alpha4.
[cacao.git] / src / mm / boehm-gc / tests / test_cpp.cc
1 /****************************************************************************
2 Copyright (c) 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 for any
8 purpose, provided the above notices are retained on all copies.
9 Permission to modify the code and to distribute modified code is
10 granted, provided the above notices are retained, and a notice that
11 the code was modified is included with the above copyright notice.
12 ****************************************************************************
13 Last modified on Mon Jul 10 21:06:03 PDT 1995 by ellis
14      modified on December 20, 1994 7:27 pm PST by boehm
15
16 usage: test_cpp number-of-iterations
17
18 This program tries to test the specific C++ functionality provided by
19 gc_c++.h that isn't tested by the more general test routines of the
20 collector.
21
22 A recommended value for number-of-iterations is 10, which will take a
23 few minutes to complete.
24
25 ***************************************************************************/
26
27 #ifdef HAVE_CONFIG_H
28 # include "private/config.h"
29 #endif
30 #undef GC_BUILD
31 #include "gc_cpp.h"
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #define USE_STD_ALLOCATOR
36 #ifdef USE_STD_ALLOCATOR
37 #   include "gc_allocator.h"
38 #elif __GNUC__
39 #   include "new_gc_alloc.h"
40 #else
41 #   include "gc_alloc.h"
42 #endif
43 extern "C" {
44 # include "private/gcconfig.h"
45   GC_API void GC_printf(const char *format, ...);
46   /* Use GC private output to reach the same log file.  */
47   /* Don't include gc_priv.h, since that may include Windows system     */
48   /* header files that don't take kindly to this context.               */
49 }
50 #ifdef MSWIN32
51 #   include <windows.h>
52 #endif
53 #ifdef GC_NAME_CONFLICT
54 #   define USE_GC UseGC
55     struct foo * GC;
56 #else
57 #   define USE_GC GC
58 #endif
59
60
61 #define my_assert( e ) \
62     if (! (e)) { \
63         GC_printf( "Assertion failure in " __FILE__ ", line %d: " #e "\n", \
64                     __LINE__ ); \
65         exit( 1 ); }
66
67
68 class A {public:
69     /* An uncollectable class. */
70
71     A( int iArg ): i( iArg ) {}
72     void Test( int iArg ) {
73         my_assert( i == iArg );}
74     int i;};
75
76
77 class B: public gc, public A {public:
78     /* A collectable class. */
79
80     B( int j ): A( j ) {}
81     ~B() {
82         my_assert( deleting );}
83     static void Deleting( int on ) {
84         deleting = on;}
85     static int deleting;};
86
87 int B::deleting = 0;
88
89
90 class C: public gc_cleanup, public A {public:
91     /* A collectable class with cleanup and virtual multiple inheritance. */
92
93     C( int levelArg ): A( levelArg ), level( levelArg ) {
94         nAllocated++;
95         if (level > 0) {
96             left = new C( level - 1 );
97             right = new C( level - 1 );}
98         else {
99             left = right = 0;}}
100     ~C() {
101         this->A::Test( level );
102         nFreed++;
103         my_assert( level == 0 ?
104                    left == 0 && right == 0 :
105                    level == left->level + 1 && level == right->level + 1 );
106         left = right = 0;
107         level = -123456;}
108     static void Test() {
109         my_assert( nFreed <= nAllocated && nFreed >= .8 * nAllocated );}
110
111     static int nFreed;
112     static int nAllocated;
113     int level;
114     C* left;
115     C* right;};
116
117 int C::nFreed = 0;
118 int C::nAllocated = 0;
119
120
121 class D: public gc {public:
122     /* A collectable class with a static member function to be used as
123     an explicit clean-up function supplied to ::new. */
124
125     D( int iArg ): i( iArg ) {
126         nAllocated++;}
127     static void CleanUp( void* obj, void* data ) {
128         D* self = (D*) obj;
129         nFreed++;
130         my_assert( self->i == (int) (GC_word) data );}
131     static void Test() {
132         my_assert( nFreed >= .8 * nAllocated );}
133
134     int i;
135     static int nFreed;
136     static int nAllocated;};
137
138 int D::nFreed = 0;
139 int D::nAllocated = 0;
140
141
142 class E: public gc_cleanup {public:
143     /* A collectable class with clean-up for use by F. */
144
145     E() {
146         nAllocated++;}
147     ~E() {
148         nFreed++;}
149
150     static int nFreed;
151     static int nAllocated;};
152
153 int E::nFreed = 0;
154 int E::nAllocated = 0;
155
156
157 class F: public E {public:
158     /* A collectable class with clean-up, a base with clean-up, and a
159     member with clean-up. */
160
161     F() {
162         nAllocated++;}
163     ~F() {
164         nFreed++;}
165     static void Test() {
166         my_assert( nFreed >= .8 * nAllocated );
167         my_assert( 2 * nFreed == E::nFreed );}
168
169     E e;
170     static int nFreed;
171     static int nAllocated;};
172
173 int F::nFreed = 0;
174 int F::nAllocated = 0;
175
176
177 GC_word Disguise( void* p ) {
178     return ~ (GC_word) p;}
179
180 void* Undisguise( GC_word i ) {
181     return (void*) ~ i;}
182
183
184 #ifdef MSWIN32
185 int APIENTRY WinMain(
186     HINSTANCE instance, HINSTANCE prev, LPSTR cmd, int cmdShow )
187 {
188     int argc;
189     char* argv[ 3 ];
190
191     for (argc = 1; argc < sizeof( argv ) / sizeof( argv[ 0 ] ); argc++) {
192         argv[ argc ] = strtok( argc == 1 ? cmd : 0, " \t" );
193         if (0 == argv[ argc ]) break;}
194
195 #else
196 # ifdef MACOS
197     int main() {
198 # else
199     int main( int argc, char* argv[] ) {
200 # endif
201 #endif
202
203    GC_INIT();
204
205 #  if defined(MACOS)                        // MacOS
206     char* argv_[] = {"test_cpp", "10"};     //   doesn't
207     argv = argv_;                           //     have a
208     argc = sizeof(argv_)/sizeof(argv_[0]);  //       commandline
209 #  endif
210     int i, iters, n;
211 #   ifdef USE_STD_ALLOCATOR
212       int *x = gc_allocator<int>().allocate(1);
213       int *xio = gc_allocator_ignore_off_page<int>().allocate(1);
214       int **xptr = traceable_allocator<int *>().allocate(1);
215 #   else
216 #     ifdef __GNUC__
217           int *x = (int *)gc_alloc::allocate(sizeof(int));
218 #     else
219           int *x = (int *)alloc::allocate(sizeof(int));
220 #     endif
221 #   endif
222     *x = 29;
223 #   ifdef USE_STD_ALLOCATOR
224       *xptr = x;
225       x = 0;
226 #   endif
227     if (argc != 2 || (0 >= (n = atoi( argv[ 1 ] )))) {
228         GC_printf( "usage: test_cpp number-of-iterations\nAssuming 10 iters\n" );
229         n = 10;}
230
231     for (iters = 1; iters <= n; iters++) {
232         GC_printf( "Starting iteration %d\n", iters );
233
234             /* Allocate some uncollectable As and disguise their pointers.
235             Later we'll check to see if the objects are still there.  We're
236             checking to make sure these objects really are uncollectable. */
237         GC_word as[ 1000 ];
238         GC_word bs[ 1000 ];
239         for (i = 0; i < 1000; i++) {
240             as[ i ] = Disguise( new (NoGC) A( i ) );
241             bs[ i ] = Disguise( new (NoGC) B( i ) );}
242
243             /* Allocate a fair number of finalizable Cs, Ds, and Fs.
244             Later we'll check to make sure they've gone away. */
245         for (i = 0; i < 1000; i++) {
246             C* c = new C( 2 );
247             C c1( 2 );           /* stack allocation should work too */
248             D* d = ::new (USE_GC, D::CleanUp, (void*)(GC_word)i) D( i );
249             F* f = new F;
250             if (0 == i % 10) delete c;}
251
252             /* Allocate a very large number of collectable As and Bs and
253             drop the references to them immediately, forcing many
254             collections. */
255         for (i = 0; i < 1000000; i++) {
256             A* a = new (USE_GC) A( i );
257             B* b = new B( i );
258             b = new (USE_GC) B( i );
259             if (0 == i % 10) {
260                 B::Deleting( 1 );
261                 delete b;
262                 B::Deleting( 0 );}
263 #           ifdef FINALIZE_ON_DEMAND
264               GC_invoke_finalizers();
265 #           endif
266             }
267
268             /* Make sure the uncollectable As and Bs are still there. */
269         for (i = 0; i < 1000; i++) {
270             A* a = (A*) Undisguise( as[ i ] );
271             B* b = (B*) Undisguise( bs[ i ] );
272             a->Test( i );
273             delete a;
274             b->Test( i );
275             B::Deleting( 1 );
276             delete b;
277             B::Deleting( 0 );
278 #           ifdef FINALIZE_ON_DEMAND
279                  GC_invoke_finalizers();
280 #           endif
281
282             }
283
284             /* Make sure most of the finalizable Cs, Ds, and Fs have
285             gone away. */
286         C::Test();
287         D::Test();
288         F::Test();}
289
290 #   ifdef USE_STD_ALLOCATOR
291       x = *xptr;
292 #   endif
293     my_assert (29 == x[0]);
294     GC_printf( "The test appears to have succeeded.\n" );
295     return( 0 );}