/**********************************************************************
 * Copyright (c) 2005, 2009 IBM Corporation and others.
 * All rights reserved.   This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * $Id: StatelessHeapSnapshotManager_C.cpp,v 1.5 2009/08/07 03:27:54 jwest Exp $
 *
 * Contributors:
 * IBM - Initial API and implementation
 * Spundun Bhatt (spundun@gmail.com), with the support and encouragement of the University of Southern California Information Sciences Institute Distributed Scalable Systems Division.
 **********************************************************************/

#include <string.h>
#include <time.h>
#include <stdlib.h>
#include "options.h"
#include "JvmpiWriter.h"
#include "StatelessHeapSnapshotManager_C.h"
#include "performance.h" // Uint64, _ticksPerMicrosecond

#include "../heapsnapshots/HeapSnapshotManager.h"
#include "../heapsnapshots/StatelessHeapSnapshotManager.h"
#include "../heapsnapshots/SnapshotFiller.h"
#include "../heapsnapshots/SnapshotAgentInterface.h"


#ifdef _WIN32
#include <winsock2.h> /* Bug 134924 */
#include <windows.h>
#include <process.h>
 /* typedef int PID; */
#else
#include <unistd.h>
 /* typedef pid_t PID; */
#endif

static bool optHeapDebug = false;
static FILE *debugOut = stderr;

/* Modification History */
/*Bugzilla 82214 - The code has been cleaned to remove the moves and free handling 
*/ 

/* Bug Number 73480 */
#ifdef __OS400__
/** CALLOC  *************************************************************
  * Allocate some memory from the heap.  If there is no more memory left
  * the VM will exit gracefully.
  */
static void* jvmpiAgent_Calloc(unsigned int size) {
	void *p=malloc(size);
	if(p==NULL) {
		fprintf(stderr, "FATAL ERROR:  Out of memory...JVM Exiting\n");
		fflush(stderr); 
		_jvmpiAgent_jvmpiInterface->ProfilerExit((jint)-1);
	}
	memset(p, 0, size);
	return p;
}


/** CREATE_SYMBOL  *************************************************************
  *
  */
static HashEntry * jvmpiAgent_CreateSymbol(void *id)
{
 /* Create a new hash entry and then insert it into the hash table */
 HashEntry * hashEntry = (HashEntry *)jvmpiAgent_Calloc(sizeof(HashEntry));
 hashEntry->id=id;
 hashEntry->printed=0;
 hashEntry->deleted= 0;
 hashEntry->toBeFreed=0;
 hashEntry->next=NULL;
 return hashEntry;
}


void StatelessHeapSnapshotManager_createClassSymbol(jobjectID classId,
						const char*  className,
						int          numInterfaces,
						int          numStaticFields
						) {
	//HashEntry *classObjectEntry;
	//classObjectEntry=jvmpiAgent_FindObjectSymbol(classId);
	ClassEntry *classEntry;
	HashEntry *hashEntry;
	ClassHashKey *k; 
	/* AM: This block of code will ensure that a class symbol is not created more than once for the same class */
	hashEntry = jvmpiAgent_FindClassSymbol (classId) ;
	if (!hashEntry) {
		k = (ClassHashKey *)jvmpiAgent_Calloc(sizeof(ClassHashKey)); 
		k->id=classId; 
		hashEntry = jvmpiAgent_CreateSymbol((void *)k);
		/* Allocate and copy the event data into the symbol table structure */
		hashEntry->entry  = (ClassEntry*)jvmpiAgent_Calloc(sizeof(ClassEntry));
		classEntry = CLASS_ENTRY(hashEntry);
		if(className) {
			STRDUP(classEntry->className, className);
		}
		classEntry->numInterfaces = numInterfaces;
		classEntry->numStaticFields   = numStaticFields;
		insertClassOptSymbol(hashEntry);
	}
}
#endif


/* Piyush Bug 58049 */
class FillerException {
  private :
	int e ;
  public :
	FillerException ( int error ) :e(error) {} 
	int getErrorCode () { return e ; }
 
} ;


class HyadesSnapshotFiller : public SnapshotFiller {
 public:
  HyadesSnapshotFiller(unsigned int objectMoveBatchSize, unsigned int objectFreeBatchSize)
  {
  }
  ~HyadesSnapshotFiller() {
  }

  void makeFileName(char *buf) {
	PID pid;
	time_t currentTime;
	struct tm ltime, *pMemoryLeak=NULL;
	char* hdfilename = '\0' ;
	char pidString[10] ;
	int lenPidString ;

#ifdef MVS
#pragma convlit(suspend)
#endif
	/* start from dir name */
	*buf = '\0';
#ifdef MVS
__atoe(_jvmpiAgent_Options.workDir) ;
#endif
	strcpy(buf, _jvmpiAgent_Options.workDir);
#ifdef MVS
__etoa(_jvmpiAgent_Options.workDir) ;
#endif
	buf += strlen(_jvmpiAgent_Options.workDir);
#ifdef _WIN32
	*buf = '\\'; /* file delim in Windows */
#else
	*buf = '/'; /* file delim in Unix */
#endif
	buf += 1; *buf = '\0';
	hdfilename = buf ;
	/* Applend the file prefix */
#ifdef MVS
__atoe(_jvmpiAgent_Options.heapInfoFilePrefix) ;
#endif
	strcat(buf, _jvmpiAgent_Options.heapInfoFilePrefix);
#ifdef MVS
__etoa(_jvmpiAgent_Options.heapInfoFilePrefix) ;
#endif
	/* buf always points to the end, where things can be appended */
	buf += strlen(_jvmpiAgent_Options.heapInfoFilePrefix);

	/* Get the time and date */
	time(&currentTime);
	/* ToDo: localtime_r() is not in Windows, otherwise that is better suited.
	 * Not deleting pLocalTimeBreakup, because not sure who owns it, so it is
	 * very small one time leak, but we should fix it.
	 */

	/*Piyush Bug 82214 */
	/* We have changed the naming of files so that every name will have new time. */
		pMemoryLeak = localtime(&currentTime);
		ltime = *pMemoryLeak;
		/* free (pMemLeak); can I free it here?  */
		sprintf(_headerTimeStamp, ".%.4d%.2d%.2d.%.2d%.2d%.2d \n",
			1900+ltime.tm_year, 1+ltime.tm_mon, ltime.tm_mday,
			ltime.tm_hour, ltime.tm_min, ltime.tm_sec);
		_headerTimeStamp[17] = '\0' ;

	/* Use the stored timestamp */
	strcpy(buf,_headerTimeStamp) ;
	buf += 16; /* .YYYYMMDD.HHMMSS = 12 bytes */

	/* get process id */
	pid = getpid();

#ifdef _WIN32
    itoa((int)pid,pidString,10) ;
	sprintf(buf, ".%d", (int) pid);
	lenPidString = strlen(pidString) + 1 ;
#else
	/* Here the "." is included in sprintf so the lenPidString = strlen(pidString) +1 
	   which is similar to the one above */
	lenPidString = sprintf(buf, ".%d", (int) pid);
#endif
	buf += lenPidString ;

	/* append cycle etc */
	sprintf(buf, ".trcopt");
	strcpy(_hdFileName,hdfilename) ;
	hdfilename = NULL ;

#ifdef MVS
#pragma convlit(resume)
#endif
  }
  void FillJinsightHeader() {
#if 0
    struct event {
      char traceFormatTag;   /* 'o' */
      int traceVersion;      /* 10 */
      int platformTag;
      int numberOfEvents;
      int maxThread;
      int maxClass;
      int ticksPerMicrosecond;
      Uint64 connectionTime_in_ticks;
      int processStartTime_in_ms;
      int connectionTime_in_ms;
      int parentJVMOverhead;
    };
    struct event e = {'o', 10, 44, 0, 0x100, 0x4000, 0, 0, 0, 0, 0};
    fillerfwrite(&e, sizeof(event), 1, _snappieFile);
#endif

	const int BINARY_HEAP_DUMP_VERSION = 12;

    time_t connectionStartTime;
    time(&connectionStartTime);

#if defined(__OS400__)
#pragma convert(819)
#endif
    traceWriteByte('o');
#if defined(__OS400__)
#pragma convert(0)
#endif
    traceWriteInt32LittleEndian(BINARY_HEAP_DUMP_VERSION);
    traceWritePlatformLittleEndian();
    traceWriteInt32LittleEndian(0); // UNUSED: number of events
    traceWriteInt32LittleEndian(0); // UNUSED: max thread id
    traceWriteInt32LittleEndian(0); // UNUSED: max class id
    traceWriteInt32LittleEndian(_ticksPerMicrosecond);
    traceWriteTimestampLittleEndian(0);
    traceWriteInt32LittleEndian(0);
    traceWriteInt32LittleEndian(connectionStartTime);
    traceWriteInt32LittleEndian(0);

    fflush(_snappieFile);
  }
  void traceWriteByte(char b){
	fillerfwrite(&b, sizeof(char), 1, _snappieFile);
  }
  void traceWriteOID(jobjectID oid) {
    fillerfwrite(&oid, sizeof(jobjectID), 1, _snappieFile);
  }
  void traceWriteOIDArray(jobjectID* oids, unsigned int num) {
    fillerfwrite(oids, sizeof(jobjectID), num, _snappieFile);
  }
  void traceWritePlatformLittleEndian() {

#if defined(_WIN32)
    traceWriteInt32LittleEndian(11);
#elif defined(_AIX)
    traceWriteInt32LittleEndian(22);
#elif defined(MVS)
    traceWriteInt32LittleEndian(33);
#elif defined(__linux__) && defined(__i386__)
    traceWriteInt32LittleEndian(44);
#elif defined(__linux__) && defined(__s390__)
    traceWriteInt32LittleEndian(55);
#elif defined(_SOLARIS)
    traceWriteInt32LittleEndian(66);
#elif defined(_HPUX)
    traceWriteInt32LittleEndian(77);
#elif defined(__OS400__)
    traceWriteInt32LittleEndian(88);
#elif defined(__linux__) && defined(__powerpc64__) || defined(_WIN64) || defined (__APPLE__) /*ts. bug 120479*/
    /* traceWriteInt32LittleEndian(99); */
#else
#error "unknown platform"
#endif
  }
  void traceWriteInt16LittleEndian(unsigned short id) {
    traceWriteByte(id&0xff);
    traceWriteByte((id&0xff00)>>8);
  }
  void traceWriteInt16(unsigned short id) {
	  fillerfwrite(&id, sizeof(unsigned short), 1, _snappieFile);
  }
  void traceWriteInt32LittleEndian(unsigned int id) {
    traceWriteByte(id&0xff);
    traceWriteByte((id&0xff00)>>8);
    traceWriteByte((id&0xff0000)>>16);
    traceWriteByte((id&0xff000000)>>24);
  }
  void traceWriteInt32(unsigned int id) {
	  fillerfwrite(&id, sizeof(unsigned int), 1, _snappieFile);
  }
  void traceWriteString(const char* bytes, unsigned int numBytes) {
    traceWriteInt16(numBytes);
    fillerfwrite(bytes, sizeof(char), numBytes, _snappieFile);
  }
  void traceWriteTimestampLittleEndian(Uint64 id) {
#ifdef IBM_OE
    unsigned long long mask;
#else
    Uint64 mask;
#endif // IBM_OE

    mask = 0xff;
    char byte1    = (char)(id&mask);
    traceWriteByte(byte1);

    mask = mask << 8;
    char byte2 = (char)((id&mask)>>8);
    traceWriteByte(byte2);

    mask = mask << 8;
    char byte3 = (char)((id&mask)>>16);
    traceWriteByte(byte3);

    mask = mask << 8;
    char byte4 = (char)((id&mask)>>24);
    traceWriteByte(byte4);

    mask = mask << 8;
    char byte5 = (char)((id&mask)>>32);
    traceWriteByte(byte5);

    mask = mask << 8;
    char byte6 = (char)((id&mask)>>40);
    traceWriteByte(byte6);

    mask = mask << 8;
    char byte7 = (char)((id&mask)>>48);
    traceWriteByte(byte7);

    mask = mask << 8;
    char byte8 = (char)((id&mask)>>56);
    traceWriteByte(byte8);
  }
  void traceWriteTimestamp(Uint64 id) {
	  fillerfwrite(&id, sizeof(Uint64), 1, _snappieFile);
  }
  void FillClassInfo(jobjectID   classID,
		     const char* className,
		     int         numStaticReferenceFields,
		     int         numInterfaces,
#if defined(__OS400__)
			 int         instanceSize,
			 jobjectID*  classRefs) {
#else
			 int         instanceSize) {
#endif
#if 0
    struct event1 {
      char eventTag;
      jobjectID classID;
      short classNameNumBytes;
    };
    struct event2 {
      int numStaticReferenceFields;
      int numInterfaces;
    };
    int classNameNumBytes = strlen(className);
    struct event1 e1 = {81, classID, classNameNumBytes};
    struct event2 e2 = {numStaticReferenceFields, numInterfaces};
    fillerfwrite(&e1, sizeof(event1), 1, _snappieFile);
    fillerfwrite(className, sizeof(char), classNameNumBytes, _snappieFile);
    fillerfwrite(&e2, sizeof(event2), 1, _snappieFile);
#endif

    traceWriteByte(81);
#if defined(__OS400__) || defined(_SOLARIS) || defined(_AIX)
	traceWriteOID(classID);
#else
    traceWriteInt32((int)classID);
#endif
    traceWriteString(className, strlen(className));
    traceWriteInt32(numStaticReferenceFields);
    traceWriteInt32(numInterfaces);
	traceWriteInt32(instanceSize);
#if defined(__OS400__)
	if (classRefs) {
		traceWriteInt32(numStaticReferenceFields);
		traceWriteOIDArray(classRefs, numStaticReferenceFields);
	} else {
		traceWriteInt32(0);
	}
#endif
  }
  void FillJvmpiSnapshot(char* begin, char* end) {
#if 0
    struct event {
      char eventTag;
      Uint64 timestamp;
      int sizeofVoidStar;
      int numBytesInSnapshot;
    };
    struct event e = {80, 0, sizeof(void*), end-begin};
    fillerfwrite(&e, sizeof(event), 1, _snappieFile);
#endif

    traceWriteByte(80);
    traceWriteTimestamp(0);
    traceWriteInt32(sizeof(void*));
    traceWriteInt32(end-begin);
    fillerfwrite(begin, sizeof(char), end-begin,  _snappieFile);
    fflush(_snappieFile);
  }



  void writeHeader()	
  {
    FillJinsightHeader();
  }
 
  void closeHeapDumpFile()
  {
    fclose(_snappieFile) ;
	/* Moved the callback method here so that it is called only after the heap dump is created */
	StatelessHeapSnapshotManager_optHeapCallBack(_hdFileName) ;
	
  }


#ifdef MVS
#pragma convlit(suspend)
#endif
  void createHeapDumpFile()
  {
    char filename[511];
	makeFileName(filename);

	_snappieFile = fopen(filename, "wb");
	
	/* check if fopen() failed */
	if(_snappieFile == NULL) {
		if (_jvmpiAgent_Options.standalone) {
		  fprintf(stderr, "*** Could not open output file \"%s\".  Exiting JVM. ***\n", filename);
		  fflush(stderr);  
		  _jvmpiAgent_jvmpiInterface->ProfilerExit((jint)-1);
		}
		throw FillerException(RA_OPT_HEAP_COULD_NOT_CREATE_FILE) ;/* Piyush 58049 */
	}
  }
#ifdef MVS
#pragma convlit(resume)
#endif
  
  /* Piyush Bug 58049 */
  void fillerfwrite(const void* buffer, size_t size, size_t count, FILE* stream)  {
	size_t result = 0 ;
	int error = 0 ;
	result = fwrite(buffer, size, count, stream);
	error = ferror(stream) ;
	if ( error || result != count )
	{
		throw FillerException(RA_OPT_HEAP_DISK_FULL) ;	
	}
  }	

// Multiple File Support
 private:
  FILE* _snappieFile;
  char _hdFileName[511];
  char _headerTimeStamp[17] ;
};

class HyadesSnapshotAgentInterface : public SnapshotAgentInterface {
 public:
  HyadesSnapshotAgentInterface(JVMPI_Interface* jvmpi, BOOL classInfoCallback)
	  : _jvmpi(jvmpi), _classInfoCallback(classInfoCallback)
  {
  }
  void classInfoCallback(const char*  className,
			 int          numInterfaces,
			 int          numStaticFields,
			 JVMPI_Field* statics) {
    int i;
    int numStaticReferenceFields = 0;
    for (i=0; i<numStaticFields; i++) {
      char prim = statics[i].field_signature[0];
#ifdef __OS400__
#pragma convert(819)
#endif
      if (prim == '[' || prim == 'L') {
#ifdef __OS400__
#pragma convert(0)
#endif
	numStaticReferenceFields++;
      }
    }

    _stashedClassName = strdup(className);
    _stashedNumInterfaces = numInterfaces;
    _stashedNumStaticReferenceFields = numStaticReferenceFields;
  }
  
#ifdef __OS400__
  void objectDumpCallbackMethod(JVMPI_Event *event) {
    _stashedObjectDumpLen = event->u.object_dump.data_len;
    _stashedObjectDumpData = (char *)jvmpiAgent_Calloc(_stashedObjectDumpLen);
  	memcpy(_stashedObjectDumpData,event->u.object_dump.data,_stashedObjectDumpLen);
  }
#endif
  
  char getClassInfo(jobjectID classID,
		    char**    className_outvar,
		    char*     className_freeMe,
		    int*      numInterfaces_outvar,
		    int*      numStaticReferenceFields_outvar) {

#ifdef __OS400__
/* Bug Number 73480 */
    int status = 0;
    /* 96198 Return all the values, even if the class is already
	   in the table 
     */
	if (jvmpiAgent_FindClassSymbol(classID)) status = 1;
#endif

    BOOL tmp = _classInfoCallback; /* backup the original value */
	_classInfoCallback = (BOOL) TRUE; /* change it for requesting next event */
	REQUEST_EVENT2(JVMPI_EVENT_CLASS_LOAD, classID);
    _classInfoCallback = tmp; /* restore */

    /* _stashedClassName is already a copy - caller to free*/
	*className_outvar = _stashedClassName;
    *className_freeMe = 1;
    *numInterfaces_outvar = _stashedNumInterfaces;
    *numStaticReferenceFields_outvar = _stashedNumStaticReferenceFields;
    if (optHeapDebug) {
	    fprintf(debugOut, 
		"Return from JVMPI_EVENT_CLASS_LOAD for cls_id=0x%x, cls_name=%s, numInterfaces=%d, numStatics=%d.\n",
		classID, (_stashedClassName ? _stashedClassName : "NULL"),
		_stashedNumInterfaces, _stashedNumStaticReferenceFields);
		fflush(debugOut);
    }

/* Bug Number 73480 */
#ifdef __OS400__
    if (status == 0) {
	StatelessHeapSnapshotManager_createClassSymbol(classID,_stashedClassName,
										_stashedNumInterfaces,_stashedNumStaticReferenceFields) ;
	}
	return status;
#else

    return 0;
#endif
  }
  
#ifdef __OS400__
  char getOS400ClassInfo(jobjectID classID,
		    char**    className_outvar,
		    char*     className_freeMe,
		    int*      numInterfaces_outvar,
		    int*      numStaticReferenceFields_outvar,
		    unsigned int*	  object_dump_len,
		    char**	  object_dump_data) {

	if (jvmpiAgent_FindClassSymbol(classID)) return 1;

    BOOL tmp = _classInfoCallback; /* backup the original value */
	_classInfoCallback = (BOOL) TRUE; /* change it for requesting next event */
	REQUEST_EVENT2(JVMPI_EVENT_CLASS_LOAD, classID);
	REQUEST_EVENT2(JVMPI_EVENT_OBJECT_DUMP, classID);
    _classInfoCallback = tmp; /* restore */

    /* _stashedClassName is already a copy  - caller to free*/
	*className_outvar = _stashedClassName;
    *className_freeMe = 1;
    *numInterfaces_outvar = _stashedNumInterfaces;
    *numStaticReferenceFields_outvar = _stashedNumStaticReferenceFields;
    *object_dump_len = _stashedObjectDumpLen;
    /* _stashedObjectDumpData is already a copy  - caller to free*/
	*object_dump_data = _stashedObjectDumpData;

	StatelessHeapSnapshotManager_createClassSymbol(classID,_stashedClassName,
										_stashedNumInterfaces,_stashedNumStaticReferenceFields) ;

    return 0;
  }
#endif
  
  char stillAlive() {
    return 1;
  }
  char stillTracing() {
    return stillAlive(); /*&&  file/socket not closed? */
  }
  char shouldIReportHeapSnapshotDuration() {
    return 1;
  }
  short swap16(short n) {
    return ntohs(n);
  }
  int swap32(int n) {
    return ntohl(n);
  }
  char dump_read_u1(char* cursor) {
    unsigned char u1;
    memcpy(&u1, cursor, sizeof(char));
    return u1;
  }
  short dump_read_u2(char* cursor) {
    unsigned short u2;
    memcpy(&u2, cursor, sizeof(short));
    return u2;
  }
  int dump_read_u4(char* cursor) {
    unsigned int u4;
    memcpy(&u4, cursor, sizeof(int));
    return u4;
  }
  jobjectID dump_read_jobjectID(char* cursor) {
    // Anandi 25 May 2004 - Change this so it works for 64-bit jobjectIDs
    jobjectID ptr;
    memcpy(&ptr, cursor, sizeof(jobjectID));
    return ptr;
  }
#ifdef MVS
#pragma convlit(suspend)
#endif
  void status(const char* message) {
  if (optHeapDebug) {
    fprintf(debugOut, "snapshot status: %s\n", message);
    fflush(debugOut);
  }
  }
  void status(const char* message, int message2) {
  if (optHeapDebug) {
    fprintf(debugOut, "snapshot status: %s %d\n", message, message2);
    fflush(debugOut);
  }
  }
  void error(const char* message) {
  if (optHeapDebug) {
    fprintf(debugOut, "snapshot error: %s\n", message);
    fflush(debugOut);
  }
  }
#ifdef MVS
#pragma convlit(resume)
#endif

 private:
  JVMPI_Interface* _jvmpi;
  BOOL _classInfoCallback;
  char* _stashedClassName;
  int _stashedNumInterfaces;
  int _stashedNumStaticReferenceFields;
#ifdef __OS400__
  unsigned int _stashedObjectDumpLen;
  char *_stashedObjectDumpData;
#endif
};

HeapSnapshotManager*          _manager;
HyadesSnapshotAgentInterface* _agent;
HyadesSnapshotFiller*         _filler;

extern "C"
void StatelessHeapSnapshotManager_classInfoCallback(const char*  className,
						    int          numInterfaces,
						    int          numStaticFields,
						    JVMPI_Field* statics)
{
  _agent->classInfoCallback(className,
			    numInterfaces,
			    numStaticFields,
			    statics);
}

#ifdef __OS400__
void StatelessHeapSnapshotManager_objectDumpCallbackMethod(JVMPI_Event *event)
{
  _agent->objectDumpCallbackMethod(event);
}

/* Bug Number 73480 */
/** DELETE_HASH_ENTRY  *********************************************************
  *
  */
int deleteHashEntry(HashEntry *entry,
                    void *param) {
	jvmpiAgent_DeleteSymbol(entry, (*(enum EntryType*)param));
	return 0;
}
#endif


extern "C"
void StatelessHeapSnapshotManager_setup_FromC(JVMPI_Interface *jvmpi,
											  BOOL classInfoCallback)
{
  char *debugOptHeap = getenv("DEBUGOPTHEAP");
  if (debugOptHeap && strcmp(debugOptHeap, "TRUE")) optHeapDebug = true;
  _filler  = new HyadesSnapshotFiller(1000, 1000);
  _agent   = new HyadesSnapshotAgentInterface(jvmpi, classInfoCallback);
  _manager = new StatelessHeapSnapshotManager(_filler, _agent, jvmpi, optHeapDebug, debugOut);
}

extern "C"
int StatelessHeapSnapshotManager_handleHeapSnapshot_FromC(JNIEnv*      env,
							   int          dump_level,
							   char*        begin,
							   char*        end)
{
  int errorCode = 0 ;
  try {

	  /*Piyush Bug 82214*/
	  /* Write the header in the heap dump file */
	  _filler->createHeapDumpFile() ;
	  _filler->writeHeader() ;

	  _manager->handleHeapSnapshot(env, dump_level, begin, end, askingForDumpReferences);

	  _filler->closeHeapDumpFile() ;

  } catch ( FillerException ex) {
	  /* Piyush Bug 58049 */
	  errorCode = ex.getErrorCode() ;
#ifdef _DEBUG
	  fprintf(stderr,"Caught Exception in handleHeapSnapShot : Error Code %d\n",errorCode) ;
	  fflush(stderr); 
#endif
  }
#ifdef __OS400__
/* Bug Number 73480 */
  	enum EntryType type;
	/* Delete each of the classes */
	type=Class_t;
	jvmpiAgent_ForAll(Class_t, deleteHashEntry, &type);
	type = Class_t ;
#endif
  return errorCode ;
}

/* Bug 64476 - Wrapper method added for name mangling*/
extern  "C"
void StatelessHeapSnapshotManager_optHeapCallBack(char* filename) {
    _jvmpiAgent_optHeapCallBack.ohdcb(filename) ;
}

