287 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			287 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/****************************************************************************
 | 
						|
Copyright (c) 1994 by Xerox Corporation.  All rights reserved.
 | 
						|
 
 | 
						|
THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
 | 
						|
OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
 | 
						|
 
 | 
						|
Permission is hereby granted to use or copy this program for any
 | 
						|
purpose, provided the above notices are retained on all copies.
 | 
						|
Permission to modify the code and to distribute modified code is
 | 
						|
granted, provided the above notices are retained, and a notice that
 | 
						|
the code was modified is included with the above copyright notice.
 | 
						|
****************************************************************************
 | 
						|
Last modified on Mon Jul 10 21:06:03 PDT 1995 by ellis
 | 
						|
     modified on December 20, 1994 7:27 pm PST by boehm
 | 
						|
 | 
						|
usage: test_cpp number-of-iterations
 | 
						|
 | 
						|
This program tries to test the specific C++ functionality provided by
 | 
						|
gc_c++.h that isn't tested by the more general test routines of the
 | 
						|
collector.
 | 
						|
 | 
						|
A recommended value for number-of-iterations is 10, which will take a
 | 
						|
few minutes to complete.
 | 
						|
 | 
						|
***************************************************************************/
 | 
						|
 | 
						|
#include "gc_cpp.h"
 | 
						|
#include <stdio.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <string.h>
 | 
						|
#define USE_STD_ALLOCATOR
 | 
						|
#ifdef USE_STD_ALLOCATOR
 | 
						|
#   include "gc_allocator.h"
 | 
						|
#elif __GNUC__
 | 
						|
#   include "new_gc_alloc.h"
 | 
						|
#else
 | 
						|
#   include "gc_alloc.h"
 | 
						|
#endif
 | 
						|
extern "C" {
 | 
						|
#include "private/gc_priv.h"
 | 
						|
}
 | 
						|
#ifdef MSWIN32
 | 
						|
#   include <windows.h>
 | 
						|
#endif
 | 
						|
#ifdef GC_NAME_CONFLICT
 | 
						|
#   define USE_GC UseGC
 | 
						|
    struct foo * GC;
 | 
						|
#else
 | 
						|
#   define USE_GC GC
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
#define my_assert( e ) \
 | 
						|
    if (! (e)) { \
 | 
						|
        GC_printf1( "Assertion failure in " __FILE__ ", line %d: " #e "\n", \
 | 
						|
                    __LINE__ ); \
 | 
						|
        exit( 1 ); }
 | 
						|
 | 
						|
 | 
						|
class A {public:
 | 
						|
    /* An uncollectable class. */
 | 
						|
 | 
						|
    A( int iArg ): i( iArg ) {}
 | 
						|
    void Test( int iArg ) {
 | 
						|
        my_assert( i == iArg );} 
 | 
						|
    int i;};
 | 
						|
 | 
						|
 | 
						|
class B: public gc, public A {public:
 | 
						|
    /* A collectable class. */
 | 
						|
 | 
						|
    B( int j ): A( j ) {}
 | 
						|
    ~B() {
 | 
						|
        my_assert( deleting );}
 | 
						|
    static void Deleting( int on ) {
 | 
						|
        deleting = on;}
 | 
						|
    static int deleting;};
 | 
						|
 | 
						|
int B::deleting = 0;
 | 
						|
 | 
						|
 | 
						|
class C: public gc_cleanup, public A {public:
 | 
						|
    /* A collectable class with cleanup and virtual multiple inheritance. */
 | 
						|
 | 
						|
    C( int levelArg ): A( levelArg ), level( levelArg ) {
 | 
						|
        nAllocated++;
 | 
						|
        if (level > 0) {
 | 
						|
            left = new C( level - 1 );
 | 
						|
            right = new C( level - 1 );}
 | 
						|
        else {
 | 
						|
            left = right = 0;}}
 | 
						|
    ~C() {
 | 
						|
        this->A::Test( level );
 | 
						|
        nFreed++;
 | 
						|
        my_assert( level == 0 ? 
 | 
						|
                   left == 0 && right == 0 :
 | 
						|
                   level == left->level + 1 && level == right->level + 1 );
 | 
						|
        left = right = 0;
 | 
						|
        level = -123456;}
 | 
						|
    static void Test() {
 | 
						|
        my_assert( nFreed <= nAllocated && nFreed >= .8 * nAllocated );}
 | 
						|
 | 
						|
    static int nFreed;
 | 
						|
    static int nAllocated;
 | 
						|
    int level;
 | 
						|
    C* left;
 | 
						|
    C* right;};
 | 
						|
 | 
						|
int C::nFreed = 0;
 | 
						|
int C::nAllocated = 0;
 | 
						|
 | 
						|
 | 
						|
class D: public gc {public:
 | 
						|
    /* A collectable class with a static member function to be used as
 | 
						|
    an explicit clean-up function supplied to ::new. */
 | 
						|
 | 
						|
    D( int iArg ): i( iArg ) {
 | 
						|
        nAllocated++;}
 | 
						|
    static void CleanUp( void* obj, void* data ) {
 | 
						|
        D* self = (D*) obj;
 | 
						|
        nFreed++;
 | 
						|
        my_assert( self->i == (int) (long) data );}
 | 
						|
    static void Test() {
 | 
						|
        my_assert( nFreed >= .8 * nAllocated );}
 | 
						|
       
 | 
						|
    int i;
 | 
						|
    static int nFreed;
 | 
						|
    static int nAllocated;};
 | 
						|
 | 
						|
int D::nFreed = 0;
 | 
						|
int D::nAllocated = 0;
 | 
						|
 | 
						|
 | 
						|
class E: public gc_cleanup {public:
 | 
						|
    /* A collectable class with clean-up for use by F. */
 | 
						|
 | 
						|
    E() {
 | 
						|
        nAllocated++;}
 | 
						|
    ~E() {
 | 
						|
        nFreed++;}
 | 
						|
 | 
						|
    static int nFreed;
 | 
						|
    static int nAllocated;};
 | 
						|
    
 | 
						|
int E::nFreed = 0;
 | 
						|
int E::nAllocated = 0;
 | 
						|
   
 | 
						|
 | 
						|
class F: public E {public:
 | 
						|
    /* A collectable class with clean-up, a base with clean-up, and a
 | 
						|
    member with clean-up. */
 | 
						|
 | 
						|
    F() {
 | 
						|
        nAllocated++;}
 | 
						|
    ~F() {
 | 
						|
        nFreed++;}
 | 
						|
    static void Test() {
 | 
						|
        my_assert( nFreed >= .8 * nAllocated );
 | 
						|
        my_assert( 2 * nFreed == E::nFreed );}
 | 
						|
       
 | 
						|
    E e;
 | 
						|
    static int nFreed;
 | 
						|
    static int nAllocated;};
 | 
						|
    
 | 
						|
int F::nFreed = 0;
 | 
						|
int F::nAllocated = 0;
 | 
						|
   
 | 
						|
 | 
						|
long Disguise( void* p ) {
 | 
						|
    return ~ (long) p;}
 | 
						|
 | 
						|
void* Undisguise( long i ) {
 | 
						|
    return (void*) ~ i;}
 | 
						|
 | 
						|
 | 
						|
#ifdef MSWIN32
 | 
						|
int APIENTRY WinMain(
 | 
						|
    HINSTANCE instance, HINSTANCE prev, LPSTR cmd, int cmdShow ) 
 | 
						|
{
 | 
						|
    int argc;
 | 
						|
    char* argv[ 3 ];
 | 
						|
 | 
						|
    for (argc = 1; argc < sizeof( argv ) / sizeof( argv[ 0 ] ); argc++) {
 | 
						|
        argv[ argc ] = strtok( argc == 1 ? cmd : 0, " \t" );
 | 
						|
        if (0 == argv[ argc ]) break;}
 | 
						|
 | 
						|
#else
 | 
						|
# ifdef MACOS
 | 
						|
    int main() {
 | 
						|
# else
 | 
						|
    int main( int argc, char* argv[] ) {
 | 
						|
# endif
 | 
						|
#endif
 | 
						|
 | 
						|
#  if defined(MACOS)                        // MacOS
 | 
						|
    char* argv_[] = {"test_cpp", "10"};     //   doesn't
 | 
						|
    argv = argv_;                           //     have a
 | 
						|
    argc = sizeof(argv_)/sizeof(argv_[0]);  //       commandline
 | 
						|
#  endif 
 | 
						|
    int i, iters, n;
 | 
						|
#   ifdef USE_STD_ALLOCATOR
 | 
						|
      int *x = gc_allocator<int>().allocate(1);
 | 
						|
      int **xptr = traceable_allocator<int *>().allocate(1);
 | 
						|
#   else 
 | 
						|
#     ifdef __GNUC__
 | 
						|
          int *x = (int *)gc_alloc::allocate(sizeof(int));
 | 
						|
#     else
 | 
						|
          int *x = (int *)alloc::allocate(sizeof(int));
 | 
						|
#     endif
 | 
						|
#   endif
 | 
						|
    *x = 29;
 | 
						|
#   ifdef USE_STD_ALLOCATOR
 | 
						|
      *xptr = x;
 | 
						|
      x = 0;
 | 
						|
#   endif
 | 
						|
    if (argc != 2 || (0 >= (n = atoi( argv[ 1 ] )))) {
 | 
						|
        GC_printf0( "usage: test_cpp number-of-iterations\n" );
 | 
						|
        exit( 1 );}
 | 
						|
        
 | 
						|
    for (iters = 1; iters <= n; iters++) {
 | 
						|
        GC_printf1( "Starting iteration %d\n", iters );
 | 
						|
 | 
						|
            /* Allocate some uncollectable As and disguise their pointers.
 | 
						|
            Later we'll check to see if the objects are still there.  We're
 | 
						|
            checking to make sure these objects really are uncollectable. */
 | 
						|
        long as[ 1000 ];
 | 
						|
        long bs[ 1000 ];
 | 
						|
        for (i = 0; i < 1000; i++) {
 | 
						|
            as[ i ] = Disguise( new (NoGC) A( i ) );
 | 
						|
            bs[ i ] = Disguise( new (NoGC) B( i ) );}
 | 
						|
 | 
						|
            /* Allocate a fair number of finalizable Cs, Ds, and Fs.
 | 
						|
            Later we'll check to make sure they've gone away. */
 | 
						|
        for (i = 0; i < 1000; i++) {
 | 
						|
            C* c = new C( 2 );
 | 
						|
            C c1( 2 );           /* stack allocation should work too */
 | 
						|
            D* d = ::new (USE_GC, D::CleanUp, (void*)(long)i) D( i );
 | 
						|
            F* f = new F;
 | 
						|
            if (0 == i % 10) delete c;}
 | 
						|
 | 
						|
            /* Allocate a very large number of collectable As and Bs and
 | 
						|
            drop the references to them immediately, forcing many
 | 
						|
            collections. */
 | 
						|
        for (i = 0; i < 1000000; i++) {
 | 
						|
            A* a = new (USE_GC) A( i );
 | 
						|
            B* b = new B( i );
 | 
						|
            b = new (USE_GC) B( i );
 | 
						|
            if (0 == i % 10) {
 | 
						|
                B::Deleting( 1 );
 | 
						|
                delete b;
 | 
						|
                B::Deleting( 0 );}
 | 
						|
#	    ifdef FINALIZE_ON_DEMAND
 | 
						|
	      GC_invoke_finalizers();
 | 
						|
#	    endif
 | 
						|
	    }
 | 
						|
 | 
						|
            /* Make sure the uncollectable As and Bs are still there. */
 | 
						|
        for (i = 0; i < 1000; i++) {
 | 
						|
            A* a = (A*) Undisguise( as[ i ] );
 | 
						|
            B* b = (B*) Undisguise( bs[ i ] );
 | 
						|
            a->Test( i );
 | 
						|
            delete a;
 | 
						|
            b->Test( i );
 | 
						|
            B::Deleting( 1 );
 | 
						|
            delete b;
 | 
						|
            B::Deleting( 0 );
 | 
						|
#	    ifdef FINALIZE_ON_DEMAND
 | 
						|
	   	 GC_invoke_finalizers();
 | 
						|
#	    endif
 | 
						|
 | 
						|
	    }
 | 
						|
 | 
						|
            /* Make sure most of the finalizable Cs, Ds, and Fs have
 | 
						|
            gone away. */
 | 
						|
        C::Test();
 | 
						|
        D::Test();
 | 
						|
        F::Test();}
 | 
						|
 | 
						|
#   ifdef USE_STD_ALLOCATOR
 | 
						|
      x = *xptr;
 | 
						|
#   endif
 | 
						|
    my_assert (29 == x[0]);
 | 
						|
    GC_printf0( "The test appears to have succeeded.\n" );
 | 
						|
    return( 0 );}
 | 
						|
    
 | 
						|
 |