9bf53de811ec88b9c7dd031178cad0d9705354fd
[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 **xptr = traceable_allocator<int *>().allocate(1);
210 #   else 
211 #     ifdef __GNUC__
212           int *x = (int *)gc_alloc::allocate(sizeof(int));
213 #     else
214           int *x = (int *)alloc::allocate(sizeof(int));
215 #     endif
216 #   endif
217     *x = 29;
218 #   ifdef USE_STD_ALLOCATOR
219       *xptr = x;
220       x = 0;
221 #   endif
222     if (argc != 2 || (0 >= (n = atoi( argv[ 1 ] )))) {
223         GC_printf( "usage: test_cpp number-of-iterations\nAssuming 10 iters\n" );
224         n = 10;}
225         
226     for (iters = 1; iters <= n; iters++) {
227         GC_printf( "Starting iteration %d\n", iters );
228
229             /* Allocate some uncollectable As and disguise their pointers.
230             Later we'll check to see if the objects are still there.  We're
231             checking to make sure these objects really are uncollectable. */
232         GC_word as[ 1000 ];
233         GC_word bs[ 1000 ];
234         for (i = 0; i < 1000; i++) {
235             as[ i ] = Disguise( new (NoGC) A( i ) );
236             bs[ i ] = Disguise( new (NoGC) B( i ) );}
237
238             /* Allocate a fair number of finalizable Cs, Ds, and Fs.
239             Later we'll check to make sure they've gone away. */
240         for (i = 0; i < 1000; i++) {
241             C* c = new C( 2 );
242             C c1( 2 );           /* stack allocation should work too */
243             D* d = ::new (USE_GC, D::CleanUp, (void*)(GC_word)i) D( i );
244             F* f = new F;
245             if (0 == i % 10) delete c;}
246
247             /* Allocate a very large number of collectable As and Bs and
248             drop the references to them immediately, forcing many
249             collections. */
250         for (i = 0; i < 1000000; i++) {
251             A* a = new (USE_GC) A( i );
252             B* b = new B( i );
253             b = new (USE_GC) B( i );
254             if (0 == i % 10) {
255                 B::Deleting( 1 );
256                 delete b;
257                 B::Deleting( 0 );}
258 #           ifdef FINALIZE_ON_DEMAND
259               GC_invoke_finalizers();
260 #           endif
261             }
262
263             /* Make sure the uncollectable As and Bs are still there. */
264         for (i = 0; i < 1000; i++) {
265             A* a = (A*) Undisguise( as[ i ] );
266             B* b = (B*) Undisguise( bs[ i ] );
267             a->Test( i );
268             delete a;
269             b->Test( i );
270             B::Deleting( 1 );
271             delete b;
272             B::Deleting( 0 );
273 #           ifdef FINALIZE_ON_DEMAND
274                  GC_invoke_finalizers();
275 #           endif
276
277             }
278
279             /* Make sure most of the finalizable Cs, Ds, and Fs have
280             gone away. */
281         C::Test();
282         D::Test();
283         F::Test();}
284
285 #   ifdef USE_STD_ALLOCATOR
286       x = *xptr;
287 #   endif
288     my_assert (29 == x[0]);
289     GC_printf( "The test appears to have succeeded.\n" );
290     return( 0 );}
291     
292