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