/**********************************************************************
 * 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: print.c,v 1.4 2009/01/06 17:11:49 jkubasta Exp $
 *
 * Contributors:
 * IBM - Initial API and implementation
 **********************************************************************/

#ifdef _JVMPI__ASYNCRONOUS_IO
#ifdef _WIN32
	#include <winsock2.h> /* Bug 134924 */
	#include <windows.h>
#else
	#include <aio.h>
#endif
#endif

#ifndef _WIN32
 #include <fcntl.h>
 #include <sys/stat.h>   /* 199558 */
 #ifdef _HPUX
  #include <unistd.h>
 #endif
#endif

#include "utility.h"
#include "print.h"
#include "options.h"
#include "RASocket.h"
#include "RADataTransfer.h"
#include "RABindings.h"
#include "JvmpiWriter.h"
#include "eventmask.h"
#include "strings.h"
#include "assert.h"

#ifdef BINARY_TRACE
#include "binary_print.h"
#endif /* BINARY_TRACE */

/* CPU timestamp granularity for each plaform */
#ifdef _WIN32									/* _WIN32 */
 #include <process.h>
 #define THREADCPUPRECISION		7
 #define THREADCPUGRANULARITY	10000000
#else											/* else */
 #define THREADCPUPRECISION		6
 #define THREADCPUGRANULARITY	1000000
#endif											/* endif */

#define TIMESTAMPPRECISION	6

#ifdef _JVMPI__ASYNCRONOUS_IO
 #define SEGMENT_SIZE	1024 /*1048576*/
 #define SEGMENT_COUNT	16
#endif

#define XML_OPENING_TAG_TRACE	"<TRACE>"
#define XML_CLOSING_TAG_TRACE	"</TRACE>"


int REALLOCATED_BUFFER_SIZE = 1024;

static char *DOW[7]= {"Sun", "Mon", "Tue", "Wed",
					  "Thu", "Fri", "Sat"};

static char *MOY[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
						"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};

RA_HANDLE			_jvmpiAgent_outFile = RA_HANDLE_NULL;			/* The output file */

int                 _jvmpiAgent_suspendIO = 1;          /* TRUE = suspend output, FALSE = produce output */


#ifdef _JVMPI__ASYNCRONOUS_IO
#ifdef _WIN32
typedef struct {
	int count;
	int offset;
	BOOL			flushPending;
	OVERLAPPED		overlap;
	char			buffer[SEGMENT_SIZE];
}IOSegment_t;

#else
#ifdef _AIX
 #define AIO_WRITE(fildes, aiocb)  aio_write(fildes, aiocb)
#else
 #define AIO_WRITE(fildes, aiocb) aio_write(aiocb)
#endif

typedef struct {
	int count;
	int offset;
	BOOL			flushPending;
	struct aiocb    aiocb;
	char			buffer[SEGMENT_SIZE];
}IOSegment_t;

#endif


IOSegment_t			_ioBuffers[SEGMENT_COUNT];			/* The buffers for IO */
int					_ioSegment=0;						/* The currently active IO segment */
long				_fileOffset=0;						/* The offset in the file */


static int getSegment()
{
	int oldCount;
	int currentSegment=_ioSegment;
	/* Increment the count on the current segment */
	oldCount=_ioBuffers[currentSegment].count;
	while(!ra_atomicCAS((int*)&_ioBuffers[currentSegment].count, (int*)&oldCount, (int)(oldCount+1)));
	return currentSegment;
}

static void releaseSegment(int currentSegment, int segmentOffset)
{
	int oldCount;

	/* Decrement the count on the segment */
	oldCount=_ioBuffers[currentSegment].count;
	while(!ra_atomicCAS((int*)&_ioBuffers[currentSegment].count, (int*)&oldCount, (int)(oldCount-1)));

	/* If we were the last element in the segment does it need to be flushed? */
	if(oldCount==1) {
		int currentFileOffset;
		int bytesWritten;

		if(_ioBuffers[currentSegment].flushPending)
		{
			/* Increment the file pointer for the next IO operation */
			currentFileOffset=_fileOffset;
			while(!ra_atomicCAS(&_fileOffset, &currentFileOffset, currentFileOffset+segmentOffset));


#ifdef _WIN32
			_ioBuffers[currentSegment].overlap.Offset=currentFileOffset;
startWrite:
			/* Ensure it has finished flushing from the last time it was full */
			WaitForSingleObject(_ioBuffers[currentSegment].overlap.hEvent, 0);
			if(!WriteFile(_jvmpiAgent_outFile, _ioBuffers[currentSegment].buffer, _ioBuffers[currentSegment].offset, &bytesWritten, &_ioBuffers[currentSegment].overlap))
			{
				DWORD error=GetLastError();
				if(error!=ERROR_IO_PENDING)
				{
					switch(error)
					{
					case ERROR_NOT_ENOUGH_MEMORY:
					case ERROR_INVALID_USER_BUFFER:
					case ERROR_NOT_ENOUGH_QUOTA:
					case ERROR_WORKING_SET_QUOTA:
						goto startWrite;
					default:
						printf("Severe error pushing IO\n");
						fflush(stdout); 
					}
				}
			}
#else
			_ioBuffers[currentSegment].aiocb.aio_offset=currentFileOffset;
			_ioBuffers[currentSegment].aiocb.aio_nbytes=_ioBuffers[currentSegment].offset;
startWrite:
			printf("Flushing buffer\n");
			fflush(stdout); 
			if(AIO_WRITE(_jvmpiAgent_outFile, &_ioBuffers[currentSegment].aiocb))
			{
					printf("     Flushing failed\n");
					fflush(stdout); 

			}
#endif

			/* Reset the offset of this segment to zero */
			/* while(!ra_atomicCAS(&_ioBuffers[currentSegment].offset, &currentBufferOffset, 0)); */
			_ioBuffers[currentSegment].offset=0;
			_ioBuffers[currentSegment].flushPending=FALSE;
		}
	}

}
#endif /* _JVMPI__ASYNCRONOUS_IO */



void jvmpiAgent_initializeStandaloneIO() {
#ifdef _WIN32
  _jvmpiAgent_outFile=CreateFile(_jvmpiAgent_Options.outputFileName,
								   GENERIC_WRITE,
								   FILE_SHARE_READ,
								   NULL,
								   CREATE_ALWAYS,
								   FILE_ATTRIBUTE_NORMAL
#ifdef _JVMPI__ASYNCRONOUS_IO
								   | FILE_FLAG_OVERLAPPED
#endif
								   ,
								   NULL);

#else
/* 199373 - added permissions */
  _jvmpiAgent_outFile = open(_jvmpiAgent_Options.outputFileName,
						     O_WRONLY|O_CREAT|O_TRUNC,
							 S_IRUSR | S_IWUSR | S_IRGRP );
#endif


  /* Check the file descriptor to ensure it is valid */

  if(_jvmpiAgent_outFile
#ifdef _WIN32
                         == INVALID_HANDLE_VALUE)
#else
                         < 0)
#endif
  {
#ifdef MVS
#pragma convlit(suspend)
#endif
	   fprintf(stderr, "*** Could not open profile output file \"%s\".  Exiting JVM. ***\n", _jvmpiAgent_Options.outputFileName);
	   fflush(stderr); 
#ifdef MVS
#pragma convlit(resume)
#endif
	_jvmpiAgent_jvmpiInterface->ProfilerExit((jint)-1);
  }



#ifdef _JVMPI__ASYNCRONOUS_IO
	int i;
 for(i=0; i<SEGMENT_COUNT; i++)
 {
	 _ioBuffers[i].offset=0;
#ifdef _WIN32
	 _ioBuffers[i].overlap.hEvent=CreateEvent(NULL, FALSE, FALSE, NULL);
	 _ioBuffers[i].overlap.Offset=0;
	 _ioBuffers[i].overlap.OffsetHigh=0;
#else
#ifndef _AIX
	 _ioBuffers[i].aiocb.aio_fildes=_jvmpiAgent_outFile; /* output file */
#else
	 _ioBuffers[i].aiocb.aio_offset=0;					 /* file offset */
	 _ioBuffers[i].aiocb.aio_buf=_ioBuffers[i].buffer;   /* i/o buffer */
	 _ioBuffers[i].aiocb.aio_reqprio=0;					 /* request priority offset */
#ifdef _AIX
	 /*_ioBuffers[i].aiocb.aio_event); */       /* signal number and value */
#else
	  /*_ioBuffers[i].aiocb.aio_sigevent= */               /* signal number and value */
#endif
	 /*_ioBuffers[i].aiocb.aio_lio_opcode=LIO_WRITE; */ 	 /* operation to be preformed */
#endif
#endif
	 _ioBuffers[i].flushPending=FALSE;
 }
#endif /* _JVMPI__ASYNCRONOUS_IO */
}

void jvmpiAgent_cleanupStandaloneIO()
{
#ifdef _JVMPI__ASYNCRONOUS_IO
  int segment=getSegment();
  _ioBuffers[segment].flushPending=TRUE;
  releaseSegment(segment, _ioBuffers[segment].offset);
#endif /* _JVMPI__ASYNCRONOUS_IO */
  CLOSE_RA_HANDLE(_jvmpiAgent_outFile);
}


/** PRINT  **********************************************************************
  * Transmit/print the raw data to the median.
  * @param  buffer - the buffer to write to the median.
  * @param  length - number of bytes to write
  */
void jvmpiAgent_print(ThreadPrivateStorage *tps, char *s, unsigned short length)
{

 if (!_jvmpiAgent_suspendIO)
 {
  if (!_jvmpiAgent_Options.standalone)
  {
   /* Insert the length of the data in the buffer and transmit */
#ifdef __OS400__
	  if (s) {
	    /* need to reassign the result back to tps->buffer2 because iconv modified tps->buffer2 */ 
		tps->buffer2 = as400_etoa_tobuffer(s, tps->buffer2); 
		ra_writeMessageBlock(&_jvmpiAgent_Options.targetHdl, RA_BINARY_DATA, (unsigned char *)tps->buffer2, length); /* 232010 */
	  }
#else
   ra_writeMessageBlock(&_jvmpiAgent_Options.targetHdl, RA_BINARY_DATA, (unsigned char *)s, length);
#endif
  }
  else
  {
	int currentBufferOffset;
	BOOL success=FALSE;

	if(!_jvmpiAgent_Options.jinsightFormat) {
	  s[length++]='\n';
	}

#ifndef _JVMPI__ASYNCRONOUS_IO

#ifdef _WIN32
	WriteFile(_jvmpiAgent_outFile, s, length, &currentBufferOffset, NULL);
#else
#ifdef MVS                    /* 174190 */
	if(!_jvmpiAgent_Options.jinsightFormat) {
	  s[length]='\0';           /* need to make the string null terminated for atoe conversion */
	  __atoe(s);
	}
#endif
	write(_jvmpiAgent_outFile, s, length);
#endif
#else /*  _JVMPI__ASYNCRONOUS_IO  */

	/* Always work with the same segment */
	currentSegment=getSegment();

	/* Grab some space within this segment */
	currentBufferOffset=_ioBuffers[currentSegment].offset;
	while(!ra_atomicCAS((int*)&_ioBuffers[currentSegment].offset, (int*)&currentBufferOffset, (int)(currentBufferOffset+length)));

	/* If there is room in this segment copy our data in.  Otherwise mark
	   this buffer to be flushed and increment the segment counter */
	if(currentBufferOffset+length<SEGMENT_SIZE)
	{
#ifdef MVS                    /* 174190 */
	if(!_jvmpiAgent_Options.jinsightFormat) {
	  s[length]='\0';         /* need to make the string null terminated for atoe conversion */
	  __atoe(s);
	}
#endif
		memcpy(&_ioBuffers[currentSegment].buffer[currentBufferOffset], s, length);
		success=TRUE;
	}
	else {
		/* printf("Flush pending\n"); */
		_ioBuffers[currentSegment].flushPending=TRUE;

		/* Increment the segment pointer */
		while(!ra_atomicCAS((int*)&_ioSegment, (int*)&currentSegment, (int)((currentSegment+1)%16)));
	}

	releaseSegment(currentSegment, currentBufferOffset);

	/* If we failed to transfer our data we need to try again */
	if(!success)
	{
		jvmpiAgent_print(tps, s, length);
	}
#endif /* _JVMPI__ASYNCRONOUS_IO */

  }
 }
}

/* REALLOCATE memory if the buffer size insufficient*******************************
 * Check buffer size and realloc memory to prevent 
 * buffer overflow.
 *
 */
void
jvmpiAgent_checkMemorySize(ThreadPrivateStorage *tps, 
						   int in_value,
						   unsigned short current)
{	
	if(in_value > REALLOCATED_BUFFER_SIZE){
		char *p = (char *)ra_allocateMessageBlock((ra_uint_t)(in_value+1) * sizeof(char));
	#ifdef __OS400__
		char *p2 = (char *)ra_allocateMessageBlock((ra_uint_t)(in_value+1) * sizeof(char));
	#endif	
		if(p != NULL && tps->buffer != NULL){			
			memcpy(p, tps->buffer, current);
			p[current] = '\0';
			ra_freeMessageBlock((unsigned char *)tps->buffer);
			tps->buffer = (char *)p;
			REALLOCATED_BUFFER_SIZE = in_value+1;
	#ifdef __OS400__
			memcpy(p2, tps->buffer2, current);
			p2[current] = '\0';
			ra_freeMessageBlock((unsigned char *)tps->buffer2);
			tps->buffer2 = (char *)p2; 
			REALLOCATED_BUFFER_SIZE = in_value+1;
	#endif
		}
	}
}

/** INSERT_ELEMENT_START  ********************************************************
  * Creates an XML entry tag and places it immediately following the data header
  * of the provided buffer. DOES NO BOUNDS CHECKING.
  * with the name specified. This function
  * @param       elementName - The XML tage name
  * @param elementNameLength - the length of the element name
  * @param      buffer - The buffer to place the tag in (at the beginning)
  * @returns        >0 - the next index in the buffer free for writing.
  *                  0 -
  */
static unsigned short
jvmpiAgent_insertElementStart(const char *elementName,
							  unsigned short elementNameLength,
							  ThreadPrivateStorage *tps)
{ 
 if (!_jvmpiAgent_suspendIO)
 {
  tps->buffer[0]='<';
  memcpy(&tps->buffer[1], elementName, elementNameLength);
  return elementNameLength+1;
 }
 return 0;
}
static unsigned short
jvmpiAgent_appendInt16(char *buffer,
						 unsigned short offset,
						 unsigned short value) {
	buffer[offset++]=(unsigned char)value>>8 & 0x00ff;
	buffer[offset++]=(unsigned char)value;
	return offset;
}

static unsigned short
jvmpiAgent_appendInt32(char *buffer,
						 unsigned short offset,
						 unsigned long value) {
	buffer[offset++]=(unsigned char)value>>24 & 0x000000ff;
	buffer[offset++]=(unsigned char)value>>16 & 0x000000ff;
	buffer[offset++]=(unsigned char)value>>8  & 0x000000ff;
	buffer[offset++]=(unsigned char)value;
	return offset;
}


/** APPEND_INTEGER_ATTRIBUTE  **********************************************************
  */
static unsigned short
jvmpiAgent_appendIntegerAttribute(const char *attributeName,
						 unsigned short attributeNameLength,
						 unsigned short offset,
						 int value,
						 char *buffer)
{
#ifdef _WIN32
 buffer[offset++]=' ';
 memcpy(&buffer[offset], attributeName, attributeNameLength);
 offset+=attributeNameLength;
 buffer[offset++]='=';
 buffer[offset++]='\"';
 /* We could optimize this conversion by writing assembley language
	   and keepin track of the offset, instead we will convert using itoa
	   and then add the length of this string to the offset */
 itoa(value, &buffer[offset], 10);
 offset+=strlen(&buffer[offset]);
 buffer[offset++]='\"';
 return offset;
#else
	int length;
#ifdef MVS                    /* 174190 */
#pragma convlit(suspend)
   char intstr[20];
   length=sprintf(intstr,"=\"%d\"",value);
   __etoa(intstr);
	length=sprintf(&buffer[offset], "%c%s%s", 0x20, attributeName, intstr);
#pragma convlit(resume)
#else
	length=sprintf(&buffer[offset], " %s=\"%d\"", attributeName, value);
#endif
	return offset+length;
#endif
}



/** APPEND_INTEGER_64_ATTRIBUTE  **********************************************************
  */
static unsigned short
jvmpiAgent_appendInteger64Attribute(const char *attributeName,
						   unsigned short attributeNameLength,
						   unsigned short offset,
						   Uint64 value,
						   char *buffer)
{
#ifdef _WIN32
 buffer[offset++]=' ';
 memcpy(&buffer[offset], attributeName, attributeNameLength);
 offset+=attributeNameLength;
 buffer[offset++]='=';
 buffer[offset++]='\"';
 /* This is a Microsoft specific conversion routine */
 _ui64toa(value, &buffer[offset], 10);
 offset+=strlen(&buffer[offset]);
 buffer[offset++]='\"';
 return offset;
#else
	int length;
#ifdef MVS                    /* 174190 */
#pragma convlit(suspend)
   char intstr[50];
   length=sprintf(intstr,"=\"%lu\"",value); /*fix 89008*/
   __etoa(intstr);
	length=sprintf(&buffer[offset], "%c%s%s", 0x20, attributeName, intstr);
#pragma convlit(resume)
#else
	length=sprintf(&buffer[offset], " %s=\"%lu\"", attributeName, value); /*fix 89008*/
#endif
	return offset+length;
#endif
}


/** APPEND_LONG_ATTRIBUTE  **********************************************************
  */
static unsigned short
jvmpiAgent_appendLongAttribute(const char *attributeName,
					      unsigned short attributeNameLength,
					      unsigned short offset,
					      long value,
					      char *buffer)
{
#ifdef _WIN32
 buffer[offset++]=' ';
 memcpy(&buffer[offset], attributeName, attributeNameLength);
 offset+=attributeNameLength;
 buffer[offset++]='=';
 buffer[offset++]='\"';
 /* We could optimize this conversion by writing assembley language
	   and keepin track of the offset, instead we will convert using itoa
	   and then add the length of this string to the offset */
 ltoa(value, &buffer[offset], 10);
 offset+=strlen(&buffer[offset]);
 buffer[offset++]='\"';
 return offset;
#else
	int length;
#ifdef MVS                    /* 174190 */
#pragma convlit(suspend)
   char intstr[50];
   length=sprintf(intstr,"=\"%ld\"",value); /*fix 89008*/
   __etoa(intstr);
	length=sprintf(&buffer[offset], "%c%s%s", 0x20, attributeName, intstr);
#pragma convlit(resume)
#else
	length=sprintf(&buffer[offset], " %s=\"%ld\"", attributeName, value); /*fix 89008*/
#endif
	return offset+length;
#endif
}

static unsigned short
jvmpiAgent_appendUnsignedLongAttribute(const char *attributeName,
						      unsigned short attributeNameLength,
						      unsigned short offset,
						      unsigned long value,
						      char *buffer)
{
#ifdef _WIN32
 buffer[offset++]=' ';
 memcpy(&buffer[offset], attributeName, attributeNameLength);
 offset+=attributeNameLength;
 buffer[offset++]='=';
 buffer[offset++]='\"';
 /* We could optimize this conversion by writing assembley language
	   and keepin track of the offset, instead we will convert using itoa
	   and then add the length of this string to the offset */
 ultoa(value, &buffer[offset], 10);
 offset+=strlen(&buffer[offset]);
 buffer[offset++]='\"';
 return offset;
#else
	int length;
#ifdef MVS                    /* 174190 */
#pragma convlit(suspend)
   char intstr[50];
   length=sprintf(intstr,"=\"%lu\"",value); /*fix 89008*/
   __etoa(intstr);
	length=sprintf(&buffer[offset], "%c%s%s", 0x20, attributeName, intstr);
#pragma convlit(resume)
#else
	length=sprintf(&buffer[offset], " %s=\"%lu\"", attributeName, value); /*fix 89008*/
#endif
	return offset+length;
#endif
}

static unsigned short
jvmpiAgent_appendListInteger(unsigned short offset,
					    int value,
					    char *buffer)
{
#ifdef _WIN32
 /* Overwrite the previously appended space  */
 buffer[offset-1]=',';
 ltoa(value, &buffer[offset], 10);
 offset+=strlen(&buffer[offset]);
 buffer[offset++]='\"';
 return offset;
#else
	int length;
	buffer[offset-1]=',';
#ifdef MVS                    /* 174190 */
#pragma convlit(suspend)
#endif
	length=sprintf(&buffer[offset], "%d\"", value);
#ifdef MVS                    /* 174190 */
  buffer[offset+length]='\0';
#pragma convlit(resume)
  __etoa(buffer+offset);
#endif
	return offset+length;
#endif
}

static unsigned short
jvmpiAgent_appendListUnsignedLong(unsigned short offset,
						 unsigned long value,
						 char *buffer)
{
#ifdef _WIN32
 /* Overwrite the previously appended space  */
 buffer[offset-1]=',';
 ultoa(value, &buffer[offset], 10);
 offset+=strlen(&buffer[offset]);
 buffer[offset++]='\"';
 return offset;
#else
	int length;
	buffer[offset-1]=',';
#ifdef MVS                    /* 174190 */
#pragma convlit(suspend)
#endif
	length=sprintf(&buffer[offset], "%u\"", value);
#ifdef MVS                    /* 174190 */
  buffer[offset+length]='\0';
#pragma convlit(resume)
  __etoa(buffer+offset);
#endif
	return offset+length;
#endif
}


/** APPEND_STRING_ATTRIBUTE  **********************************************************
  */

/* 50273
 * KC: Certain characters occurring in string attributes must be escaped
 * to make them palatabale to XML. For example, '>' better show up as
 * '&gt;'. The code below is in support of these conversions, on behalf
 * of jvmpiAgent_appendStringAttribute.
 */
#ifndef MAX
#define MAX(a,b) ((a) >= (b) ? (a) : (b))
#endif

#define MAX_ESCAPED_STRING_SIZE 7
typedef struct escape_seq
{
	char s[MAX_ESCAPED_STRING_SIZE];
	int  len;
} escape_seq_t;

/* ordering in escapees must match that in escape_str table */

#ifdef __OS400__ 
#pragma convert(819)
#endif

const char escapees[] = "<>&\"'";
static const escape_seq_t escape_str[] =
  {
	{/* < */ "&lt;",   sizeof("&lt;") - 1},
	{/* > */ "&gt;",   sizeof("&gt;") - 1},
	{/* & */ "&amp;",  sizeof("&amp;") - 1},
	{/* " */ "&quot;", sizeof("&quot;") - 1},
	{/* ' */ "&apos;", sizeof("&apos;") - 1},
	{"", 0}
  };

#ifdef __OS400__ /* 239987 starts */
#pragma convert(0)
#endif

/* To accomodate escape strings, we need to alloc some extra space.
 * Do it in chunks instead of one string at a time, to minimize
 * the allocation thrash. */
#define XML_ESCAPE_CHUNK_SIZE 128


typedef struct range {
	unsigned char lower; 
	unsigned char upper; 
} Range; 


/* This table of values is based on Table 3-6 "Well-formed UTF-8
Byte Sequences", available at 
http://www.unicode.org/versions/Unicode4.0.0/ch03.pdf

Entries with 0x00 as the upper part of the range are NOT part of
the expected byte sequence in a well-formed utf-8 byte sequence. 
For example, for utf8Table[1], the first character seen in the valid
byte sequence is between 0xC2 and 0xDF, and the next must be between 0x80
and 0xBF. Since utf8Table[1][2].upper is 0x00, the next character beyond this 
is considered to be part of the "next" byte sequence. 
*/ 

Range utf8Table[][4] = 
{ 
	{ {0x00,0x7F},{0x00,0x00},{0x00,0x00}, {0x00,0x00} },
	{ {0xC2,0xDF},{0x80,0xBF},{0x00,0x00}, {0x00,0x00} },
	{ {0xE0,0xE0},{0xA0,0xBF},{0x80,0xBF}, {0x00,0x00} },
	{ {0xE1,0xEC},{0x80,0xBF},{0x80,0xBF}, {0x00,0x00} },
	{ {0xED,0xED},{0x80,0x9F},{0x80,0xBF}, {0x00,0x00} },
	{ {0xEE,0xEF},{0x80,0xBF},{0x80,0xBF}, {0x00,0x00} },
	{ {0xF0,0xF0},{0x90,0xBF},{0x80,0xBF}, {0x80,0xBF} },
	{ {0xF1,0xF3},{0x80,0xBF},{0x80,0xBF}, {0x80,0xBF} },
	{ {0xF4,0xF4},{0x80,0x8F},{0x80,0xBF}, {0x80,0xBF} }
}; 



/* stripControls(const char *inbuf, char **outBuf)
 
   Strip invalid UTF-8 characters. 

   This function strips invalid UTF-8 characters by verifying that the
   byte sequences within the buffer provided (inbuf) are valid according
   to the "Well-formed UTF-8 Byte Sequences" table. 

   @param inbuf the buffer to strip of invalid utf-8 characters
   @param outBuf the buffer into which to put the stripped version of inbuf
   @return outBuf if any characters were stripped from inbuf, NULL otherwise. 
*/ 
static char* 
stripControls(const unsigned char *inbuf, unsigned char **outBuf) {
	const unsigned char * end;
	unsigned char *offset=NULL;
	unsigned char *current=(unsigned char*)inbuf;
	end=inbuf+strlen((const char *)inbuf);
	while(current<end) {
		int idx, row = -1, 	numCharsToStrip = 0, numCharsToPass = 1; 

		/* we first determine the row of the UTF-8 table that we are dealing 
		with. This will allow us to examine the byte sequence to see
		if the individual bytes fall within the expected range as laid out in 
		the table. */ 
		for (idx = 0; idx < 9; idx++) {
			if (*current >= utf8Table[idx][0].lower &&
				*current <= utf8Table[idx][0].upper) {
					row = idx; 
					break; 
			}
		}


		/* If we were unable to determine the row, then this character
		   comprises an ill-formed byte-sequence and should be stripped */ 
		if (row == -1) {
			numCharsToStrip = 1; 
		}

		/* If we are dealing with the first row, then this is a standard ASCII
	       character and we must check if there are any control characters 
		   to be stripped */ 
		else if (row == 0) {
			if (*current < 0x20) {
				switch (*current) {
					case 0x9: /* Horizontal TAB */ 
					case 0xA: /* New line */ 
					case 0xD: /* Carriage return */ 
						break; /* do not strip the character */ 
					default:
						numCharsToStrip = 1; /* strip the character */
						break;  
				}
			}
		}

		/* Otherwise verify that each byte in the byte-sequence
		falls within the required range as dictated by the utf-8 table */ 
		else {
			for (idx = 1; idx < 4 && current+idx < end &&  
				utf8Table[row][idx].upper != 0x00; idx++) {
					if (*(current+idx) < utf8Table[row][idx].lower ||
						*(current+idx) > utf8Table[row][idx].upper) {
							/* We have detected an invalid byte in the
							   byte sequence. We can safely strip the 
							   bytes up to but not including the
							   current byte we are examining. */ 
							numCharsToStrip = idx;
							break;
					}
					else {
						numCharsToPass++; 
					}
			}
			/* If we fell off the end before the byte-sequence was expected
			   to finish then we should strip the characters */ 
			if (current + idx >= end && idx < 4 
				&& utf8Table[row][idx].upper != 0x00) {
                    numCharsToStrip = idx; 
			}

			/* Code points U+FFFE and U+FFFF are not valid XML -- we need
			the following special case to check for the UTF-8 encodings of these 
			code points and strip them */ 
			if (numCharsToStrip == 0 && row == 5 && idx == 3) {
				/* check for code points U+FFFE or U+FFFF */ 
				if ( (*current == 0xEF) && 
					 (*(current+1) == 0xBF) &&
					 ( (*(current+2) == 0xBE) || (*(current+2) == 0xBF) ) ) {
						 numCharsToStrip = 3; 
				}
			}
		}

		if (numCharsToStrip > 0) {
			/* if necessary create the new buffer into which we put 
			   the stripped version of the original buffer */ 
			if(!offset) {
				offset=(unsigned char*)malloc(strlen((const char *)inbuf));
				memcpy(offset, inbuf, current-inbuf);
				*outBuf=offset;
				offset+=current-inbuf;
			}
			current += numCharsToStrip; 
		}
		else if(offset) {
			if (numCharsToPass == 1) {
				/* we don't bother with the overhead calling the memcpy
				   function in the most frequent case */ 
				*offset++ = *current++; 
			}
			else {
				memcpy(offset,current,numCharsToPass); 
				offset += numCharsToPass; 
				current += numCharsToPass;
			}
		}
		else {
			current += numCharsToPass;
		}	 
	}


	if(offset) {
		*offset='\0';
		return (char *)*outBuf;
	}
	return NULL;

}

/* The basic idea is to locate and quickly copy the substrings
 * within inbuf that do not require escaping, then do something more
 * costly for handling the special characters. An assumption is made
 * that special chars will be few and far between, so the code is
 * optimized first for the case where there are no special chars
 * and then for large substrings of "normal" chars. */
static char*
escape_for_xml(const char *inbuf, char **outbuf)
{
	size_t span;				/* span of substr not requiring escape */
	char *op;					/* current loc in output buffer */
	char *start_op;				/* beginning of output buffer */
	char *end_op;				/* end of alloc'd output buffer */
	size_t out_len;				/* size of alloc'd output buffer */
	const char *ip;				/* current loc in inbuf */
	const char *end_ip;			/* ptr to terminating null in inbuf */
	size_t in_len = strlen(inbuf);
	

	/* Check the green path first */
	span = strcspn(inbuf, escapees);
	if (span == in_len) {
		/* No chars require escaping. We're outta here. */
		return NULL;
	}

	/* There are one or more escapable characters. */
	ip = inbuf;
	end_ip = inbuf + in_len;

	out_len = in_len + XML_ESCAPE_CHUNK_SIZE;
	start_op = (char*) malloc(out_len);
	end_op = start_op + out_len;
	op = start_op;

	while (ip < end_ip)
	{
		int i;

		/* do we need more space in output buffer? */
		if (op + span + MAX_ESCAPED_STRING_SIZE >= end_op)
		{
			size_t used = op - start_op;

			out_len += MAX(span+MAX_ESCAPED_STRING_SIZE,
							XML_ESCAPE_CHUNK_SIZE);
			start_op = (char*) realloc(start_op, out_len);
			op = start_op + used;		/* reset curr ptr in new buffer */
			end_op = start_op + out_len;
		}

		/* handle unescaped portion with straight copy */
		if (span > 0) {
			memcpy(op, ip, span);
			op += span;
			ip += span;
		}

		/* handle char requiring escaping */
		for (i = 0; escape_str[i].len > 0; i++) {
			if ( *ip == escapees[i] ) {
				memcpy(op, escape_str[i].s, escape_str[i].len);
				op += escape_str[i].len;
				ip++;
				break;
			}
		}

		/* are there any more chars requiring escaping? */
		span = strcspn(ip, escapees);
	}
	*op = '\0';
	*outbuf = start_op;

	return start_op;
}

static unsigned short
jvmpiAgent_appendStringAttribute(const char *attributeName,
												 unsigned short attributeNameLength,
												 unsigned short offset,
												 const char *in_value,
												 ThreadPrivateStorage *tps)
{
	int valLength;
	int addToBuffer;
	
	valLength= in_value ? strlen(in_value) : 0;
	
	addToBuffer = offset + 4 + attributeNameLength + valLength + 1;
	jvmpiAgent_checkMemorySize(tps, addToBuffer, offset);
	
	tps->buffer[offset++]=' ';
	memcpy(&tps->buffer[offset], attributeName, attributeNameLength);
	offset+=attributeNameLength;
	tps->buffer[offset++]='=';
	tps->buffer[offset++]='\"';
	if(valLength>0)
	{
		const char *value;
		const char *strippedValue=NULL;

		/* Strip invalid control characters from the string.  These will mess up the XML */

#ifdef __OS400__ 
		if( !strcmp(attributeName, APPLICATION_NAME_ATTRIBUTE) ||
			!strcmp(attributeName, GROUP_NAME_ATTRIBUTE) ||
			!strcmp(attributeName, NAME_ATTRIBUTE) ||
			!strcmp(attributeName, PARENT_NAME_ATTRIBUTE) ||
			!strcmp(attributeName, SOURCE_NAME_ATTRIBUTE) ||
			!strcmp(attributeName, SIGNATURE_ATTRIBUTE) ||
			!strcmp(attributeName, THREAD_NAME_ATTRIBUTE) ||
			!strcmp(attributeName, PATTERN_ATTRIBUTE) ||
			!strcmp(attributeName, METHOD_PATTERN_ATTRIBUTE)) {
#endif
		if(stripControls((unsigned char *)in_value, (unsigned char**)&strippedValue)) {
			valLength = strlen(strippedValue);
		}
		else {
			strippedValue=in_value;
		}
#ifdef __OS400__
		}
		else {
			strippedValue = in_value; 
		}
#endif 

		if (escape_for_xml(strippedValue, (char**)&value)) {	/* 50273 */
			/* we had to add escape sequences to input string */
			valLength = strlen(value);
		} else {
			/* nothing changed, use orig input, don't reset length */
			value = strippedValue;
		}

#ifdef __OS400__ /* 236501 */
		if( !strcmp(attributeName, APPLICATION_NAME_ATTRIBUTE) ||
			!strcmp(attributeName, GROUP_NAME_ATTRIBUTE) ||
			!strcmp(attributeName, NAME_ATTRIBUTE) ||
			!strcmp(attributeName, PARENT_NAME_ATTRIBUTE) ||
			!strcmp(attributeName, SOURCE_NAME_ATTRIBUTE) ||
			!strcmp(attributeName, SIGNATURE_ATTRIBUTE) ||
			!strcmp(attributeName, THREAD_NAME_ATTRIBUTE) ||
			!strcmp(attributeName, PATTERN_ATTRIBUTE) ||
			!strcmp(attributeName, METHOD_PATTERN_ATTRIBUTE)) {
			memcpy(&tps->buffer[offset], as400_atoe((char*)value), valLength); /* 232010 */
		}
		else {
			memcpy(&tps->buffer[offset], (char*)value, valLength); /* 232010 */
		}
#else
		memcpy(&tps->buffer[offset], value, valLength);
	
#endif

		if(strippedValue!=in_value) {
			free((void*)strippedValue);
		}

		if (value != strippedValue) {	/* 50273 */
			/* pointing to buffer alloc'd by escape_for_xml */
			free((void*)value);
		}

	}
	offset+=valLength;
	tps->buffer[offset++]='\"';

	return offset;
}


/** APPEND_ELEMENT_END  ********************************************************
  * Creates an XML closing tag and places in at the end of the provided buffer.
  * If the elementName is NULL the entire buffer is appended with the closing
  * tag.  If it is non-NULL the buffer is loaded with a closing tag with the
  * specified name.  NOTE:  When a elementName is specified the buffer is trampled
  * @param       elementName - The XML tag name, NULL for empty tag
  * @param elementNameLength - length of the XML tag name, ignored if elementName=NULL
  * @param            offset - the offset in the buffer to place the closing tag
  * @param            buffer - The buffer to place the tag ending
  * @returns			>0   - the length of the  entire element
  */
static unsigned short
jvmpiAgent_appendElementEnd(const char *elementName,
					   unsigned short elementNameLength,
					   unsigned short offset,
					   ThreadPrivateStorage *tps)
{
 if (!_jvmpiAgent_suspendIO)
 {
  if(elementName!=NULL)
  {
   memcpy(&tps->buffer[offset], elementName, elementNameLength);
   offset+=elementNameLength;
  }
  memcpy(&tps->buffer[offset], "/>", 2);
 }
 return offset+2;
}



/*
 * Used to start a new empty element
 */
static unsigned short
jvmpiAgent_insertEmptyEventHeader(JNIEnv *env_id,
								  ThreadPrivateStorage *tps,
								  const char *eventName,
								  unsigned short eventNameLength)
{
 unsigned short current=0;
 if (!_jvmpiAgent_suspendIO)
 {
  current=jvmpiAgent_insertElementStart(eventName, eventNameLength, tps);
  if (jvmpiAgent_isPrintStaticId())
  {
   current=jvmpiAgent_appendIntegerAttribute(STATIC_THREAD_IDREF_ATTRIBUTE,
					 STRLEN_STATIC_THREAD_IDREF_ATTRIBUTE,
					 current,
					 tps->staticThreadId,
					 tps->buffer);
  }
  if (jvmpiAgent_isPrintObjId())
  {
   current=jvmpiAgent_appendIntegerAttribute(THREAD_IDREF_ATTRIBUTE,
					STRLEN_THREAD_IDREF_ATTRIBUTE,
					current,
					(jint)env_id,
					tps->buffer);
  }
 }
 return current;
}

/*
 * Used to start a new empty element
 */
static unsigned short
jvmpiAgent_insertEmptyEventHeader1(JNIEnv *env_id,
								   ThreadPrivateStorage *tps,
								   const char *eventName,
								   unsigned short eventNameLength)
{
 unsigned short current=0;
 if (!_jvmpiAgent_suspendIO)
 {
  current=jvmpiAgent_insertElementStart(eventName, eventNameLength, tps);
  if (jvmpiAgent_isPrintStaticId())
  {
   current=jvmpiAgent_appendIntegerAttribute(STATIC_THREAD_ID_ATTRIBUTE,
				STRLEN_STATIC_THREAD_ID_ATTRIBUTE,
				current,
				tps->staticThreadId,
				tps->buffer);
  }
  if (jvmpiAgent_isPrintObjId())
  {
   current=jvmpiAgent_appendIntegerAttribute(THREAD_ID_ATTRIBUTE,
				STRLEN_THREAD_ID_ATTRIBUTE,
				current,
				(jint)env_id,
				tps->buffer);
  }
 }
 return current;
}

static unsigned short
jvmpiAgent_printTraceIdrefAttribute(ThreadPrivateStorage *tps,
									unsigned short current)
{
 if (_jvmpiAgent_Options.traceIdrefs)
 {
  return jvmpiAgent_appendStringAttribute(TRACE_IDREF_ATTRIBUTE, STRLEN_TRACE_IDREF_ATTRIBUTE, current, _jvmpiAgent_trace_id , tps);
 }
 else
 {
  return current;
 }
}


/** APPEND__LABELED_TIMESTAMP  ****************************************************
  *
  */
static unsigned short
jvmpiAgent_appendLabeledTimestamp(char *buffer,
				  unsigned short offset,
				  const char *attributeName,
				  unsigned short attributeNameLength,
				  timestamp_t time,
				  BOOL asInterval) {
#ifdef MVS                    /* 174190 */
   int mycurr;
#endif

 
 buffer[offset++]=' ';
 memcpy(&buffer[offset], attributeName, attributeNameLength);
 offset+=attributeNameLength;
 buffer[offset++]='=';
 buffer[offset++]='\"';

#ifdef MVS                    /* 174190 */
   mycurr = offset;
#pragma convlit(suspend)
#endif

 /* convert the time to a string using helper method that is locale-insensitive */ 
 offset = double2string(ticksToTime2(time, asInterval),buffer,offset,9); 

 buffer[offset++]='\"';
#ifdef MVS                    /* 174190 */
  buffer[offset]='\0';
#pragma convlit(resume)
  __etoa(buffer+mycurr);
#endif
 return offset;
}

/** APPEND_TIMESTAMP  ****************************************************
  *
  */
static unsigned short
jvmpiAgent_appendTimestamp(char *buffer,
						   unsigned short offset,
						   timestamp_t time)
{
  return jvmpiAgent_appendLabeledTimestamp(buffer, offset, TIME_ATTRIBUTE, STRLEN_TIME_ATTRIBUTE, time, FALSE);
}


static unsigned short
jvmpiAgent_appendOverhead(char *buffer,
						   unsigned short offset,
						   Uint64 time)
{
  return jvmpiAgent_appendLabeledTimestamp(buffer, offset, OVERHEAD_ATTRIBUTE, STRLEN_OVERHEAD_ATTRIBUTE, time, TRUE);
}

/** APPEND_TIMESTAMP  ****************************************************
  *
  */
static unsigned short
jvmpiAgent_appendString(char *buffer,
						unsigned short offset,
						const char *value)
{
	int length=strlen(value);
	memcpy(&buffer[offset], value, length+1);
	return offset+length+1;
}




/** PRINT_COLLATION_VALUE_ATTRIBUTE  **********************************************
  */
static unsigned short
jvmpiAgent_printCollationValueAttribute(char *buffer,
										unsigned short current,
										SegmentedValue_t *collationValue)
{
 if (_jvmpiAgent_Options.collationValues)
 {
#ifdef SEGMENTED_VALUE_MULTIWORD
  unsigned long i;
  current=jvmpiAgent_appendUnsignedLongAttribute(COLLATION_VALUE_ATTRIBUTE, STRLEN_COLLATION_VALUE_ATTRIBUTE, current, collationValue->values[0], buffer);
  for (i = 1; i < collationValue->numberOfWords; i++)
  {
   current=jvmpiAgent_appendListUnsignedLong(current, collationValue->values[i], buffer);
  }
#else
  current=jvmpiAgent_appendUnsignedLongAttribute(COLLATION_VALUE_ATTRIBUTE, STRLEN_COLLATION_VALUE_ATTRIBUTE, current, collationValue->value, buffer);
#endif
 }
 return current;
}

/*
 * Handles the output of a METHOD_COUNT element and attributes.
 */
static int
jvmpiAgent_printMethodCount(HashEntry *hashEntry, void * parm)
{

 if (!_jvmpiAgent_suspendIO && CLASS_ENTRY(METHOD_ENTRY(hashEntry)->classHashEntry)->traceFlag 
	 && METHOD_ENTRY(hashEntry)->traceFlag)
 {
  ThreadPrivateStorage *tps=(ThreadPrivateStorage*)parm;
   unsigned short current=0;
  jvmpiAgent_outputMethodDeclaration(hashEntry, tps);
  current=jvmpiAgent_insertElementStart(METHOD_COUNT_ELEMENT, STRLEN_METHOD_COUNT_ELEMENT, tps);
  current=jvmpiAgent_appendIntegerAttribute(STATIC_METHOD_IDREF_ATTRIBUTE, STRLEN_STATIC_METHOD_IDREF_ATTRIBUTE, current, METHOD_ENTRY(hashEntry)->static_id, tps->buffer);
  current=jvmpiAgent_appendIntegerAttribute(COUNT_ATTRIBUTE, STRLEN_COUNT_ATTRIBUTE, current, METHOD_ENTRY(hashEntry)->methodCount, tps->buffer);

  /*##MW There is a race condition between the increment and the print that must be fixed */
  jvmpiAgent_incrementSegmentedValue(&_jvmpiAgent_collation, 0);
  current=jvmpiAgent_printCollationValueAttribute(tps->buffer, current, &_jvmpiAgent_collation);

  current=jvmpiAgent_printTraceIdrefAttribute(tps, current);
  current=jvmpiAgent_appendElementEnd(NULL, 0, current, tps);
  jvmpiAgent_print(tps, tps->buffer, current);
 }
 return 0;
}


/** PRINT_OPTION  **********************************************************
  * Outputs an OPTION element
  */
void
jvmpiAgent_PrintOption(ThreadPrivateStorage *tps,
					   char *key,
					   char *value)
{
 unsigned short current=0;
 if (!_jvmpiAgent_suspendIO)
 { 
	 current=jvmpiAgent_insertElementStart(OPTION_ELEMENT, STRLEN_OPTION_ELEMENT, tps);
	 current=jvmpiAgent_appendStringAttribute(KEY_ATTRIBUTE,
		 STRLEN_KEY_ATTRIBUTE,
		 current,
		 key,
		 tps);
	 current=jvmpiAgent_appendStringAttribute(VALUE_ATTRIBUTE,
		 STRLEN_VALUE_ATTRIBUTE,
		 current,
		 value,
		 tps);
	 current=jvmpiAgent_appendElementEnd(NULL, 0, current, tps);
	 jvmpiAgent_print(tps, tps->buffer, current);	 
 }
}

unsigned short jvmpiAgent_appendCurrentTimeStamp(char *buffer,
						 unsigned short offset)
{
 timestamp_t timestamp;
 jvmpiAgent_getCurrentTime(&timestamp);
 return jvmpiAgent_appendTimestamp(buffer, offset, timestamp);
}




/* Append the Thread CPU time. 

  This function appends the cumulative cpuTime into the trace. It assumes the time value
  passed in is in nanoseconds (the JVMPI method GetCurrentThreadCPUTime() returns
  values in units of nanoseconds). 

   @param buffer the buffer to write to
   @param offset the offset into the buffer where we're writing
   @param time the cumulative cpu time to put into the trace element (in nanoseconds) 
*/ 
 
static unsigned short
jvmpiAgent_appendThreadCPUTime(char *buffer,
					      unsigned short offset,
					      Uint64 time)
{

  /* convert the time into a double value. This allows us to use our
	utility function double2string to properly output the timestamp */ 
#ifdef _WIN32
 double ts_double = ((double) (signed __int64)time) / ((double)1000000000); 
#else
 double ts_double = ((double)time) / ((double)1000000000); 
#endif 


#ifdef MVS                    /* 174190 */
   int mycurr;
#endif
 
 buffer[offset++]=' ';
 memcpy(&buffer[offset], THREAD_CPU_TIME_ATTRIBUTE, STRLEN_THREAD_CPU_TIME_ATTRIBUTE);
 offset+=STRLEN_THREAD_CPU_TIME_ATTRIBUTE;
 buffer[offset++]='=';
 buffer[offset++]='\"';

#ifdef MVS                    /* 174190 */
   mycurr = offset;
#pragma convlit(suspend)
#endif

 /* convert the time to a string using helper method that is locale-insensitive */ 
offset = double2string(ts_double,buffer,offset,9); 

 buffer[offset++]='\"';
#ifdef MVS                    /* 174190 */
  buffer[offset]='\0';
#pragma convlit(resume)
  __etoa(buffer+mycurr);
#endif
 return offset;
}


/** PRINT_FILTER  **********************************************************
  * Outputs a FILTER element
  */
void
jvmpiAgent_printFilter(ThreadPrivateStorage *tps,
					   Filter *filter) {
    if (!_jvmpiAgent_suspendIO) {

        unsigned short current=0;
        char *startPattern;
		
        current=jvmpiAgent_insertElementStart(FILTER_ELEMENT, STRLEN_FILTER_ELEMENT, tps);
        startPattern=tps->buffer+current;
		current=jvmpiAgent_appendStringAttribute(PATTERN_ATTRIBUTE, STRLEN_PATTERN_ATTRIBUTE, current, filter->pattern, tps);

		*(tps->buffer + current) = '\0';

        /* RKD:  If the pattern contains any '/' replace these with '.' */
        while((startPattern=strchr(startPattern, '/'))) {
	        *startPattern=(char)'.';
        }

        if (jvmpiAgent_getClassFilterMode(filter) == INCLUDE) {
            current=jvmpiAgent_appendStringAttribute(CLASS_MODE_ATTRIBUTE, STRLEN_CLASS_MODE_ATTRIBUTE, current, INCLUDE_VALUE, tps);
        }
        else {
            current=jvmpiAgent_appendStringAttribute(CLASS_MODE_ATTRIBUTE, STRLEN_CLASS_MODE_ATTRIBUTE, current, EXCLUDE_VALUE, tps);
        }
        if (filter->genericPattern == NONE) {
            current=jvmpiAgent_appendStringAttribute(GENERICPATTERN_ATTRIBUTE, STRLEN_GENERICPATTERN_ATTRIBUTE, current, NONE_VALUE, tps);
        }
        else if (filter->genericPattern == PREFIX) {
            current=jvmpiAgent_appendStringAttribute(GENERICPATTERN_ATTRIBUTE, STRLEN_GENERICPATTERN_ATTRIBUTE, current, PREFIX_VALUE, tps);
        }
        else {
            current=jvmpiAgent_appendStringAttribute(GENERICPATTERN_ATTRIBUTE, STRLEN_GENERICPATTERN_ATTRIBUTE, current, SUFFIX_VALUE, tps);
        }

        if(filter->methodDetailCount>0) {
            unsigned int i;
            for(i=0; i<filter->methodDetailCount;i++) {
                unsigned short offset=current;
				offset=jvmpiAgent_appendStringAttribute(METHOD_PATTERN_ATTRIBUTE, STRLEN_METHOD_PATTERN_ATTRIBUTE, offset, filter->methodDetails[i].pattern, tps);
				
				if (filter->methodDetails[i].mode == INCLUDE)
				{
					offset=jvmpiAgent_appendStringAttribute(METHOD_MODE_ATTRIBUTE, STRLEN_METHOD_MODE_ATTRIBUTE, offset, INCLUDE_VALUE, tps);
				}
				else
				{
					offset=jvmpiAgent_appendStringAttribute(METHOD_MODE_ATTRIBUTE, STRLEN_METHOD_MODE_ATTRIBUTE, offset, EXCLUDE_VALUE, tps);
				}

                if (filter->methodDetails[i].genericPattern == NONE) {
                    offset=jvmpiAgent_appendStringAttribute(METHOD_GENERICPATTERN_ATTRIBUTE, STRLEN_METHOD_GENERICPATTERN_ATTRIBUTE, offset, NONE_VALUE, tps);
                }
                else if (filter->methodDetails[i].genericPattern == PREFIX) {
                    offset=jvmpiAgent_appendStringAttribute(METHOD_GENERICPATTERN_ATTRIBUTE, STRLEN_METHOD_GENERICPATTERN_ATTRIBUTE, offset, PREFIX_VALUE, tps);
                }
                else {
                    offset=jvmpiAgent_appendStringAttribute(METHOD_GENERICPATTERN_ATTRIBUTE, STRLEN_METHOD_GENERICPATTERN_ATTRIBUTE, offset, SUFFIX_VALUE, tps);
                }

                offset=jvmpiAgent_printTraceIdrefAttribute(tps, offset);
                offset=jvmpiAgent_appendElementEnd(NULL, 0, offset, tps);
                jvmpiAgent_print(tps, tps->buffer, offset);
            }
        }
        else {
            current=jvmpiAgent_printTraceIdrefAttribute(tps, current);
            current=jvmpiAgent_appendElementEnd(NULL, 0, current, tps);
            jvmpiAgent_print(tps, tps->buffer, current);
        }
    }
}

/*
 This function ensures that the string name can be legally output as XML by translating any
 '<' or '>" characters to '-'.
*/
char * jvmpiAgent_formatName(char *name)
{
	int i;
	if (name)
	{
		for (i=strlen(name)-1; i >=0; i--)
		{
#ifdef __OS400__
#pragma convert(819) /* 236501 */
#endif
			if (name[i] == '<' || name[i] == '>') name[i] = '-';
#ifdef __OS400__
#pragma convert(0)
#endif
		}
	}
	return name;
}


/** PRINT_METHOD  **********************************************************
  * Handles the output of a METHOD element and attributes
  */
void jvmpiAgent_printMethod(MethodEntry *methodEntry,
							ThreadPrivateStorage *tps)
{
 if (!_jvmpiAgent_suspendIO && (_jvmpiAgent_Options.stackInfo > StackInfoNone || _jvmpiAgent_Options.methodCounts))
 {
  unsigned short current=0;

  if(_jvmpiAgent_Options.jinsightFormat)
  {
#ifdef BINARY_TRACE
    unsigned short numBytes = BINARYTRACE_printMethodDefine(tps->buffer, methodEntry);
    jvmpiAgent_print(tps, tps->buffer, numBytes);
#endif /* BINARY_TRACE */
  }
  else
  {
    current=jvmpiAgent_insertElementStart(METHOD_ELEMENT, STRLEN_METHOD_ELEMENT, tps);
    current=jvmpiAgent_appendStringAttribute(NAME_ATTRIBUTE, STRLEN_NAME_ATTRIBUTE, current, jvmpiAgent_formatName(methodEntry->methodData.method_name), tps);
    current=jvmpiAgent_appendStringAttribute(SIGNATURE_ATTRIBUTE, STRLEN_SIGNATURE_ATTRIBUTE, current, methodEntry->methodData.method_signature, tps);

    /* A.M: Print the method detail attribute if the proper option is set */
	if (_jvmpiAgent_Options.methodDetails)
	{
        /* Visibility */
        if(methodEntry->isPrivate) {
            current=jvmpiAgent_appendStringAttribute(VISIBILITY_ATTRIBUTE, STRLEN_VISIBILITY_ATTRIBUTE, current, "private", tps);
        }
        else if(methodEntry->isProtected) {
            current=jvmpiAgent_appendStringAttribute(VISIBILITY_ATTRIBUTE, STRLEN_VISIBILITY_ATTRIBUTE, current, "protected", tps);
        }
        else if(methodEntry->isPublic) {
            current=jvmpiAgent_appendStringAttribute(VISIBILITY_ATTRIBUTE, STRLEN_VISIBILITY_ATTRIBUTE, current, "public", tps);
        }

		/* isNative? */
		current=jvmpiAgent_appendStringAttribute(IS_NATIVE_ATTRIBUTE, STRLEN_IS_NATIVE_ATTRIBUTE, current, (methodEntry->isNative ? "true" : "false"), tps);
		/* isAbstract? */
		current=jvmpiAgent_appendStringAttribute(IS_ABSTRACT_ATTRIBUTE, STRLEN_IS_ABSTRACT_ATTRIBUTE, current, (methodEntry->isAbstract ? "true" : "false"), tps);
		/* isStatic? */
		current=jvmpiAgent_appendStringAttribute(IS_STATIC_ATTRIBUTE, STRLEN_IS_STATIC_ATTRIBUTE, current, (methodEntry->isStatic ? "true" : "false"), tps);
		/* isSynchronized? */
		current=jvmpiAgent_appendStringAttribute(IS_SYNCHRONIZED_ATTRIBUTE, STRLEN_IS_SYNCHRONIZED_ATTRIBUTE, current, (methodEntry->isSynchronized ? "true" : "false"), tps);

		/* Exceptions */
        if (methodEntry->exceptions != (int)NULL && strlen(methodEntry->exceptions) != (int)NULL) {
			current=jvmpiAgent_appendStringAttribute(EXCEPTIONS_ATTRIBUTE, STRLEN_EXCEPTIONS_ATTRIBUTE, current, methodEntry->exceptions, tps);
        }

	}

    if (methodEntry->methodData.start_lineno != -1)
	{
      current=jvmpiAgent_appendIntegerAttribute(START_LINENO_ATTRIBUTE, STRLEN_START_LINENO_ATTRIBUTE, current, methodEntry->methodData.start_lineno, tps->buffer);
	}
    if (methodEntry->methodData.end_lineno != -1)
	{
      current=jvmpiAgent_appendIntegerAttribute(END_LINENO_ATTRIBUTE, STRLEN_END_LINENO_ATTRIBUTE, current, methodEntry->methodData.end_lineno, tps->buffer);
	}
    if(jvmpiAgent_isPrintStaticId())
	{
      current=jvmpiAgent_appendIntegerAttribute(STATIC_METHOD_ID_ATTRIBUTE, STRLEN_STATIC_METHOD_ID_ATTRIBUTE, current, methodEntry->static_id, tps->buffer);
	}
    if(jvmpiAgent_isPrintMethodId())
	{
	  current=jvmpiAgent_appendIntegerAttribute(METHOD_ID_ATTRIBUTE, STRLEN_METHOD_ID_ATTRIBUTE, current, (jint)(methodEntry->methodData.method_id), tps->buffer);
	}
    if (jvmpiAgent_isPrintObjId())
	{
      current=jvmpiAgent_appendIntegerAttribute(CLASS_IDREF_ATTRIBUTE, STRLEN_CLASS_IDREF_ATTRIBUTE, current, (jint)(CLASS_ENTRY(methodEntry->classHashEntry)->classId), tps->buffer);
	}
    if(jvmpiAgent_isPrintStaticId())
	{
      current=jvmpiAgent_appendIntegerAttribute(STATIC_CLASS_IDREF_ATTRIBUTE, STRLEN_STATIC_CLASS_IDREF_ATTRIBUTE, current, (jint)(CLASS_ENTRY(methodEntry->classHashEntry)->static_id), tps->buffer);
	}
    current=jvmpiAgent_printCollationValueAttribute(tps->buffer, current, &methodEntry->collation);
    current=jvmpiAgent_printTraceIdrefAttribute(tps, current);
    current=jvmpiAgent_appendElementEnd(NULL, 0, current, tps);
    jvmpiAgent_print(tps, tps->buffer, current);
  }
 }
}

/** PRINT_METHOD_ENTRY_EVENT  **********************************************
  * Handles the output of a METHOD_ENTRY, METHOD_CALL element and attributes
  */
void jvmpiAgent_printMethodEntryEvent(JVMPI_Event *event,
                                      ThreadLocalStorage *tps,
                                      StackEntry *stackEntry,
                                      unsigned long stackDepth) {
 unsigned short current=0;

 /* Print the information */
 stackEntry->printed = 1; /* Indicate that this entry is printed */
 jvmpiAgent_outputMethodDeclaration(stackEntry->methodHashEntry, tps);

 /* Make sure that the objAlloc is printed if necessary. 
	The following conditions ensure that if either the attribute transientObjIdRef, 
	or objIdRef is printed in the methodEntry element, the objAlloc 
	will have been 	printed first. (The conditions come directly from those used
	for testing whether to print the attribute -- see below.) 
	bugzilla_46357
 */ 
 
	if( stackEntry->objectHashEntry &&
		( (jvmpiAgent_isPrintObjId() && _jvmpiAgent_Options.mode==TraceModeFull) ||
		jvmpiAgent_isPrintStaticId())) {

		if (!stackEntry->objectHashEntry->printed) {
			jvmpiAgent_printObjAllocElement(stackEntry->objectHashEntry,event->env_id, 0); 
		}
	}


 if(_jvmpiAgent_Options.jinsightFormat)
 {
#ifdef BINARY_TRACE
   unsigned short numBytes = BINARYTRACE_printMethodEnter(tps->buffer, stackEntry);
   jvmpiAgent_print(tps, tps->buffer, numBytes);
#endif /* BINARY_TRACE */
 }
 else
 {
   /* RKD:  There is no longer a need for differentiating between method entry and method call events
            in the profiler as we are not supporting multiple process tracing correlation.  If we ever
			do go down that route we will need to differntiate.
   current=jvmpiAgent_insertEmptyEventHeader(event->env_id, tps, CLASS_ENTRY(METHOD_ENTRY(stackEntry->methodHashEntry)->classHashEntry)->traceFlag ? METHOD_ENTRY_ATTRIBUTE : METHOD_CALL_ATTRIBUTE, (unsigned short)(CLASS_ENTRY(METHOD_ENTRY(stackEntry->methodHashEntry)->classHashEntry)->traceFlag ? STRLEN_METHOD_ENTRY_ATTRIBUTE : STRLEN_METHOD_CALL_ATTRIBUTE));
    */
   current=jvmpiAgent_insertEmptyEventHeader(event->env_id, tps, METHOD_ENTRY_ATTRIBUTE, STRLEN_METHOD_ENTRY_ATTRIBUTE );

   if(_jvmpiAgent_Options.timestamp)
   {
     current=jvmpiAgent_appendTimestamp(tps->buffer, current, stackEntry->timestamp );
   }
   if(jvmpiAgent_isPrintStaticId())
   {
     current=jvmpiAgent_appendIntegerAttribute(STATIC_METHOD_IDREF_ATTRIBUTE, STRLEN_STATIC_METHOD_IDREF_ATTRIBUTE, current, (jint)(METHOD_ENTRY(stackEntry->methodHashEntry)->static_id), tps->buffer);
   }
   if(jvmpiAgent_isPrintMethodId())
   {
 	 current=jvmpiAgent_appendIntegerAttribute(METHOD_IDREF_ATTRIBUTE, STRLEN_METHOD_IDREF_ATTRIBUTE, current, (jint)( ((MethodHashKey *)stackEntry->methodHashEntry->id)->id), tps->buffer);
   }


   /* Only print the object information when in FULL TraceMode and when requested */
   if(jvmpiAgent_isPrintObjId() && _jvmpiAgent_Options.mode==TraceModeFull)
   {
     current=jvmpiAgent_appendIntegerAttribute(OBJ_IDREF_ATTRIBUTE, STRLEN_OBJ_IDREF_ATTRIBUTE, current, stackEntry->objectHashEntry ? (jint)((ObjectHashKey*)stackEntry->objectHashEntry->id)->id : 0, tps->buffer);
     current=jvmpiAgent_appendIntegerAttribute(CLASS_IDREF_ATTRIBUTE, STRLEN_CLASS_IDREF_ATTRIBUTE, current, (jint)((ClassHashKey*)METHOD_ENTRY(stackEntry->methodHashEntry)->classHashEntry->id)->id, tps->buffer);
   }
   if (stackEntry->objectHashEntry && jvmpiAgent_isPrintStaticId())
   {
     current=jvmpiAgent_appendIntegerAttribute(STATIC_OBJ_IDREF_ATTRIBUTE, STRLEN_STATIC_OBJ_IDREF_ATTRIBUTE, current, stackEntry->objectHashEntry ? OBJECT_ENTRY(stackEntry->objectHashEntry)->static_id : 0 , tps->buffer);
   }
   if(jvmpiAgent_isPrintStaticId())
   {
     current=jvmpiAgent_appendIntegerAttribute(STATIC_CLASS_IDREF_ATTRIBUTE, STRLEN_STATIC_CLASS_IDREF_ATTRIBUTE, current, CLASS_ENTRY(METHOD_ENTRY(stackEntry->methodHashEntry)->classHashEntry)->static_id, tps->buffer);
   }

   if(_jvmpiAgent_Options.ticket)
   {
     current=jvmpiAgent_printTicketAttribute(&stackEntry->ticket,tps->buffer, current);
   }
   current=jvmpiAgent_appendIntegerAttribute(STACK_DEPTH_ATTRIBUTE, STRLEN_STACK_DEPTH_ATTRIBUTE, current, stackDepth, tps->buffer);
   if (_jvmpiAgent_Options.contextFlow)
   {
     /*## Values of context flow information not implemented yet. */
     current=jvmpiAgent_appendIntegerAttribute(SEQUENCE_COUNTER_ATTRIBUTE, STRLEN_SEQUENCE_COUNTER_ATTRIBUTE, current, 0, tps->buffer);
     current=jvmpiAgent_appendStringAttribute(CONTEXT_DATA_ATTRIBUTE, STRLEN_CONTEXT_DATA_ATTRIBUTE, current, "##not implemented yet##", tps);
   }

   /*##MW There is a race condition between the increment and the print that must be fixed */
   jvmpiAgent_incrementSegmentedValue(&_jvmpiAgent_collation, 0);
   current=jvmpiAgent_printCollationValueAttribute(tps->buffer, current, &_jvmpiAgent_collation);

   current=jvmpiAgent_printTraceIdrefAttribute(tps, current);
   current=jvmpiAgent_appendElementEnd(NULL, 0, current, tps);
   jvmpiAgent_print(tps, tps->buffer, current);
 }

}

/** PRINT_AG_METHOD_ENTRY_EVENT  **************************preagg/135437*******
  *
  * Handles the output of a AG_METHOD_ENTRY element and attributes
  */
void jvmpiAgent_printAgMethodEntryEvent(ThreadPrivateStorage * tps, StackFrame * call) {

   unsigned short current=0;

   /* Note that tps->env is passed in place of event->env_id passed elsewhere and should be equivalent in the preAgg case. */
   current=jvmpiAgent_insertEmptyEventHeader(tps->env, tps, AG_METHOD_ENTRY_ELEMENT, STRLEN_AG_METHOD_ENTRY_ELEMENT);

   current=jvmpiAgent_appendIntegerAttribute(STATIC_METHOD_IDREF_ATTRIBUTE, STRLEN_STATIC_METHOD_IDREF_ATTRIBUTE, current, 
                                             (jint)(METHOD_ENTRY(call->methodHashEntry)->static_id), tps->buffer);

   current=jvmpiAgent_appendLabeledTimestamp(tps->buffer, current, BASETIME1_ATTRIBUTE, STRLEN_BASETIME1_ATTRIBUTE, call->baseTime, TRUE);
   current=jvmpiAgent_appendLabeledTimestamp(tps->buffer, current, MINTIME_ATTRIBUTE, STRLEN_MINTIME_ATTRIBUTE, call->minTime, TRUE);
   current=jvmpiAgent_appendLabeledTimestamp(tps->buffer, current, MAXTIME_ATTRIBUTE, STRLEN_MAXTIME_ATTRIBUTE, call->maxTime, TRUE);   
   
   current=jvmpiAgent_appendIntegerAttribute(COUNT_ATTRIBUTE, STRLEN_COUNT_ATTRIBUTE, current, call->numCalls, tps->buffer);

   if (_jvmpiAgent_Options.cpuTime) {
      current=jvmpiAgent_appendThreadCPUTime(tps->buffer, current, (Uint64)(call->baseCPUTime)); 
   }

   current=jvmpiAgent_appendElementEnd(NULL, 0, current, tps);   
   jvmpiAgent_print(tps, tps->buffer, current);
}

/** PRINT_THREAD_START_ELEMENT  ********************************************
  *
  */
void
jvmpiAgent_printThreadStartElement(JNIEnv *env_id,
								   HashEntry *threadHashEntry)
{
 if (!_jvmpiAgent_suspendIO)
 {
  unsigned short current=0;
  HashEntry *objectHashEntry = 0;
  ThreadLocalStorage *tps = THREAD_ENTRY(threadHashEntry);
  timestamp_t now;

  threadHashEntry->printed = 1;
  jvmpiAgent_getCurrentTime(&now);

  if(_jvmpiAgent_Options.jinsightFormat)
  {
#ifdef BINARY_TRACE
    unsigned short numBytes = BINARYTRACE_printThreadStart(tps->buffer, tps);
    jvmpiAgent_print(tps, tps->buffer, numBytes);
#endif /* BINARY_TRACE */
  }
  else
  {
    /* The thread object is found using a special function */
    jobjectID threadObject=_jvmpiAgent_jvmpiInterface->GetThreadObject(env_id);

    /* Ensure our thread object has been declared */
    objectHashEntry = jvmpiAgent_FindObjectSymbolWithAllocate(threadObject, env_id);


    current=jvmpiAgent_insertEmptyEventHeader1(((ThreadHashKey*)threadHashEntry->id)->id, tps, THREAD_START_ELEMENT, STRLEN_THREAD_START_ELEMENT);
    /* Get the timestamp information if necessary */
    if(_jvmpiAgent_Options.timestamp)
	{
      current=jvmpiAgent_appendTimestamp(tps->buffer, current, now );
	}
	current=jvmpiAgent_appendStringAttribute(THREAD_NAME_ATTRIBUTE, STRLEN_THREAD_NAME_ATTRIBUTE, current, jvmpiAgent_formatName(tps->threadName), tps);
    current=jvmpiAgent_appendStringAttribute(GROUP_NAME_ATTRIBUTE, STRLEN_GROUP_NAME_ATTRIBUTE, current, jvmpiAgent_formatName(tps->groupName), tps);
    current=jvmpiAgent_appendStringAttribute(PARENT_NAME_ATTRIBUTE, STRLEN_PARENT_NAME_ATTRIBUTE, current, jvmpiAgent_formatName(tps->parentName), tps);
    if(jvmpiAgent_isPrintObjId())
	{
      current=jvmpiAgent_appendIntegerAttribute(OBJ_IDREF_ATTRIBUTE, STRLEN_OBJ_IDREF_ATTRIBUTE, current, (jint)threadObject, tps->buffer);
	}

    /* Since we don't see an OBJ_ALLOC for some of the system threads we can only output a 0 for the static object id */
    /* ##MW Perhaps we could internally manufacture an object and use that to hold a unique static id */
    if(jvmpiAgent_isPrintStaticId())
	{
      current=jvmpiAgent_appendIntegerAttribute(STATIC_OBJ_IDREF_ATTRIBUTE, STRLEN_STATIC_OBJ_IDREF_ATTRIBUTE, current, objectHashEntry ? OBJECT_ENTRY(objectHashEntry)->static_id : 0, tps->buffer);
	}
    current=jvmpiAgent_printCollationValueAttribute(tps->buffer, current, &tps->collation);
    current=jvmpiAgent_printTraceIdrefAttribute(tps, current);
    current=jvmpiAgent_appendElementEnd(NULL, 0, current, tps);
	jvmpiAgent_print(tps, tps->buffer, current);
  }
 }
}


/** PRINT_OBJ_FREE_ELEMENT  ************************************************
  * Handles the output of OBJ_FREE.
  */
void
jvmpiAgent_printObjFreeElement(ThreadLocalStorage *tps,
							   HashEntry *objectHashEntry)
{
 HashEntry *classHashEntry=OBJECT_ENTRY(objectHashEntry)->classHashEntry;

 if (!_jvmpiAgent_suspendIO && classHashEntry && (_jvmpiAgent_Options.gc != GcNone))
  {

	if(_jvmpiAgent_Options.jinsightFormat)
	{
#ifdef BINARY_TRACE
	  unsigned short numBytes = BINARYTRACE_printObjectFree(tps->buffer, objectHashEntry);
	  jvmpiAgent_print(tps, tps->buffer, numBytes);
#endif /* BINARY_TRACE */
	}
	else
	{
	  unsigned short current=0;

      jvmpiAgent_outputClassDeclaration(classHashEntry, tps);

      current=jvmpiAgent_insertEmptyEventHeader(tps->env, tps, OBJ_FREE_ELEMENT, STRLEN_OBJ_FREE_ELEMENT);
      /* Get the timestamp information if necessary */
      if (_jvmpiAgent_Options.timestamp)
	  {
        current=jvmpiAgent_appendCurrentTimeStamp(tps->buffer, current);
	  }
      if (jvmpiAgent_isPrintStaticId())
	  {
        current=jvmpiAgent_appendIntegerAttribute(STATIC_OBJ_IDREF_ATTRIBUTE, STRLEN_STATIC_OBJ_IDREF_ATTRIBUTE, current, OBJECT_ENTRY(objectHashEntry)->static_id, tps->buffer);
	  }
      if (jvmpiAgent_isPrintObjId())
	  {
        current=jvmpiAgent_appendIntegerAttribute(OBJ_IDREF_ATTRIBUTE, STRLEN_OBJ_IDREF_ATTRIBUTE, current, (jint)((ObjectHashKey*)objectHashEntry->id)->id, tps->buffer);
	  }
      if (_jvmpiAgent_Options.contextFlow)
	  {
        /*## Values of context flow information not implemented yet. */
        current=jvmpiAgent_appendIntegerAttribute(SEQUENCE_COUNTER_ATTRIBUTE, STRLEN_SEQUENCE_COUNTER_ATTRIBUTE, current, 0, tps->buffer);
        current=jvmpiAgent_appendStringAttribute(CONTEXT_DATA_ATTRIBUTE, STRLEN_CONTEXT_DATA_ATTRIBUTE, current, "##not implemented yet##", tps);
	  }

      /*##MW There is a race condition between the increment and the print that must be fixed */
      jvmpiAgent_incrementSegmentedValue(&_jvmpiAgent_collation, 0);
      current=jvmpiAgent_printCollationValueAttribute(tps->buffer, current, &_jvmpiAgent_collation);

      current=jvmpiAgent_printTraceIdrefAttribute(tps, current);
      current=jvmpiAgent_appendElementEnd(NULL, 0, current, tps);
      jvmpiAgent_print(tps, tps->buffer, current);
	}
  }
}


void jvmpiAgent_printJvmInitDoneElement(JVMPI_Event *event)
{
  if(_jvmpiAgent_Options.jinsightFormat && !_jvmpiAgent_Options.standalone) {
    return;
  }

 if (!_jvmpiAgent_suspendIO)
 {
  ThreadPrivateStorage *tps = jvmpiAgent_getThreadLocalStorage(event->env_id);
  unsigned short current=0;

  current=jvmpiAgent_insertEmptyEventHeader(event->env_id, tps, JVM_INIT_DONE_ELEMENT, STRLEN_JVM_INIT_DONE_ELEMENT);
  /* Get the timestamp information if necessary */
  if(_jvmpiAgent_Options.timestamp)
  {
   current=jvmpiAgent_appendCurrentTimeStamp(tps->buffer, current);
  }

  /*##MW There is a race condition between the increment and the print that must be fixed */
  jvmpiAgent_incrementSegmentedValue(&_jvmpiAgent_collation, 0);
  current=jvmpiAgent_printCollationValueAttribute(tps->buffer, current, &_jvmpiAgent_collation);

  current=jvmpiAgent_printTraceIdrefAttribute(tps, current);
  current=jvmpiAgent_appendElementEnd(NULL, 0, current, tps);
  jvmpiAgent_print(tps, tps->buffer, current);
 }

  if(_jvmpiAgent_Options.jinsightFormat && _jvmpiAgent_Options.standalone) {
#ifdef BINARY_TRACE
    unsigned short numBytes = BINARYTRACE_printEndOfXMLHeader(tps->buffer);
    jvmpiAgent_print(tps, tps->buffer, numBytes);
#endif /* BINARY_TRACE */
  }
}


void jvmpiAgent_printGcStartElement(JVMPI_Event *event)
{
 if (!_jvmpiAgent_suspendIO && _jvmpiAgent_Options.gc != GcNone)
 {
  ThreadPrivateStorage *tps = jvmpiAgent_getThreadLocalStorage(event->env_id);
  unsigned short current=0;
  if(_jvmpiAgent_Options.jinsightFormat)
  {
#ifdef BINARY_TRACE
    unsigned short numBytes = BINARYTRACE_printGcStart(tps->buffer);
    jvmpiAgent_print(tps, tps->buffer, numBytes);
#endif /* BINARY_TRACE */
  }
  else
  {
	 current=jvmpiAgent_insertEmptyEventHeader(event->env_id, tps, GC_START_ELEMENT, STRLEN_GC_START_ELEMENT);
     /* Get the timestamp information if necessary */
     if(_jvmpiAgent_Options.timestamp)
	 {
       current=jvmpiAgent_appendCurrentTimeStamp(tps->buffer, current);
	 }

     /*##MW There is a race condition between the increment and the print that must be fixed */
     jvmpiAgent_incrementSegmentedValue(&_jvmpiAgent_collation, 0);
     current=jvmpiAgent_printCollationValueAttribute(tps->buffer, current, &_jvmpiAgent_collation);

     current=jvmpiAgent_printTraceIdrefAttribute(tps, current);
     current=jvmpiAgent_appendElementEnd(NULL, 0, current, tps);
     jvmpiAgent_print(tps, tps->buffer, current);
  }
 }
}


void jvmpiAgent_printGcFinishElement(JVMPI_Event *event)
{
 if (!_jvmpiAgent_suspendIO && _jvmpiAgent_Options.gc != GcNone)
 {
  ThreadPrivateStorage *tps = jvmpiAgent_getThreadLocalStorage(event->env_id);
  unsigned short current=0;

  if(_jvmpiAgent_Options.jinsightFormat)
  {
#ifdef BINARY_TRACE
    unsigned short numBytes = BINARYTRACE_printGcFinish(tps->buffer);
    jvmpiAgent_print(tps, tps->buffer, numBytes);
#endif /* BINARY_TRACE */
  }
  else
  {
	 current=jvmpiAgent_insertEmptyEventHeader(event->env_id, tps, GC_FINISH_ELEMENT, STRLEN_GC_FINISH_ELEMENT);
     /* Get the timestamp information if necessary */
     if(_jvmpiAgent_Options.timestamp)
	 {
       current=jvmpiAgent_appendCurrentTimeStamp(tps->buffer, current);
	 }
#ifdef __OS400__
     current=jvmpiAgent_appendInteger64Attribute(USED_OBJECTS_ATTRIBUTE, STRLEN_USED_OBJECTS_ATTRIBUTE, current, (event->u.gc_info.used_objects).unsigned_ll, tps->buffer);
     current=jvmpiAgent_appendInteger64Attribute(USED_OBJECT_SPACE_ATTRIBUTE, STRLEN_USED_OBJECT_SPACE_ATTRIBUTE, current, (event->u.gc_info.used_object_space).unsigned_ll, tps->buffer);
     current=jvmpiAgent_appendInteger64Attribute(TOTAL_OBJECT_SPACE_ATTRIBUTE, STRLEN_TOTAL_OBJECT_SPACE_ATTRIBUTE, current, (event->u.gc_info.total_object_space).unsigned_ll, tps->buffer);
#else
     current=jvmpiAgent_appendInteger64Attribute(USED_OBJECTS_ATTRIBUTE, STRLEN_USED_OBJECTS_ATTRIBUTE, current, event->u.gc_info.used_objects, tps->buffer);
     current=jvmpiAgent_appendInteger64Attribute(USED_OBJECT_SPACE_ATTRIBUTE, STRLEN_USED_OBJECT_SPACE_ATTRIBUTE, current, event->u.gc_info.used_object_space, tps->buffer);
     current=jvmpiAgent_appendInteger64Attribute(TOTAL_OBJECT_SPACE_ATTRIBUTE, STRLEN_TOTAL_OBJECT_SPACE_ATTRIBUTE, current, event->u.gc_info.total_object_space, tps->buffer);
#endif

     /*##MW There is a race condition between the increment and the print that must be fixed */
     jvmpiAgent_incrementSegmentedValue(&_jvmpiAgent_collation, 0);
     current=jvmpiAgent_printCollationValueAttribute(tps->buffer, current, &_jvmpiAgent_collation);

     current=jvmpiAgent_printTraceIdrefAttribute(tps, current);
     current=jvmpiAgent_appendElementEnd(NULL, 0, current, tps);
     jvmpiAgent_print(tps, tps->buffer, current);
  }
 }
}


/** PRINT_GC_ROOT_ELEMEMT  *******************************************************
 *
 */
void
jvmpiAgent_printGcRootElement(JVMPI_Event *event,
							  unsigned long id,
							  char* type)
{
	if(!_jvmpiAgent_suspendIO && _jvmpiAgent_Options.gc != GcNone)
	{
		unsigned short current=0;
		ThreadPrivateStorage *tps = jvmpiAgent_getThreadLocalStorage(event->env_id);
		
		if(_jvmpiAgent_Options.jinsightFormat)
		{
#ifdef BINARY_TRACE
			/* BINARY_TRACE */
#endif
		}
		else
		{
			current=jvmpiAgent_insertElementStart(GC_ROOT_ELEMENT, STRLEN_GC_ROOT_ELEMENT, tps);

			if(strcmp(type, "STICKY_CLASS") == 0)
			{
				current = jvmpiAgent_appendIntegerAttribute(STATIC_CLASS_IDREF_ATTRIBUTE, STRLEN_STATIC_CLASS_IDREF_ATTRIBUTE, current, id, tps->buffer);
			}
/*
			else if(strcmp(type, "THREAD_BLOCK") == 0)
			{
				current = jvmpiAgent_appendIntegerAttribute(STATIC_THREAD_IDREF_ATTRIBUTE, STRLEN_STATIC_THREAD_IDREF_ATTRIBUTE, current, id, tps->buffer);
			}
*/
			else
			{
				current = jvmpiAgent_appendIntegerAttribute(STATIC_OBJ_IDREF_ATTRIBUTE, STRLEN_STATIC_OBJ_IDREF_ATTRIBUTE, current, id, tps->buffer);
			}

			current = jvmpiAgent_appendStringAttribute(GC_ROOT_TYPE_ATTRIBUTE, STRLEN_GC_ROOT_TYPE_ATTRIBUTE, current, type, tps);

			/* Finish up */
			current = jvmpiAgent_appendElementEnd(NULL, 0, current, tps);
			jvmpiAgent_print(tps, tps->buffer, current);
		}
	}
}



unsigned short
jvmpiAgent_printThreadOwnerAttribute(char *buffer, unsigned short current,
									 unsigned long thread_owner)
{
	return jvmpiAgent_appendUnsignedLongAttribute(THREAD_OWNER_ATTRIBUTE,
						      STRLEN_THREAD_OWNER_ATTRIBUTE,
						      current,thread_owner, buffer);
}

unsigned short
jvmpiAgent_printTimeoutAttribute(char *buffer, unsigned short current,
								 Uint64 timeout)
{

	return jvmpiAgent_appendInteger64Attribute(TIMEOUT_ATTRIBUTE,
						      STRLEN_TIMEOUT_ATTRIBUTE,current,timeout,buffer);
}


/** PRINT_MONITOR_WAIT_ELEMENT  *****************************************************
  *
  * Print the <monWait> element to the trace indicating JVMPI_EVENT_MONITOR_WAIT occurred.
  *
  * args -
  *		objectHashEntry - the hash entry corresponding to the monitor object
  *		event - the MONITOR_WAIT event as reported by JVMPI
  *		timestamp - when the MONITOR_WAIT event occurred
  *     isThreadSleep - 0 indicates regular monitor, 1 indicates wait occurred
  *                     within Thread.sleep()
  */
void
jvmpiAgent_printMonitorWaitElement(HashEntry *objectHashEntry, JVMPI_Event *event,
								   timestamp_t timestamp, int isThreadSleep)
{

	/* only print element if io is not suspended */
	if (!_jvmpiAgent_suspendIO) {
		
		unsigned short current=0;
		ThreadPrivateStorage *tps;
		
		tps = jvmpiAgent_getThreadLocalStorage(event->env_id);
		
		if(!timestamp) {
			jvmpiAgent_getCurrentTime(&timestamp);
		}

		/* does there need to be any code handling binary trace/jinsight format?
   		 (not dealt with for now) */

		current=jvmpiAgent_insertEmptyEventHeader(event->env_id, tps, MONITOR_WAIT_ELEMENT,
			STRLEN_MONITOR_WAIT_ELEMENT);

		if(_jvmpiAgent_Options.timestamp)
		{
			current=jvmpiAgent_appendTimestamp(tps->buffer, current, timestamp);
		}


		/* Print the object identifier. Object identifier is -1 if in Thread.sleep() */

		if(jvmpiAgent_isPrintStaticId())
		{
			current=jvmpiAgent_appendIntegerAttribute(STATIC_OBJ_IDREF_ATTRIBUTE,
				STRLEN_STATIC_OBJ_IDREF_ATTRIBUTE, current,
				(isThreadSleep == 0 ? OBJECT_ENTRY(objectHashEntry)->static_id : -1),
				tps->buffer);
		}

		if(jvmpiAgent_isPrintObjId())
		{
			current=jvmpiAgent_appendIntegerAttribute(OBJ_IDREF_ATTRIBUTE,
				STRLEN_OBJ_IDREF_ATTRIBUTE, current,
				(isThreadSleep == 0 ? (jint)((ObjectHashKey*)objectHashEntry->id)->id : -1),
				tps->buffer);

		}


		/* print the timeout attribute */
#ifdef __OS400__
		current = jvmpiAgent_printTimeoutAttribute(tps->buffer,current,
			(event->u.monitor_wait.timeout).unsigned_ll);
#else
		current = jvmpiAgent_printTimeoutAttribute(tps->buffer,current,
			event->u.monitor_wait.timeout);
#endif

			
		/* The collation value */


		/*##MW There is a race condition between the increment and the print
		that must be fixed */

		jvmpiAgent_incrementSegmentedValue(&_jvmpiAgent_collation, 0);
		current=jvmpiAgent_printCollationValueAttribute(tps->buffer, current,
			&_jvmpiAgent_collation);

		/* The trace Id */

		current=jvmpiAgent_printTraceIdrefAttribute(tps, current);

		/* Finish up */

		current=jvmpiAgent_appendElementEnd(NULL, 0, current, tps);
		jvmpiAgent_print(tps, tps->buffer, current);
	}

}


/** PRINT_MONITOR_WAITED_ELEMENT  *****************************************************
  *
  * Print the <monWaited> element to the trace indicating JVMPI_EVENT_MONITOR_WAITED occurred.
  *
  * args -
  *		objectHashEntry - hash entry corresponding to the monitor object
  *		event - the MONITOR_WAITED event as reported by JVMPI
  *		timestamp - when the MONITOR_WAITED event occurred
  *     isThreadSleep - 0 indicates regular monitor, 1 indicates wait occurred
  *                     within Thread.sleep()
  */
void
jvmpiAgent_printMonitorWaitedElement(HashEntry* objectHashEntry, JVMPI_Event *event,
								   timestamp_t timestamp, int isThreadSleep)
{

	/* only print element if io is not suspended */
	if (!_jvmpiAgent_suspendIO) {
		
		unsigned short current=0;
		ThreadPrivateStorage *tps;
		
		tps = jvmpiAgent_getThreadLocalStorage(event->env_id);
		
		if(!timestamp) {
			jvmpiAgent_getCurrentTime(&timestamp);
		}

		/* does there need to be any code handling binary trace/jinsight format?
		   (not dealt with for now) */

		current=jvmpiAgent_insertEmptyEventHeader(event->env_id, tps, MONITOR_WAITED_ELEMENT,
			STRLEN_MONITOR_WAITED_ELEMENT);

		if(_jvmpiAgent_Options.timestamp)
		{
			current=jvmpiAgent_appendTimestamp(tps->buffer, current, timestamp);
		}


		/* Print the object identifier. Object identifier is -1 if in Thread.sleep() */

		if(jvmpiAgent_isPrintStaticId())
		{
			current=jvmpiAgent_appendIntegerAttribute(STATIC_OBJ_IDREF_ATTRIBUTE,
				STRLEN_STATIC_OBJ_IDREF_ATTRIBUTE, current,
				(isThreadSleep == 0 ? OBJECT_ENTRY(objectHashEntry)->static_id : -1),
				tps->buffer);
		}

		if(jvmpiAgent_isPrintObjId())
		{
			current=jvmpiAgent_appendIntegerAttribute(OBJ_IDREF_ATTRIBUTE,
				STRLEN_OBJ_IDREF_ATTRIBUTE, current,
				(isThreadSleep == 0 ? (jint)((ObjectHashKey *)objectHashEntry->id)->id : -1),
				tps->buffer);

		}

		/* print the timeout attribute */
#ifdef __OS400__
		current = jvmpiAgent_printTimeoutAttribute(tps->buffer,current,
			(event->u.monitor_wait.timeout).unsigned_ll);
#else
		current = jvmpiAgent_printTimeoutAttribute(tps->buffer,current,
			event->u.monitor_wait.timeout);
#endif

		/* The collation value */


		/*##MW There is a race condition between the increment and the print
		that must be fixed */

		jvmpiAgent_incrementSegmentedValue(&_jvmpiAgent_collation, 0);
		current=jvmpiAgent_printCollationValueAttribute(tps->buffer, current,
			&_jvmpiAgent_collation);

		/* The trace Id */

		current=jvmpiAgent_printTraceIdrefAttribute(tps, current);

		/* Finish up */

		current=jvmpiAgent_appendElementEnd(NULL, 0, current, tps);
		jvmpiAgent_print(tps, tps->buffer, current);
	}
}

/** PRINT_MONITOR_STILL_OWNED_ELEMENT  ************************************************
  *
  * Print the <monStillOwned> element to the trace indicating
  * a thread is still owning a monitor at the moment we checked
  * It is potentially sent on JVMPI_EVENT_MONITOR_CONTENDED_ENTER
  * just before a <monContendedEnter> element where the
  * thread is the contended thread
  *
  * args -
  *		objectHashEntry - the hash entry corresponding to the monitor object
  *		event - the JVMPI_EVENT_MONITOR_CONTENDED_ENTER event as reported by JVMPI
  */
void
jvmpiAgent_printMonitorStillOwnedElement(HashEntry *objectHashEntry, JVMPI_Event *event)

{
	/* only print element if io is not suspended */
	if (!_jvmpiAgent_suspendIO) {
		
		unsigned short current=0;
		ThreadPrivateStorage *tps;
		
		tps = jvmpiAgent_getThreadLocalStorage(event->env_id);
		
		current=jvmpiAgent_insertEmptyEventHeader(event->env_id, tps,
			MONITOR_STILL_OWNED_EVENT, STRLEN_MONITOR_STILL_OWNED_EVENT);

		/* Print the object identifier. */

		if(jvmpiAgent_isPrintStaticId())
		{
			current=jvmpiAgent_appendIntegerAttribute(STATIC_OBJ_IDREF_ATTRIBUTE,
				STRLEN_STATIC_OBJ_IDREF_ATTRIBUTE, current,
				OBJECT_ENTRY(objectHashEntry)->static_id,
				tps->buffer);
		}

		if(jvmpiAgent_isPrintObjId())
		{
			current=jvmpiAgent_appendIntegerAttribute(OBJ_IDREF_ATTRIBUTE,
				STRLEN_OBJ_IDREF_ATTRIBUTE, current,
				(jint)((ObjectHashKey*)objectHashEntry->id)->id, tps->buffer);

		}


		/* The collation value */


		/*##MW There is a race condition between the increment and the print
		that must be fixed */

		jvmpiAgent_incrementSegmentedValue(&_jvmpiAgent_collation, 0);
		current=jvmpiAgent_printCollationValueAttribute(tps->buffer, current,
			&_jvmpiAgent_collation);

		/* The trace Id */

		current=jvmpiAgent_printTraceIdrefAttribute(tps, current);

		/* Finish up */

		current=jvmpiAgent_appendElementEnd(NULL, 0, current, tps);
		jvmpiAgent_print(tps, tps->buffer, current);
	}

}


/** PRINT_MONITOR_CONTENDED_ENTER_ELEMENT  ************************************************
  *
  * Print the <monContendedEnter> element to the trace indicating
  * JVMPI_EVENT_MONITOR_CONTENDED_ENTER occurred.
  *
  * args -
  *		objectHashEntry - the hash entry corresponding to the monitor object
  *		event - the MONITOR_WAITED event as reported by JVMPI
  *		thread_owner - the current thread that owns the monitor object
  *		timestamp - when the MONITOR_WAITED event occurred
  */
void
jvmpiAgent_printMonitorContendedEnterElement(HashEntry *objectHashEntry, JVMPI_Event *event,
							 unsigned long thread_owner, timestamp_t timestamp)

{
	/* only print element if io is not suspended */
	if (!_jvmpiAgent_suspendIO) {
		
		unsigned short current=0;
		ThreadPrivateStorage *tps;
		
		tps = jvmpiAgent_getThreadLocalStorage(event->env_id);
		
		if(!timestamp) {
			jvmpiAgent_getCurrentTime(&timestamp);
		}

		/* does there need to be any code handling binary trace/jinsight format?
		   (not dealt with for now) */

		current=jvmpiAgent_insertEmptyEventHeader(event->env_id, tps,
			MONITOR_CONTENDED_ENTER_ELEMENT, STRLEN_MONITOR_CONTENDED_ENTER_ELEMENT);

		if(_jvmpiAgent_Options.timestamp)
		{
			current=jvmpiAgent_appendTimestamp(tps->buffer, current, timestamp);
		}


		/* Print the object identifier. */

		if(jvmpiAgent_isPrintStaticId())
		{
			current=jvmpiAgent_appendIntegerAttribute(STATIC_OBJ_IDREF_ATTRIBUTE,
				STRLEN_STATIC_OBJ_IDREF_ATTRIBUTE, current,
				OBJECT_ENTRY(objectHashEntry)->static_id,
				tps->buffer);
		}

		if(jvmpiAgent_isPrintObjId())
		{
			current=jvmpiAgent_appendIntegerAttribute(OBJ_IDREF_ATTRIBUTE,
				STRLEN_OBJ_IDREF_ATTRIBUTE, current,
				(jint)((ObjectHashKey*)objectHashEntry->id)->id, tps->buffer);

		}


		/* print the thread owner attribute */

		current = jvmpiAgent_printThreadOwnerAttribute(tps->buffer,current, thread_owner);
			
		/* The collation value */


		/*##MW There is a race condition between the increment and the print
		that must be fixed */

		jvmpiAgent_incrementSegmentedValue(&_jvmpiAgent_collation, 0);
		current=jvmpiAgent_printCollationValueAttribute(tps->buffer, current,
			&_jvmpiAgent_collation);

		/* The trace Id */

		current=jvmpiAgent_printTraceIdrefAttribute(tps, current);

		/* Finish up */

		current=jvmpiAgent_appendElementEnd(NULL, 0, current, tps);
		jvmpiAgent_print(tps, tps->buffer, current);
	}

}


/** PRINT_MONITOR_CONTENDED_ENTERED_ELEMENT  ************************************************
  *
  * Print the <monContendedEntered> element to the trace indicating
  * JVMPI_EVENT_MONITOR_CONTENDED_ENTERED occurred.
  *
  * args -
  *		objectHashEntry - the hash entry corresponding to the monitor object
  *		event - the MONITOR_WAITED event as reported by JVMPI
  *		timestamp - when the MONITOR_WAITED event occurred
  */
void
jvmpiAgent_printMonitorContendedEnteredElement(HashEntry *objectHashEntry, JVMPI_Event *event,
											   timestamp_t timestamp)
{
	/* only print element if io is not suspended */
	if (!_jvmpiAgent_suspendIO) {
		
		unsigned short current=0;
		ThreadPrivateStorage *tps;
		
		tps = jvmpiAgent_getThreadLocalStorage(event->env_id);
		
		if(!timestamp) {
			jvmpiAgent_getCurrentTime(&timestamp);
		}

		/* does there need to be any code handling binary trace/jinsight format?
		 (not dealt with for now) */

		current=jvmpiAgent_insertEmptyEventHeader(event->env_id, tps,
			MONITOR_CONTENDED_ENTERED_ELEMENT, STRLEN_MONITOR_CONTENDED_ENTERED_ELEMENT);

		if(_jvmpiAgent_Options.timestamp)
		{
			current=jvmpiAgent_appendTimestamp(tps->buffer, current, timestamp);
		}

		/* Print the object identifier. */

		if(jvmpiAgent_isPrintStaticId())
		{
			current=jvmpiAgent_appendIntegerAttribute(STATIC_OBJ_IDREF_ATTRIBUTE,
				STRLEN_STATIC_OBJ_IDREF_ATTRIBUTE, current,
				OBJECT_ENTRY(objectHashEntry)->static_id,
				tps->buffer);
		}

		if(jvmpiAgent_isPrintObjId())
		{
			current=jvmpiAgent_appendIntegerAttribute(OBJ_IDREF_ATTRIBUTE,
				STRLEN_OBJ_IDREF_ATTRIBUTE, current,
				(jint)((ObjectHashKey*)objectHashEntry->id)->id, tps->buffer);

		}


			
		/* The collation value */


		/*##MW There is a race condition between the increment and the print
		that must be fixed */

		jvmpiAgent_incrementSegmentedValue(&_jvmpiAgent_collation, 0);
		current=jvmpiAgent_printCollationValueAttribute(tps->buffer, current,
			&_jvmpiAgent_collation);

		/* The trace Id */

		current=jvmpiAgent_printTraceIdrefAttribute(tps, current);

		/* Finish up */

		current=jvmpiAgent_appendElementEnd(NULL, 0, current, tps);
		jvmpiAgent_print(tps, tps->buffer, current);
	}
}





/** PRINT_OBJ_ALLOC_ELEMENT  *****************************************************
  *
  */
void
jvmpiAgent_printObjAllocElement(HashEntry *objectHashEntry,
								JNIEnv *env_id,
                                timestamp_t timestamp)
{
 if (!_jvmpiAgent_suspendIO)
 {
  unsigned short current=0;
  ThreadPrivateStorage *tps = jvmpiAgent_getThreadLocalStorage(env_id);
  HashEntry *classHashEntry = OBJECT_ENTRY(objectHashEntry)->classHashEntry;

  objectHashEntry->printed = 1;

  if(!timestamp) {
      jvmpiAgent_getCurrentTime(&timestamp);
  }


  if(_jvmpiAgent_Options.jinsightFormat)
  {
#ifdef BINARY_TRACE
    unsigned short numBytes = BINARYTRACE_printObjectAllocation(tps->buffer,
								objectHashEntry,
								classHashEntry);
    jvmpiAgent_print(tps, tps->buffer, numBytes);
#endif /* BINARY_TRACE */
  }
  else
  {

	/* Ensure our class declaration has been printed */
    jvmpiAgent_outputClassDeclaration(OBJECT_ENTRY(objectHashEntry)->classHashEntry, tps);

    current=jvmpiAgent_insertEmptyEventHeader(env_id, tps, OBJ_ALLOC_ELEMENT, STRLEN_OBJ_ALLOC_ELEMENT);

    if(_jvmpiAgent_Options.timestamp)
	{
      current=jvmpiAgent_appendTimestamp(tps->buffer, current, timestamp);
	}

    /* Print the object identifier as well as the class identifier */
    if(jvmpiAgent_isPrintStaticId())
	{
      current=jvmpiAgent_appendIntegerAttribute(STATIC_OBJ_ID_ATTRIBUTE, STRLEN_STATIC_OBJ_ID_ATTRIBUTE, current, OBJECT_ENTRY(objectHashEntry)->static_id, tps->buffer);
      current=jvmpiAgent_appendIntegerAttribute(STATIC_CLASS_IDREF_ATTRIBUTE, STRLEN_STATIC_CLASS_IDREF_ATTRIBUTE, current, (jint)(classHashEntry ? CLASS_ENTRY(classHashEntry)->static_id : 0), tps->buffer);
	}
    if(jvmpiAgent_isPrintObjId())
	{
      current=jvmpiAgent_appendIntegerAttribute(OBJ_ID_ATTRIBUTE, STRLEN_OBJ_ID_ATTRIBUTE, current, (jint)((ObjectHashKey*)objectHashEntry->id)->id, tps->buffer);
      current=jvmpiAgent_appendIntegerAttribute(CLASS_IDREF_ATTRIBUTE, STRLEN_CLASS_IDREF_ATTRIBUTE, current, (jint)(classHashEntry ? ((ClassHashKey*)classHashEntry->id)->id : 0), tps->buffer);
	}


    if(_jvmpiAgent_Options.objAllocIsArray)
	{
      current=jvmpiAgent_appendIntegerAttribute(IS_ARRAY_ATTRIBUTE, STRLEN_IS_ARRAY_ATTRIBUTE, current, OBJECT_ENTRY(objectHashEntry)->is_array, tps->buffer);
	}

    /* Print the size of this object */
#ifdef _LP64
    current=jvmpiAgent_appendLongAttribute(SIZE_ATTRIBUTE, STRLEN_SIZE_ATTRIBUTE, current, OBJECT_ENTRY(objectHashEntry)->size, tps->buffer); /*fix 89008*/
#else
    current=jvmpiAgent_appendIntegerAttribute(SIZE_ATTRIBUTE, STRLEN_SIZE_ATTRIBUTE, current, OBJECT_ENTRY(objectHashEntry)->size, tps->buffer);
#endif

    /* The collation value */
    current=jvmpiAgent_printCollationValueAttribute(tps->buffer, current, &OBJECT_ENTRY(objectHashEntry)->collation);

    /* The trace Id */
    current=jvmpiAgent_printTraceIdrefAttribute(tps, current);

    /* Finish up */
    current=jvmpiAgent_appendElementEnd(NULL, 0, current, tps);
    jvmpiAgent_print(tps, tps->buffer, current);
  }
 }
}

/** PRINT_CLASS_UNLOAD_ELEMENT  ********************************************
  *
  */
void
jvmpiAgent_printClassUnloadElement(JVMPI_Event *event,
								   ThreadLocalStorage *tps,
								   HashEntry *classHashEntry)
{
 if (!_jvmpiAgent_suspendIO && CLASS_ENTRY(classHashEntry)->traceFlag && (_jvmpiAgent_Options.gc != GcNone))
 {
	 if(_jvmpiAgent_Options.jinsightFormat)
	 {
#ifdef BINARY_TRACE
	   unsigned short numBytes = BINARYTRACE_printClassUnload(tps->buffer, classHashEntry);
	   jvmpiAgent_print(tps, tps->buffer, numBytes);
#endif /* BINARY_TRACE */
	 }
	 else
	 {
	    unsigned short current=0;
        current=jvmpiAgent_insertEmptyEventHeader(event->env_id, tps, CLASS_UNLOAD_ELEMENT, STRLEN_CLASS_UNLOAD_ELEMENT);
        if(jvmpiAgent_isPrintObjId())
		{
          current=jvmpiAgent_appendIntegerAttribute(CLASS_IDREF_ATTRIBUTE, STRLEN_CLASS_IDREF_ATTRIBUTE, current, (jint)(event->u.class_unload.class_id), tps->buffer);
		}
        if(jvmpiAgent_isPrintStaticId())
		{
           current=jvmpiAgent_appendIntegerAttribute(STATIC_CLASS_IDREF_ATTRIBUTE, STRLEN_STATIC_CLASS_IDREF_ATTRIBUTE, current, (jint)(CLASS_ENTRY(classHashEntry)->static_id), tps->buffer);
		}
        /* Get the timestamp information if necessary */
        if(_jvmpiAgent_Options.timestamp)
		{
          current=jvmpiAgent_appendCurrentTimeStamp(tps->buffer, current);
		}

        /*##MW There is a race condition between the increment and the print that must be fixed */
        jvmpiAgent_incrementSegmentedValue(&_jvmpiAgent_collation, 0);
        current=jvmpiAgent_printCollationValueAttribute(tps->buffer, current, &_jvmpiAgent_collation);

        current=jvmpiAgent_printTraceIdrefAttribute(tps, current);
        current=jvmpiAgent_appendElementEnd(NULL, 0, current, tps);
        jvmpiAgent_print(tps, tps->buffer, current);
	 }
 }
}

/** PRINT_OBJ_MOVE_ELEMENT  ************************************************
  * Handles the output of OBJ_MOVE.
  */
void jvmpiAgent_printObjMoveElement(JVMPI_Event *event,
									HashEntry *objectHashEntry)
{
 HashEntry *classHashEntry = OBJECT_ENTRY(objectHashEntry)->classHashEntry;
 if (!_jvmpiAgent_suspendIO && classHashEntry)
 {
  ThreadPrivateStorage *tps = jvmpiAgent_getThreadLocalStorage(event->env_id);
  unsigned short current=0;

  jvmpiAgent_outputClassDeclaration(classHashEntry, tps);

  current=jvmpiAgent_insertEmptyEventHeader(event->env_id, tps, OBJ_MOVE_ELEMENT, STRLEN_OBJ_MOVE_ELEMENT);
  /* Get the timestamp information if necessary */
  if(_jvmpiAgent_Options.timestamp)
  {
   current=jvmpiAgent_appendCurrentTimeStamp(tps->buffer, current);
  }
  if (jvmpiAgent_isPrintStaticId())
  {
   current=jvmpiAgent_appendIntegerAttribute(STATIC_OBJ_IDREF_ATTRIBUTE, STRLEN_STATIC_OBJ_IDREF_ATTRIBUTE, current, OBJECT_ENTRY(objectHashEntry)->static_id, tps->buffer);
  }
  if (jvmpiAgent_isPrintObjId())
  {
   current=jvmpiAgent_appendIntegerAttribute(OBJ_IDREF_ATTRIBUTE, STRLEN_OBJ_IDREF_ATTRIBUTE, current, (jint)(event->u.obj_move.obj_id), tps->buffer);
  }
  if (jvmpiAgent_isPrintObjId())
  {
   current=jvmpiAgent_appendIntegerAttribute(NEW_OBJ_ID_ATTRIBUTE, STRLEN_NEW_OBJ_ID_ATTRIBUTE, current, (jint)(event->u.obj_move.new_obj_id), tps->buffer);
  }

  /*##MW There is a race condition between the increment and the print that must be fixed */
  jvmpiAgent_incrementSegmentedValue(&_jvmpiAgent_collation, 0);
  current=jvmpiAgent_printCollationValueAttribute(tps->buffer, current, &_jvmpiAgent_collation);

  current=jvmpiAgent_printTraceIdrefAttribute(tps, current);
  current=jvmpiAgent_appendElementEnd(NULL, 0, current, tps);
  jvmpiAgent_print(tps, tps->buffer, current);
 }
}


/** PRINT_THREAD_END_ELEMENT  **********************************************
  */
void jvmpiAgent_printThreadEndElement(JNIEnv *env_id,
									  ThreadLocalStorage *tps)
{
 if (!_jvmpiAgent_suspendIO)
 {
	unsigned short current=0;
	
	if(_jvmpiAgent_Options.jinsightFormat)
	{
#ifdef BINARY_TRACE
	  unsigned short numBytes = BINARYTRACE_printThreadEnd(tps->buffer, tps);
	  jvmpiAgent_print(tps, tps->buffer, numBytes);
#endif /* BINARY_TRACE */
	 }
	 else
	 {
	   current=jvmpiAgent_insertEmptyEventHeader(env_id, tps, THREAD_END_ELEMENT, STRLEN_THREAD_END_ELEMENT);
	   /* Get the timestamp information if necessary */
	   if(_jvmpiAgent_Options.timestamp)
	   {
	     current=jvmpiAgent_appendCurrentTimeStamp(tps->buffer, current);
	   }

	   /*##MW There is a race condition between the increment and the print that must be fixed */
	   jvmpiAgent_incrementSegmentedValue(&_jvmpiAgent_collation, 0);
	   current=jvmpiAgent_printCollationValueAttribute(tps->buffer, current, &_jvmpiAgent_collation);

	   current=jvmpiAgent_printTraceIdrefAttribute(tps, current);
	   current=jvmpiAgent_appendElementEnd(NULL, 0, current, tps);
	   jvmpiAgent_print(tps, tps->buffer, current);
	
	 }
 }
}


/** PRINT_METHOD_EXIT_EVENT  ***********************************************
  * Prints the METHOD_EXIT, METHOD_RETURN element
  */
void
jvmpiAgent_printMethodExitElement(JVMPI_Event *event,
								  ThreadLocalStorage *tps,
								  HashEntry *methodHashEntry,
				  timestamp_t timestamp, 
				  timestamp_t cpu_timestamp)
{
 unsigned short current=0;
 jobjectID object_id = 0;   
 jint static_id = 0;
 HashEntry *objectHashEntry = jvmpiAgent_Peek(tps, 0)->objectHashEntry;
 
 if(_jvmpiAgent_Options.jinsightFormat) {
#ifdef BINARY_TRACE
   unsigned short numBytes = BINARYTRACE_printMethodExit(tps->buffer, tps,
							 timeJustAfterGotControl);
   jvmpiAgent_print(tps, tps->buffer, numBytes);
#endif /* BINARY_TRACE */
   return;
 }

  /* Object information will only be there if we are in FULL trace mode */
 if (objectHashEntry)
 {
  object_id = ((ObjectHashKey*)objectHashEntry->id)->id;
  static_id = OBJECT_ENTRY(objectHashEntry)->static_id ;
 }
 assert(event);
 assert(methodHashEntry);
 assert(tps);


 if (object_id && jvmpiAgent_isPrintStaticId())
 {
  HashEntry *objectHashEntry = 0;
  objectHashEntry = jvmpiAgent_FindObjectSymbolWithAllocate(object_id, event->env_id);
 }

 /* RKD:  We don't emit methidCall events any more.  So remove the methodreturn peer.
 current=jvmpiAgent_insertEmptyEventHeader(event->env_id, tps, CLASS_ENTRY(METHOD_ENTRY(methodHashEntry)->classHashEntry)->traceFlag ? METHOD_EXIT_ELEMENT : METHOD_RETURN_ELEMENT,
 (unsigned short)(CLASS_ENTRY(METHOD_ENTRY(methodHashEntry)->classHashEntry)->traceFlag ? STRLEN_METHOD_EXIT_ELEMENT : STRLEN_METHOD_RETURN_ELEMENT));
 */
  current=jvmpiAgent_insertEmptyEventHeader(event->env_id, tps, METHOD_EXIT_ELEMENT, STRLEN_METHOD_EXIT_ELEMENT);


 if(jvmpiAgent_isPrintStaticId())
 {
   current=jvmpiAgent_appendIntegerAttribute(STATIC_METHOD_IDREF_ATTRIBUTE, STRLEN_STATIC_METHOD_IDREF_ATTRIBUTE, current, (jint)(METHOD_ENTRY(methodHashEntry)->static_id), tps->buffer);
 }
 if(jvmpiAgent_isPrintMethodId())
 {
	current=jvmpiAgent_appendIntegerAttribute(METHOD_IDREF_ATTRIBUTE, STRLEN_METHOD_IDREF_ATTRIBUTE, current, (jint)(METHOD_ENTRY(methodHashEntry)->methodData.method_id), tps->buffer);
 }



 if(object_id && jvmpiAgent_isPrintObjId())
 {
  current=jvmpiAgent_appendIntegerAttribute(OBJ_IDREF_ATTRIBUTE, STRLEN_OBJ_IDREF_ATTRIBUTE, current, (jint)object_id, tps->buffer);
  current=jvmpiAgent_appendIntegerAttribute(CLASS_IDREF_ATTRIBUTE, STRLEN_CLASS_IDREF_ATTRIBUTE, current,(jint)((ClassHashKey*) ((MethodEntry *)methodHashEntry->entry)->classHashEntry->id)->id, tps->buffer);
 }
 if (object_id && jvmpiAgent_isPrintStaticId())
 {
  if (objectHashEntry)
  {
   current=jvmpiAgent_appendIntegerAttribute(STATIC_OBJ_IDREF_ATTRIBUTE, STRLEN_STATIC_OBJ_IDREF_ATTRIBUTE, current, ((ObjectEntry*)objectHashEntry->entry)->static_id, tps->buffer);
  }
 }
 if(jvmpiAgent_isPrintStaticId())
 {
  current=jvmpiAgent_appendIntegerAttribute(STATIC_CLASS_IDREF_ATTRIBUTE, STRLEN_STATIC_CLASS_IDREF_ATTRIBUTE, current, CLASS_ENTRY(METHOD_ENTRY(methodHashEntry)->classHashEntry)->static_id, tps->buffer);
 }
 if(_jvmpiAgent_Options.cpuTime) {
  Uint64 cpu_exit_overhead, cpu_overheadSoFar, cpu_totalInvocationOverhead, cpu_cumulativeTime;
   timestamp_t cpuNow;

   /* load the running sum of all overhead so far */
   cpu_overheadSoFar = tps->stackEntry[tps->tos].cumulative_cpu_overhead;

   /* determine the cumulative method time spent in this method */ 
   cpu_cumulativeTime = TIMESTAMP_SUB(cpu_timestamp,tps->stackEntry[tps->tos].cpuTime); 

   /* subtract the overhead  */ 
   cpu_cumulativeTime = TIMESTAMP_SUB(cpu_cumulativeTime,cpu_overheadSoFar); 
   
   /* print the CPU cumulative time */
   current=jvmpiAgent_appendThreadCPUTime(tps->buffer, current, cpu_cumulativeTime); 

   /* now we have to add the overhead so far to the 
   overhead in the call one up on the stack  (overhead is cumulative in the call stack) */ 

   /* acquire the timestamp as late as possible; note: anything after
      this will be overhead that is blamed to the invoker, but it's
      the best we can do for now */
   cpuNow = jvmpiAgent_getCurrentThreadCPUTime(); 

    /* determine the current exit overhead */
   cpu_exit_overhead = TIMESTAMP_SUB(cpuNow,cpu_timestamp);

   /* add it to the running sum of all overhead for this invocation */
   cpu_totalInvocationOverhead = cpu_overheadSoFar+cpu_exit_overhead;

   /* now add it to the stack entry one up in the stack */ 
   if (tps->tos > 1) {
	   tps->stackEntry[tps->tos-1].cumulative_cpu_overhead += cpu_totalInvocationOverhead; 
   }
 }
 if(_jvmpiAgent_Options.ticket)
 {
  current=jvmpiAgent_printTicketAttribute(&jvmpiAgent_Peek(tps, 0)->ticket, tps->buffer, current);
 }
 if (_jvmpiAgent_Options.contextFlow)
 {
  /*## Values of context flow information not implemented yet. */
  current=jvmpiAgent_appendIntegerAttribute(SEQUENCE_COUNTER_ATTRIBUTE, STRLEN_SEQUENCE_COUNTER_ATTRIBUTE, current, 0, tps->buffer);
  current=jvmpiAgent_appendStringAttribute(CONTEXT_DATA_ATTRIBUTE, STRLEN_CONTEXT_DATA_ATTRIBUTE, current, "##not implemented yet##", tps);
 }

 /*##MW There is a race condition between the increment and the print that must be fixed */
 jvmpiAgent_incrementSegmentedValue(&_jvmpiAgent_collation, 0);
 current=jvmpiAgent_printCollationValueAttribute(tps->buffer, current, &_jvmpiAgent_collation);

 current=jvmpiAgent_printTraceIdrefAttribute(tps, current);

 /* Print the timestamp (and overhead) information if necessary */
 if(_jvmpiAgent_Options.timestamp)
 {
   Uint64 exit_overhead, overheadSoFar, totalInvocationOverhead;
   timestamp_t now;

   /* load the running sum of all overhead so far */
   overheadSoFar = tps->stackEntry[tps->tos].cumulative_overhead;

   /* acquire the timestamp as late as possible; note: anything after
      this will be overhead that is blamed to the invoker, but it's
      the best we can do for now */
   jvmpiAgent_getCurrentTime(&now);

   /* print the timestamp */
   current=jvmpiAgent_appendTimestamp(tps->buffer, current, now);

   /* determine the current exit overhead */
   exit_overhead = TIMESTAMP_SUB(now,timestamp);

   /* add it to the running sum of all overhead for this invocation */
   totalInvocationOverhead = overheadSoFar+exit_overhead;
   current = jvmpiAgent_appendOverhead(tps->buffer, current, totalInvocationOverhead);
 }

 current=jvmpiAgent_appendElementEnd(NULL, 0, current, tps);
 jvmpiAgent_print(tps, tps->buffer, current);
}


/** PRINT_AG_METHOD_EXIT_ELEMENT **************************preAgg/135437*******
  * 
  * Prints the METHOD_EXIT element
  */
void jvmpiAgent_printAgMethodExitElement(ThreadPrivateStorage * tps, StackFrame * call) {

   unsigned short current=0;
   
   /* Note that tps->env is passed in place of event->env_id passed elsewhere and should be equivalent in the preAgg case. */
   current=jvmpiAgent_insertEmptyEventHeader(tps->env, tps, AG_METHOD_EXIT_ELEMENT, STRLEN_AG_METHOD_EXIT_ELEMENT);
   
   current=jvmpiAgent_appendIntegerAttribute(STATIC_METHOD_IDREF_ATTRIBUTE, STRLEN_STATIC_METHOD_IDREF_ATTRIBUTE, current, 
                                             (jint)(METHOD_ENTRY(call->methodHashEntry)->static_id), tps->buffer);
   
   current=jvmpiAgent_appendElementEnd(NULL, 0, current, tps);
   
   jvmpiAgent_print(tps, tps->buffer, current);
}

/** PRINT_METHODS  **********************************************************
  *  Handles the output of all the METHOD elements and attributes for a class.
  */
void
jvmpiAgent_printMethods(HashEntry **mp,
						int count,
						ThreadPrivateStorage *tps)
{
 if (!_jvmpiAgent_suspendIO && (_jvmpiAgent_Options.stackInfo > StackInfoNone || _jvmpiAgent_Options.methodCounts))
 {
  int i;
  for (i=0; i < count; i++)
  {
	if (METHOD_ENTRY(mp[i])->traceFlag) { 
	   jvmpiAgent_printMethod(METHOD_ENTRY(mp[i]), tps);
	   mp[i]->printed = 1;
	}
  }
 }
}


/** PRINT_FIELDS  ***********************************************************
  * Handles the output of all the STATIC_FIELD or INSTANCE_FIELD elements
  * and attributes for a class.
  */
void jvmpiAgent_printFields(ThreadPrivateStorage *tps,
							PI_Field *fp, int count,
							FieldType_t fieldType)
{
 if (!_jvmpiAgent_suspendIO)
 {
  int i;
  for (i=0; i < count && fp; i++)
  {
   unsigned short current=0;

   if (fieldType == Static)
   {
 	current=jvmpiAgent_insertElementStart(STATIC_FIELD_ELEMENT, STRLEN_STATIC_FIELD_ELEMENT, tps);
   }
   else
   {
	current=jvmpiAgent_insertElementStart(INSTANCE_FIELD_ELEMENT, STRLEN_INSTANCE_FIELD_ELEMENT, tps);
   }
   current=jvmpiAgent_appendStringAttribute(NAME_ATTRIBUTE, STRLEN_NAME_ATTRIBUTE, current, fp->field_name, tps);
   current=jvmpiAgent_appendStringAttribute(SIGNATURE_ATTRIBUTE, STRLEN_SIGNATURE_ATTRIBUTE, current, fp->field_signature, tps);
   current=jvmpiAgent_appendIntegerAttribute(FIELD_ID_ATTRIBUTE, STRLEN_FIELD_ID_ATTRIBUTE, current, fp->fieldId, tps->buffer);
   current=jvmpiAgent_appendElementEnd(NULL, 0, current, tps);
   jvmpiAgent_print(tps, tps->buffer, current);
   fp++; /* Skip to the next method */
  }
 }
}


/** PRINT_CLASS  ****************************************************************
  * Handles the output of the CLASS_LOAD element and attributes
  */
void
jvmpiAgent_printClass(HashEntry *classHashEntry,
					  ThreadPrivateStorage *tps)
{
 unsigned short current=0;
 if (!_jvmpiAgent_suspendIO)
 {

	classHashEntry->printed = 1;


	if(_jvmpiAgent_Options.jinsightFormat)
	{
#ifdef BINARY_TRACE
	  ClassEntry *classEntry = CLASS_ENTRY(classHashEntry);
	  unsigned short numBytes;

	  /* 1. "define" the class, which just defines the class id */
	  numBytes = BINARYTRACE_printClassDefine(tps->buffer, classEntry);
	  jvmpiAgent_print(tps, tps->buffer, numBytes);

	  /* 2. "load" the class, which defines properies of class */
	  numBytes = BINARYTRACE_printClassLoad(tps->buffer, classEntry);
	  jvmpiAgent_print(tps, tps->buffer, numBytes);

	  /* 3. instance fields */
	  BINARYTRACE_printFields(tps, classEntry, classEntry->numInstanceFields,
				  0,
				  classEntry->instances, FALSE);

	  /* 4. static fields */
	  BINARYTRACE_printFields(tps, classEntry, classEntry->numStaticFields,
				  classEntry->numInstanceFields,
				  classEntry->statics, TRUE);
#endif /* BINARY_TRACE */
	}
	else
	{
	  ClassEntry *classEntry = CLASS_ENTRY(classHashEntry);

      current=jvmpiAgent_insertEmptyEventHeader(tps->env, tps,
	    										CLASS_LOAD_ELEMENT,
		    									STRLEN_CLASS_LOAD_ELEMENT);


      current=jvmpiAgent_appendStringAttribute(NAME_ATTRIBUTE, STRLEN_NAME_ATTRIBUTE, current, classEntry->className, tps);
      current=jvmpiAgent_appendStringAttribute(SOURCE_NAME_ATTRIBUTE, STRLEN_SOURCE_NAME_ATTRIBUTE, current, classEntry->sourceName, tps);
      if (_jvmpiAgent_Options.classLoadDetails)
	  {

		/* Show the classloader of this entry (if one has been detected) */
		if (classEntry->classLoaderName && strlen(classEntry->classLoaderName) > 0)
			current = jvmpiAgent_appendStringAttribute(CLASS_LOADER_NAME, STRLEN_CLASS_LOADER_NAME, current, classEntry->classLoaderName, tps);

		if (classEntry->superClassName && strlen(classEntry->superClassName) > 0)
			current=jvmpiAgent_appendStringAttribute(SUPER_CLASS_NAME_ATTRIBUTE, STRLENT_SUPER_CLASS_NAME_ATTRIBUTE, current, classEntry->superClassName, tps);

		current=jvmpiAgent_appendIntegerAttribute(NUM_INTERFACES_ATTRIBUTE, STRLEN_NUM_INTERFACES_ATTRIBUTE, current, classEntry->numInterfaces, tps->buffer);

		/* Show the interface names only if there are any interfaces implemented */
		if (classEntry->nameOfInterfaces && strlen(classEntry->nameOfInterfaces) > 0)
			current=jvmpiAgent_appendStringAttribute(INTERFACE_NAMES_ATTRIBUTE, STRLEN_INTERFACE_NAMES_ATTRIBUTE, current, classEntry->nameOfInterfaces, tps);

		current=jvmpiAgent_appendIntegerAttribute(NUM_METHODS_ATTRIBUTE, STRLEN_NUM_METHODS_ATTRIBUTE, current, classEntry->numMethods, tps->buffer);
		current=jvmpiAgent_appendIntegerAttribute(NUM_STATIC_FIELDS_ATTRIBUTE, STRLEN_NUM_STATIC_FIELDS_ATTRIBUTE, current, classEntry->numStaticFields, tps->buffer);
		current=jvmpiAgent_appendIntegerAttribute(NUM_INSTANCE_FIELDS_ATTRIBUTE, STRLEN_NUM_INSTANCE_FIELDS_ATTRIBUTE, current, classEntry->numInstanceFields, tps->buffer);
	  }
      if (jvmpiAgent_isPrintObjId())
	  {
        current=jvmpiAgent_appendIntegerAttribute(CLASS_ID_ATTRIBUTE, STRLEN_CLASS_ID_ATTRIBUTE, current, (jint)classEntry->classId, tps->buffer);
	  }
      if(jvmpiAgent_isPrintStaticId())
	  {
        current=jvmpiAgent_appendIntegerAttribute(STATIC_CLASS_ID_ATTRIBUTE, STRLEN_STATIC_CLASS_ID_ATTRIBUTE, current, (jint)classEntry->static_id, tps->buffer);
		/* Give the objectID of our class object if we have it*/
		if(CLASS_ENTRY(classHashEntry)->classObject) {
			current=jvmpiAgent_appendIntegerAttribute(STATIC_OBJ_IDREF_ATTRIBUTE, STRLEN_STATIC_OBJ_IDREF_ATTRIBUTE, current, (jint)OBJECT_ENTRY(CLASS_ENTRY(classHashEntry)->classObject)->static_id, tps->buffer);

		}
	  }
      if(_jvmpiAgent_Options.timestamp)
	  {
        /* In case we don't have a time for it (which is the case for primitives), this would be a good time to figure it out */
		if (classEntry->timestamp == 0)
		{
            jvmpiAgent_getCurrentTime(&classEntry->timestamp);
        }
        current=jvmpiAgent_appendTimestamp(tps->buffer, current, classEntry->timestamp);
	  }
      if (_jvmpiAgent_Options.contextFlow)
	  {
        /*## Values of context flow information not implemented yet. */
        current=jvmpiAgent_appendIntegerAttribute(SEQUENCE_COUNTER_ATTRIBUTE, STRLEN_SEQUENCE_COUNTER_ATTRIBUTE, current, 0, tps->buffer);
        current=jvmpiAgent_appendStringAttribute(CONTEXT_DATA_ATTRIBUTE, STRLEN_CONTEXT_DATA_ATTRIBUTE, current, "##not implemented yet##", tps);
	  }
      current=jvmpiAgent_printCollationValueAttribute(tps->buffer, current, &classEntry->collation);
      current=jvmpiAgent_printTraceIdrefAttribute(tps, current);
      current=jvmpiAgent_appendElementEnd(NULL, 0, current, tps);
      jvmpiAgent_print(tps, tps->buffer, current);

      if (_jvmpiAgent_Options.classLoadDetails)
	  {
        jvmpiAgent_printFields(tps, CLASS_ENTRY(classHashEntry)->statics, CLASS_ENTRY(classHashEntry)->numStaticFields, Static);
        jvmpiAgent_printFields(tps, CLASS_ENTRY(classHashEntry)->instances, CLASS_ENTRY(classHashEntry)->numInstanceFields, Instance);
	  }
	}
 }
}

void jvmpiAgent_printTraceEndElement(ThreadPrivateStorage *tps)
{
 unsigned short current = 0;
 current=jvmpiAgent_insertElementStart(TRACE_STOP_ELEMENT, STRLEN_TRACE_STOP_ELEMENT, tps);
 current = jvmpiAgent_printTraceIdrefAttribute(tps, current);

 /* Get the timestamp information if necessary */
 if(_jvmpiAgent_Options.timestamp)
 {
  current=jvmpiAgent_appendCurrentTimeStamp(tps->buffer, current);
 }

 /*##MW There is a race condition between the increment and the print that must be fixed */
 jvmpiAgent_incrementSegmentedValue(&_jvmpiAgent_collation, 0);
 current=jvmpiAgent_printCollationValueAttribute(tps->buffer, current, &_jvmpiAgent_collation);

 current=jvmpiAgent_appendElementEnd(NULL, 0, current, tps);
 jvmpiAgent_print(tps, tps->buffer, current);
}


unsigned short jvmpiAgent_printTicketAttribute(SegmentedValue_t *ticket, char *buffer, unsigned short current)
{
#ifdef SEGMENTED_VALUE_MULTIWORD
 unsigned long i;
 current=jvmpiAgent_appendUnsignedLongAttribute(TICKET_ATTRIBUTE, STRLEN_TICKET_ATTRIBUTE, current, ticket->values[0], buffer);
 for (i = 1; i < ticket->numberOfWords; i++)
 {
  current=jvmpiAgent_appendListUnsignedLong(current, ticket->values[i], buffer);
 }
#else
  current=jvmpiAgent_appendUnsignedLongAttribute(TICKET_ATTRIBUTE, STRLEN_TICKET_ATTRIBUTE, current, ticket->value, buffer);
#endif
 return current;
}


void jvmpiAgent_printTraceStartElement(ThreadLocalStorage *tps, char *options)
{
 if (!_jvmpiAgent_suspendIO)
 {
  ra_string_t uuid;
  ra_IPAddresses_t addresses;
  timestamp_t startTime;
  unsigned short current=0;
  jvmpiAgent_getCurrentTime(&startTime);

  /* We need to free this later so set to null in case the API call fails that does malloc */
  addresses.addresses=NULL;

  /* Initialize the collation value sequence */
  jvmpiAgent_initializeSegmentedValue(&_jvmpiAgent_collation, 1);

  current=jvmpiAgent_insertElementStart(TRACE_START_ELEMENT, STRLEN_TRACE_START_ELEMENT, tps);

  ra_generateUUID(&uuid);
#ifdef MVS
  if (uuid.length != __etoa(uuid.data)) {
#pragma convlit(suspend)
      printf("EBCDIC to ASCII conversion failure.\n");
	  fflush(stdout); 
#pragma convlit(resume)
  }
#endif
  _jvmpiAgent_trace_id=uuid.data;

  current=jvmpiAgent_appendStringAttribute(TRACE_ID_ATTRIBUTE, STRLEN_TRACE_ID_ATTRIBUTE, current, _jvmpiAgent_trace_id , tps);
/* 199373 begin */
#ifdef MVS
  uuid.length = strlen(ra_getAgentUUID(_jvmpiAgent_bindingStorage));
  uuid.data = (char *)malloc(uuid.length+1);
  if (uuid.data == NULL) {
#pragma convlit(suspend)
     printf("Memory allocation failure.\n");
	 fflush(stdout); 
#pragma convlit(resume)
     return;
  }
  strcpy(uuid.data, ra_getAgentUUID(_jvmpiAgent_bindingStorage));
  if (uuid.length != __etoa(uuid.data)) {
#pragma convlit(suspend)
      printf("EBCDIC to ASCII conversion failure.\n");
	  fflush(stdout); 
#pragma convlit(resume)
  }
  current=jvmpiAgent_appendStringAttribute(AGENT_IDREF_ATTRIBUTE, STRLEN_AGENT_IDREF_ATTRIBUTE, current, uuid.data, tps);
  free(uuid.data);
#else
  current=jvmpiAgent_appendStringAttribute(AGENT_IDREF_ATTRIBUTE, STRLEN_AGENT_IDREF_ATTRIBUTE, current, ra_getAgentUUID(_jvmpiAgent_bindingStorage) , tps);
#endif
/* 199373 end */

  if(_jvmpiAgent_Options.timestamp) {
	current=jvmpiAgent_appendTimestamp(tps->buffer, current, startTime);
  }

  /*##MW There is a race condition between the increment and the print that must be fixed */
  jvmpiAgent_incrementSegmentedValue(&_jvmpiAgent_collation, 0);
  current=jvmpiAgent_printCollationValueAttribute(tps->buffer, current, &_jvmpiAgent_collation);

  current=jvmpiAgent_appendElementEnd(NULL, 0, current, tps);
  jvmpiAgent_print(tps, tps->buffer, current);
 }
}


static unsigned short printHostNameAttribute(ThreadPrivateStorage *tps, unsigned short current)
{
 char hostNameBuffer[100];

 if(ra_getLocalHostName(hostNameBuffer, sizeof(hostNameBuffer))==0)
 {
#ifdef MVS                    /* 174190 */
  __etoa(hostNameBuffer);
#endif
  current=jvmpiAgent_appendStringAttribute(HOSTNAME_ATTRIBUTE, STRLEN_HOSTNAME_ATTRIBUTE, current, hostNameBuffer, tps);
 }
 return current;
}


static unsigned short printIPAddressAttribute(ThreadPrivateStorage *tps, unsigned short current)
{
 ra_IPAddresses_t addresses;
 unsigned char *p;
 int i;
 
 /* Get the network information and print it */
 if(ra_getLocalIPAddresses(&addresses)==0)
 {
#ifdef MVS                    /* 174190 */
   int mycurr = current;
#pragma convlit(suspend)
#endif
  tps->buffer[current++]=' ';
  memcpy(&tps->buffer[current], IPADDRESS_ATTRIBUTE, STRLEN_IPADDRESS_ATTRIBUTE);
  current+=STRLEN_IPADDRESS_ATTRIBUTE;
  tps->buffer[current++]='=';
  tps->buffer[current++]='\"';
  for (p=addresses.addresses; *p; p+=addresses.addressLength)
  {
   /* If this isn't the first IP address add a comma */
   if(p!=addresses.addresses)
   {
	tps->buffer[current++]=',';
   }

   /* the first number of the address */
#ifdef _WIN32
   itoa(p[0], &tps->buffer[current], 10);
   current+=strlen(&tps->buffer[current]);
#else
   current+=sprintf(&tps->buffer[current], "%d", p[0]);
#endif

   /* Subsequent "." separated address numbers */
   for (i=1; i < addresses.addressLength; i++)
   {
	tps->buffer[current++]='.';
#ifdef _WIN32
	itoa(p[i], &tps->buffer[current], 10);
	current+=strlen(&tps->buffer[current]);
#else
	current+=sprintf(&tps->buffer[current], "%d", p[i]);
#endif
   }
  }
  /* Add closing quote */
  tps->buffer[current++]='\"';
#ifdef MVS                    /* 174190 */
  tps->buffer[current]='\0';
#pragma convlit(resume)
  __etoa(tps->buffer+mycurr);
#endif
 }
 else
 {
  /* Couldn't resolve the IP (probably no network) */
  current=jvmpiAgent_appendStringAttribute(IPADDRESS_ATTRIBUTE, STRLEN_IPADDRESS_ATTRIBUTE, current, UNAVAILABLE, tps);
 }
 /* The memory required for the addreses is allocated in the jvmpicommGetLocalIPAddresses
  */
#ifndef _DEBUG
 ra_free(addresses.addresses); /*ts. Bug 143342, changed from free to ra_free to match with ra_malloc */
#endif
 return current;
}


void jvmpiAgent_printNodeElement(ThreadLocalStorage *tps)
{
 unsigned short current = 0;
 timestamp_t time;
#ifdef MVS
 char *uuid;
 int uuidlen;
#endif
 jvmpiAgent_getProcessStartTime(&time);
 current=jvmpiAgent_insertElementStart(NODE_ELEMENT, STRLEN_NODE_ELEMENT, tps);

#ifdef MVS
  uuidlen = strlen(ra_getNodeUUID(_jvmpiAgent_bindingStorage));
  uuid = (char *)malloc(uuidlen+1);   /* 192196 */
  if (uuid == NULL) {
#pragma convlit(suspend)
     printf("Memory allocation failure.\n");
	 fflush(stdout); 
#pragma convlit(resume)
     return;
  }
  strcpy(uuid, ra_getNodeUUID(_jvmpiAgent_bindingStorage));
  if (uuidlen != __etoa(uuid)) {
#pragma convlit(suspend)
      printf("EBCDIC to ASCII conversion failure.\n");
	  fflush(stdout); 
#pragma convlit(resume)
  }
 current=jvmpiAgent_appendStringAttribute(NODE_ID_ATTRIBUTE, STRLEN_NODE_ID_ATTRIBUTE, current, uuid, tps);
 free(uuid);
#else
 current=jvmpiAgent_appendStringAttribute(NODE_ID_ATTRIBUTE, STRLEN_NODE_ID_ATTRIBUTE, current, ra_getNodeUUID(_jvmpiAgent_bindingStorage) , tps);
#endif
 current=printHostNameAttribute(tps, current);
 current=printIPAddressAttribute(tps, current);
 current=jvmpiAgent_appendIntegerAttribute(TIMEZONE_ATTRIBUTE, STRLEN_TIMEZONE_ATTRIBUTE, current, jvmpiAgent_getTimezone(), tps->buffer);
 if(_jvmpiAgent_Options.timestamp) {
	current=jvmpiAgent_appendTimestamp(tps->buffer, current, time);
 }
 current=jvmpiAgent_appendElementEnd(NULL, 0, current, tps);
 jvmpiAgent_print(tps, tps->buffer, current);
}


void jvmpiAgent_printProcessCreateElement(ThreadLocalStorage *tps)
{
 unsigned short current = 0;
 timestamp_t time;
#ifdef MVS
 char *uuid;
 int uuidlen;
#endif
 jvmpiAgent_getProcessStartTime(&time);

 current=jvmpiAgent_insertElementStart(PROCESS_CREATE_ELEMENT, STRLEN_PROCESS_CREATE_ELEMENT, tps);
#ifdef MVS
  uuidlen = strlen(ra_getProcessUUID(_jvmpiAgent_bindingStorage));
  uuid = (char *)malloc(uuidlen+1);   /* 192196 */
  if (uuid == NULL) {
#pragma convlit(suspend)
     printf("Memory allocation failure.\n");
	 fflush(stdout); 
#pragma convlit(resume)
     return;
  }
  strcpy(uuid, ra_getProcessUUID(_jvmpiAgent_bindingStorage));
  if (uuidlen != __etoa(uuid)) {
#pragma convlit(suspend)
      printf("EBCDIC to ASCII conversion failure.\n");
	  fflush(stdout); 
#pragma convlit(resume)
  }
 current=jvmpiAgent_appendStringAttribute(PROCESS_ID_ATTRIBUTE, STRLEN_PROCESS_ID_ATTRIBUTE, current, uuid, tps);
 free(uuid);
#else
 current=jvmpiAgent_appendStringAttribute(PROCESS_ID_ATTRIBUTE, STRLEN_PROCESS_ID_ATTRIBUTE, current, ra_getProcessUUID(_jvmpiAgent_bindingStorage) , tps);
#endif
 current=jvmpiAgent_appendIntegerAttribute(PID_ATTRIBUTE, STRLEN_PID_ATTRIBUTE, current, ra_getProcessId(), tps->buffer);
#ifdef MVS
  uuidlen = strlen(ra_getNodeUUID(_jvmpiAgent_bindingStorage));
  uuid = (char *)malloc(uuidlen+1);   /* 192196 */
  if (uuid == NULL) {
#pragma convlit(suspend)
     printf("Memory allocation failure.\n");
	 fflush(stdout); 
#pragma convlit(resume)
     return;
  }
  strcpy(uuid, ra_getNodeUUID(_jvmpiAgent_bindingStorage));
  if (uuidlen != __etoa(uuid)) {
#pragma convlit(suspend)
      printf("EBCDIC to ASCII conversion failure.\n");
	  fflush(stdout); 
#pragma convlit(resume)
  }
 current=jvmpiAgent_appendStringAttribute(NODE_IDREF_ATTRIBUTE, STRLEN_NODE_IDREF_ATTRIBUTE, current, uuid , tps);
 free(uuid);
#else
 current=jvmpiAgent_appendStringAttribute(NODE_IDREF_ATTRIBUTE, STRLEN_NODE_IDREF_ATTRIBUTE, current, ra_getNodeUUID(_jvmpiAgent_bindingStorage) , tps);
#endif
 if(_jvmpiAgent_Options.timestamp) {
	current=jvmpiAgent_appendTimestamp(tps->buffer, current, time);
 }
/* 8884 */
/* current=jvmpiAgent_appendStringAttribute(APPLICATION_NAME_ATTRIBUTE, STRLEN_APPLICATION_NAME_ATTRIBUTE, current, ra_getProcessCommandLine() , tps->buffer); */
/* 8884 */
 current=jvmpiAgent_appendElementEnd(NULL, 0, current, tps);
 jvmpiAgent_print(tps, tps->buffer, current);
}


/** PRINT_EXCEPTION_ELEMENT  ***********************************************
  *
  */
void jvmpiAgent_printExceptionElement(JNIEnv *env,
									  ThreadLocalStorage *tps,
									  enum ThrowOrCatch type,
									  HashEntry *methodHashEntry,
									  jobjectID objId,
									  jthrowable e)
{
 HashEntry *objectHashEntry = jvmpiAgent_FindObjectSymbolWithAllocate(objId, env);
 unsigned short current=0;

 current=jvmpiAgent_insertEmptyEventHeader(env, tps, type == Throw ? THROW_ELEMENT : CATCH_ELEMENT, (unsigned short) (type == Throw ? STRLEN_THROW_ELEMENT : STRLEN_CATCH_ELEMENT));

 /* Get the timestamp information if necessary */
 if(_jvmpiAgent_Options.timestamp)
 {
  current=jvmpiAgent_appendCurrentTimeStamp(tps->buffer, current);
 }
 if (jvmpiAgent_isPrintObjId())
 {
  if (objId)
  {
   current=jvmpiAgent_appendIntegerAttribute(OBJ_IDREF_ATTRIBUTE, STRLEN_OBJ_IDREF_ATTRIBUTE, current, (unsigned long)objId, tps->buffer);
  }
  else
  {
   current=jvmpiAgent_appendStringAttribute(OBJ_IDREF_ATTRIBUTE, STRLEN_OBJ_IDREF_ATTRIBUTE, current, UNAVAILABLE, tps);
  }
 }
 if (jvmpiAgent_isPrintStaticId())
 {
  if (objId && objectHashEntry)
  {
   current=jvmpiAgent_appendIntegerAttribute(STATIC_OBJ_IDREF_ATTRIBUTE, STRLEN_STATIC_OBJ_IDREF_ATTRIBUTE, current, ((ObjectEntry*)objectHashEntry->entry)->static_id, tps->buffer);
  }
  else
  {
   current=jvmpiAgent_appendStringAttribute(STATIC_OBJ_IDREF_ATTRIBUTE, STRLEN_STATIC_OBJ_IDREF_ATTRIBUTE, current, UNAVAILABLE, tps);
  }
 }
 current=jvmpiAgent_appendIntegerAttribute(OBJ_HANDLE_ATTRIBUTE, STRLEN_OBJ_HANDLE_ATTRIBUTE, current, (unsigned long)e, tps->buffer);
 current=jvmpiAgent_appendIntegerAttribute(METHOD_IDREF_ATTRIBUTE, STRLEN_METHOD_IDREF_ATTRIBUTE, current, (jint)(((MethodEntry *)methodHashEntry->entry)->methodData.method_id), tps->buffer);

 if(_jvmpiAgent_Options.ticket)
 {
  current=jvmpiAgent_printTicketAttribute(&jvmpiAgent_Peek(tps,2)->ticket,tps->buffer, current);
 }

 /*##MW There is a race condition between the increment and the print that must be fixed */
 jvmpiAgent_incrementSegmentedValue(&_jvmpiAgent_collation, 0);
 current=jvmpiAgent_printCollationValueAttribute(tps->buffer, current, &_jvmpiAgent_collation);

 current=jvmpiAgent_printTraceIdrefAttribute(tps, current);
 current=jvmpiAgent_appendElementEnd(NULL, 0, current, tps);
 jvmpiAgent_print(tps, tps->buffer, current);
}

/** PRINT_LINE_ELEMENT  ****************************************************
  *
  */
void jvmpiAgent_printLineElement(JNIEnv *env,
								 ThreadLocalStorage *tps,
								 HashEntry *methodHashEntry,
								 unsigned short lineNumber)
{
  unsigned short current=0;

  current=jvmpiAgent_insertEmptyEventHeader(env, tps, LINE_ELEMENT, STRLEN_LINE_ELEMENT);
  /* Get the timestamp information if necessary */
  if(_jvmpiAgent_Options.timestamp)
  {
   current=jvmpiAgent_appendCurrentTimeStamp(tps->buffer, current);
  }

  current=jvmpiAgent_appendIntegerAttribute(LINE_NUMBER_ATTRIBUTE, STRLEN_LINE_NUMBER_ATTRIBUTE, current, lineNumber, tps->buffer);
  current=jvmpiAgent_appendIntegerAttribute(METHOD_IDREF_ATTRIBUTE, STRLEN_METHOD_IDREF_ATTRIBUTE, current, (jint)(((MethodEntry *)methodHashEntry->entry)->methodData.method_id), tps->buffer);

  /*##MW There is a race condition between the increment and the print that must be fixed */
  jvmpiAgent_incrementSegmentedValue(&_jvmpiAgent_collation, 0);
  current=jvmpiAgent_printCollationValueAttribute(tps->buffer, current, &_jvmpiAgent_collation);
  current=jvmpiAgent_printTraceIdrefAttribute(tps, current);
  current=jvmpiAgent_appendElementEnd(NULL, 0, current, tps);
  jvmpiAgent_print(tps, tps->buffer, current);
}

void jvmpiAgent_printAgentCreateElement(ThreadLocalStorage *tps,
										char *options)
{
 unsigned short current=0;
#ifdef MVS
 char *uuid;
 int uuidlen;
#endif

 current=jvmpiAgent_insertElementStart(AGENT_CREATE_ELEMENT, STRLEN_AGENT_CREATE_ELEMENT, tps);
/* 199373 begin */
#ifdef MVS
  uuidlen = strlen(ra_getAgentUUID(_jvmpiAgent_bindingStorage));
  uuid = (char *)malloc(uuidlen+1);   /* 192196 */
  if (uuid == NULL) {
#pragma convlit(suspend)
     printf("Memory allocation failure.\n");
	 fflush(stdout); 
#pragma convlit(resume)
     return;
  }
  strcpy(uuid, ra_getAgentUUID(_jvmpiAgent_bindingStorage));
  if (uuidlen != __etoa(uuid)) {
#pragma convlit(suspend)
      printf("EBCDIC to ASCII conversion failure.\n");
	  fflush(stdout); 
#pragma convlit(resume)
  }
 current=jvmpiAgent_appendStringAttribute(AGENT_ID_ATTRIBUTE, STRLEN_AGENT_ID_ATTRIBUTE, current, uuid, tps);
 free(uuid);
#else
 current=jvmpiAgent_appendStringAttribute(AGENT_ID_ATTRIBUTE, STRLEN_AGENT_ID_ATTRIBUTE, current, ra_getAgentUUID(_jvmpiAgent_bindingStorage) , tps);
#endif
/* 199373 end */

 current=jvmpiAgent_appendStringAttribute(AGENT_VERSION_ATTRIBUTE, STRLEN_AGENT_VERSION_ATTRIBUTE, current, AGENT_VERSION, tps);

#ifdef MVS
  uuidlen = strlen(ra_getProcessUUID(_jvmpiAgent_bindingStorage));
  uuid = (char *)malloc(uuidlen+1);   /* 192196 */
  if (uuid == NULL) {
#pragma convlit(suspend)
     printf("Memory allocation failure.\n");
	 fflush(stdout); 
#pragma convlit(resume)
     return;
  }
  strcpy(uuid, ra_getProcessUUID(_jvmpiAgent_bindingStorage));
  if (uuidlen != __etoa(uuid)) {
#pragma convlit(suspend)
      printf("EBCDIC to ASCII conversion failure.\n");
	  fflush(stdout); 
#pragma convlit(resume)
  }
 current=jvmpiAgent_appendStringAttribute(PROCESS_IDREF_ATTRIBUTE, STRLEN_PROCESS_IDREF_ATTRIBUTE, current, uuid, tps);
 free(uuid);
#else
 current=jvmpiAgent_appendStringAttribute(PROCESS_IDREF_ATTRIBUTE, STRLEN_PROCESS_IDREF_ATTRIBUTE, current, ra_getProcessUUID(_jvmpiAgent_bindingStorage) , tps);
#endif
 current=jvmpiAgent_appendStringAttribute(AGENT_NAME_ATTRIBUTE, STRLEN_AGENT_NAME_ATTRIBUTE, current, _jvmpiAgent_Options.processName , tps);
 current=jvmpiAgent_appendStringAttribute(AGENT_TYPE_ATTRIBUTE, STRLEN_AGENT_TYPE_ATTRIBUTE, current, _jvmpiAgent_Options.processType , tps);
 current=jvmpiAgent_appendStringAttribute(AGENT_PARAMETERS_ATTRIBUTE, STRLEN_AGENT_PARAMETERS_ATTRIBUTE, current, options , tps);
 if(_jvmpiAgent_Options.timestamp) {
	current=jvmpiAgent_appendTimestamp(tps->buffer, current, _startTimeAsTicks);
 }
 current=jvmpiAgent_appendElementEnd(NULL, 0, current, tps);
 jvmpiAgent_print(tps, tps->buffer, current);
}

/* PR Object Ref */
void jvmpiAgent_printHDStartElement(ThreadLocalStorage *tps,
									char* heapDefName)
{
  if(_jvmpiAgent_Options.jinsightFormat) {
  } else {
	unsigned short current=0;
	current=jvmpiAgent_insertElementStart(HD_START_ELEMENT, STRLEN_HD_START_ELEMENT, tps);
	current=jvmpiAgent_appendIntegerAttribute(HEAPDUMP_ID_ATTRIBUTE, STRLEN_HEAPDUMP_ID_ATTRIBUTE, current, _heapDumpInfo.index, tps->buffer);
	if(_jvmpiAgent_Options.timestamp)
	{
		current=jvmpiAgent_appendCurrentTimeStamp(tps->buffer, current);
	}
    current=jvmpiAgent_printTraceIdrefAttribute(tps, current);
	current=jvmpiAgent_appendStringAttribute(NAME_ATTRIBUTE, STRLEN_NAME_ATTRIBUTE, current, heapDefName, tps);
	current=jvmpiAgent_appendLabeledTimestamp(tps->buffer, current, BASETIME_ATTRIBUTE, STRLEN_BASETIME_ATTRIBUTE, _heapDumpInfo.lastGenerationTime, FALSE);
	current=jvmpiAgent_appendElementEnd(NULL, 0, current, tps);
	jvmpiAgent_print(tps, tps->buffer, current);
  }
}

/* Added "firstSeen" for bug 46785 */
void jvmpiAgent_printObjectArrayReferenceElement(ThreadLocalStorage *tps,
												 unsigned long obj_id,
												 unsigned int index,
												 jint objRef_id,
												 unsigned int firstSeen)
{
  if(_jvmpiAgent_Options.jinsightFormat) {
#ifdef BINARY_TRACE
    unsigned short numBytes = BINARYTRACE_printArrayReference(tps->buffer, obj_id, objRef_id);
    jvmpiAgent_print(tps, tps->buffer, numBytes);
#endif /* BINARY_TRACE */
  } else {
	unsigned short current=0;
	current=jvmpiAgent_insertElementStart(OBJECT_REFERENCE_ATTRIBUTE, STRLEN_OBJECT_REFERENCE_ATTRIBUTE, tps);
	current=jvmpiAgent_appendIntegerAttribute(OBJECT_OWNER_ATTRIBUTE, STRLEN_OBJECT_OWNER_ATTRIBUTE, current, obj_id, tps->buffer);
	current=jvmpiAgent_appendIntegerAttribute(OBJECT_TARGET_ATTRIBUTE, STRLEN_OBJECT_TARGET_ATTRIBUTE, current, objRef_id, tps->buffer);
	current=jvmpiAgent_appendIntegerAttribute(OBJECT_ARRAY_INDEX_ATTRIBUTE, STRLEN_OBJECT_ARRAY_INDEX_ATTRIBUTE, current, index, tps->buffer);
	current=jvmpiAgent_appendIntegerAttribute(HEAPDUMP_IDREF_ATTRIBUTE, STRLEN_HEAPDUMP_IDREF_ATTRIBUTE, current, _heapDumpInfo.index, tps->buffer);
	current=jvmpiAgent_appendIntegerAttribute(HEAPDUMP_FIRST_SEEN_ATTRIBUTE, STRLEN_HEAPDUMP_FIRST_SEEN_ATTRIBUTE, current, firstSeen, tps->buffer);
	current=jvmpiAgent_appendElementEnd(NULL, 0, current, tps);
	jvmpiAgent_print(tps, tps->buffer, current);
  }
}

/* Added "firstSeen" for bug 46785 */
void jvmpiAgent_printObjectInstanceReferenceElement(ThreadLocalStorage *tps,
													unsigned long obj_id,
													unsigned int index,
													jint objRef_id,
													unsigned int firstSeen,
													unsigned long fieldIdRef)
{
  if(_jvmpiAgent_Options.jinsightFormat) {
#ifdef BINARY_TRACE
    unsigned short numBytes = BINARYTRACE_printObjectReference(tps->buffer, obj_id, objRef_id);
    jvmpiAgent_print(tps, tps->buffer, numBytes);
#endif /* BINARY_TRACE */
  } else {
	unsigned short current=0;
	current=jvmpiAgent_insertElementStart(OBJECT_REFERENCE_ATTRIBUTE, STRLEN_OBJECT_REFERENCE_ATTRIBUTE, tps);
	current=jvmpiAgent_appendIntegerAttribute(OBJECT_OWNER_ATTRIBUTE, STRLEN_OBJECT_OWNER_ATTRIBUTE, current, obj_id, tps->buffer);
	current=jvmpiAgent_appendIntegerAttribute(OBJECT_TARGET_ATTRIBUTE, STRLEN_OBJECT_TARGET_ATTRIBUTE, current, objRef_id, tps->buffer);
	current=jvmpiAgent_appendIntegerAttribute(FIELD_IDREF_ATTRIBUTE, STRLEN_FIELD_IDREF_ATTRIBUTE, current, fieldIdRef, tps->buffer);
	current=jvmpiAgent_appendIntegerAttribute(HEAPDUMP_IDREF_ATTRIBUTE, STRLEN_HEAPDUMP_IDREF_ATTRIBUTE, current, _heapDumpInfo.index, tps->buffer);
	current=jvmpiAgent_appendIntegerAttribute(HEAPDUMP_FIRST_SEEN_ATTRIBUTE, STRLEN_HEAPDUMP_FIRST_SEEN_ATTRIBUTE, current, firstSeen, tps->buffer);
	current=jvmpiAgent_appendElementEnd(NULL, 0, current, tps);
	jvmpiAgent_print(tps, tps->buffer, current);
  }
}
/* PR */

void jvmpiAgent_printStaticReferenceElement(ThreadLocalStorage *tps,
											unsigned long class_id,
											unsigned int index,
											jint objRef_id,
											unsigned long fieldIdRef) {
  if(_jvmpiAgent_Options.jinsightFormat) {
#ifdef BINARY_TRACE
    unsigned short numBytes = BINARYTRACE_printClassReference(tps->buffer, class_id, objRef_id);
    jvmpiAgent_print(tps, tps->buffer, numBytes);
#endif /* BINARY_TRACE */
  } else {
	unsigned short current=0;
	current=jvmpiAgent_insertElementStart(STATIC_REFERENCE_ATTRIBUTE, STRLEN_STATIC_REFERENCE_ATTRIBUTE, tps);
	current=jvmpiAgent_appendIntegerAttribute(CLASS_OWNER_ATTRIBUTE, STRLEN_CLASS_OWNER_ATTRIBUTE, current, class_id, tps->buffer);
	current=jvmpiAgent_appendIntegerAttribute(OBJECT_TARGET_ATTRIBUTE, STRLEN_OBJECT_TARGET_ATTRIBUTE, current, objRef_id, tps->buffer);
	current=jvmpiAgent_appendIntegerAttribute(FIELD_IDREF_ATTRIBUTE, STRLEN_FIELD_IDREF_ATTRIBUTE, current, fieldIdRef, tps->buffer);
	current=jvmpiAgent_appendIntegerAttribute(HEAPDUMP_IDREF_ATTRIBUTE, STRLEN_HEAPDUMP_IDREF_ATTRIBUTE, current, _heapDumpInfo.index, tps->buffer);
	current=jvmpiAgent_appendElementEnd(NULL, 0, current, tps);
	jvmpiAgent_print(tps, tps->buffer, current);
  }
}

void jvmpiAgent_printXMLStartElement(ThreadLocalStorage *tps)
{
 if (!_jvmpiAgent_suspendIO)
 {
  unsigned short current=0;
  char *data="?xml version=\"1.0\"?>";
  current=jvmpiAgent_insertElementStart(data, 20,  tps);
  jvmpiAgent_print(tps, tps->buffer, current);
 }
}


/** PRINT_VM_SUSPEND  ************************************************************
  * Loads the memory address specified by 'buffer' with a Suspend entity including
  * timestamp.
  */
extern void jvmpiAgent_printVMSuspend(ThreadLocalStorage *tps)
{
 if(!_jvmpiAgent_suspendIO)
 {
  unsigned short current=0;
  current=jvmpiAgent_insertElementStart(PROCESS_SUSPEND_ELEMENT, STRLEN_PROCESS_SUSPEND_ELEMENT, tps);
  /* Get the timestamp information if necessary */
  if (_jvmpiAgent_Options.timestamp)
  {
   current=jvmpiAgent_appendCurrentTimeStamp(tps->buffer, current);
  }
  current=jvmpiAgent_printTraceIdrefAttribute(tps, current);
  current=jvmpiAgent_appendElementEnd(NULL, 0, current, tps);
  jvmpiAgent_print(tps, tps->buffer, current);
 }
}


/** PRINT_VM_RESUME  ************************************************************
  * Loads the memory address specified by 'buffer' with a Resume entity including
  * timestamp.
  */
extern void jvmpiAgent_printVMResume(ThreadLocalStorage *tps)
{
 if(!_jvmpiAgent_suspendIO)
 {
  unsigned short current=0;
  current=jvmpiAgent_insertElementStart(PROCESS_RESUME_ELEMENT, STRLEN_PROCESS_RESUME_ELEMENT, tps);
  /* Get the timestamp information if necessary */
  if(_jvmpiAgent_Options.timestamp)
  {
   current=jvmpiAgent_appendCurrentTimeStamp(tps->buffer, current);
  }
  current=jvmpiAgent_printTraceIdrefAttribute(tps, current);
  current=jvmpiAgent_appendElementEnd(NULL, 0, current, tps);
  jvmpiAgent_print(tps, tps->buffer, current);
 }
}


void jvmpiAgent_printStandaloneTraceTagOpen(ThreadLocalStorage *tps)
{
  strcpy(tps->buffer, XML_OPENING_TAG_TRACE);
  jvmpiAgent_print(tps, tps->buffer, (unsigned short)strlen(tps->buffer));
}


void jvmpiAgent_printStandaloneTraceTagClose(ThreadLocalStorage *tps)
{
  strcpy(tps->buffer, XML_CLOSING_TAG_TRACE);
  jvmpiAgent_print(tps, tps->buffer, (unsigned short)strlen(tps->buffer));
}


void jvmpiAgent_printAgentDestroyElement(ThreadLocalStorage *tps)
{
 if(!_jvmpiAgent_suspendIO)
 {
/* 199373 begin */
#ifdef MVS
  char *uuid;
  int uuidlen;
#endif
  unsigned short current=0;
  current=jvmpiAgent_insertElementStart(AGENT_DESTROY_ELEMENT, STRLEN_AGENT_DESTROY_ELEMENT, tps);

#ifdef MVS
  uuidlen = strlen(ra_getAgentUUID(_jvmpiAgent_bindingStorage));
  uuid = (char *)malloc(uuidlen+1);   /* 192196 */
  if (uuid == NULL) {
#pragma convlit(suspend)
     printf("Memory allocation failure.\n");
	 fflush(stdout); 
#pragma convlit(resume)
     return;
  }
  strcpy(uuid, ra_getAgentUUID(_jvmpiAgent_bindingStorage));
  if (uuidlen != __etoa(uuid)) {
#pragma convlit(suspend)
      printf("EBCDIC to ASCII conversion failure.\n");
	  fflush(stdout); 
#pragma convlit(resume)
  }
  current=jvmpiAgent_appendStringAttribute(AGENT_IDREF_ATTRIBUTE, STRLEN_AGENT_IDREF_ATTRIBUTE, current, uuid, tps);
  free(uuid);
#else
  current=jvmpiAgent_appendStringAttribute(AGENT_IDREF_ATTRIBUTE, STRLEN_AGENT_IDREF_ATTRIBUTE, current, ra_getAgentUUID(_jvmpiAgent_bindingStorage) , tps);
#endif
/* 199373 end */

  /* Get the timestamp information if necessary */
  if(_jvmpiAgent_Options.timestamp)
  {
   current=jvmpiAgent_appendCurrentTimeStamp(tps->buffer, current);
  }
  current=jvmpiAgent_appendElementEnd(NULL, 0, current, tps);
  jvmpiAgent_print(tps, tps->buffer, current);
 }
}

void jvmpiAgent_printJvmShutdownElement(JVMPI_Event *event) {
 if (!_jvmpiAgent_suspendIO)
 {
  ThreadPrivateStorage *tps = jvmpiAgent_getThreadLocalStorage(0);
  /* char * buffer = tps->buffer; Get the global work thread buffer */

  if(_jvmpiAgent_Options.jinsightFormat) {
#ifdef BINARY_TRACE
    BINARYTRACE_printTraceEnd(tps);
#endif /* BINARY_TRACE */
  }
  else {
  unsigned short current=0;
  current=jvmpiAgent_insertEmptyEventHeader(event->env_id, tps, JVM_SHUT_DOWN_ELEMENT, STRLEN_JVM_SHUT_DOWN_ELEMENT);
  /* Get the timestamp information if necessary */
  if(_jvmpiAgent_Options.timestamp)
  {
   current=jvmpiAgent_appendCurrentTimeStamp(tps->buffer, current);
  }
  jvmpiAgent_incrementSegmentedValue(&_jvmpiAgent_collation, 0);
  current=jvmpiAgent_printCollationValueAttribute(tps->buffer, current, &_jvmpiAgent_collation);
  current=jvmpiAgent_printTraceIdrefAttribute(tps, current);
  current=jvmpiAgent_appendElementEnd(NULL, 0, current, tps);
  jvmpiAgent_print(tps, tps->buffer, current);
  /* If a global method count was asked for,  print it out */
  if (_jvmpiAgent_Options.methodCounts)
  {
   jvmpiAgent_ForAll(Method_t, jvmpiAgent_printMethodCount, tps);
  }

  /* Print the closing tag */
  jvmpiAgent_printTraceEndElement(tps);
  jvmpiAgent_printAgentDestroyElement(tps);
 }
 }
}

void jvmpiAgent_printTraceStopElement(ThreadLocalStorage *tps) {
 unsigned short current=0;
 current=jvmpiAgent_insertElementStart(TRACE_STOP_ELEMENT, STRLEN_TRACE_STOP_ELEMENT, tps);
 if(_jvmpiAgent_Options.timestamp) {
	current=jvmpiAgent_appendCurrentTimeStamp(tps->buffer, current);
 }
 jvmpiAgent_appendElementEnd(NULL, 0, current, tps);
 jvmpiAgent_print(tps, tps->buffer, current);
}
