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