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