/**********************************************************************
 * Copyright (c) 2005, 2007 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: binary_print.c,v 1.2 2007/04/06 00:35:02 jkubasta Exp $
 *
 * Contributors:
 * IBM - Initial API and implementation
 **********************************************************************/
#ifdef BINARY_TRACE

#include "hash.h"
#include "binarytrace.h"
#include "binary_privates.h"
#include "binary_print.h"

#if 0
#define BINARYTRACE_DEBUG(buffer, msg) \
  memcpy(buffer, msg, strlen(msg));\
  buffer += strlen(msg);
#else
#define BINARYTRACE_DEBUG(buffer, msg)
#endif

static inline char jvmpi_to_jni(char jvmpi_type) {
  switch(jvmpi_type) {
  case JVMPI_BYTE:
    return SIGNATURE_BYTE;
  case JVMPI_BOOLEAN:
    return SIGNATURE_BOOLEAN;
  case JVMPI_CHAR:
    return SIGNATURE_CHAR;
  case JVMPI_SHORT:
    return SIGNATURE_SHORT;
  case JVMPI_INT:
    return SIGNATURE_INT;
  case JVMPI_FLOAT:
    return SIGNATURE_FLOAT;
  case JVMPI_LONG:
    return SIGNATURE_LONG;
  case JVMPI_DOUBLE:
    return SIGNATURE_DOUBLE;
  case JVMPI_CLASS:
    return SIGNATURE_CLASS;
  default:
    assert(0);
    return 0;
  }
}

inline void prof_fill_u1(char* cursor,
			 char  data)
{
  *cursor = data;
}
inline void prof_fill_boolean(char* cursor,
			      BOOL  data)
{
  prof_fill_u1(cursor, data ? 1 : 0);
}
inline void prof_fill_EventType(char*         cursor,
				jsEventType_t event)
{
  prof_fill_u1(cursor, event);
}
inline void prof_fill_u2(char* cursor,
			 short data)
{
#ifdef NEED_ALIGNMENT
  memcpy((void*)cursor, (void*)&data, sizeof(short));
#else
  short* buf = (short*)cursor;
  *buf = data;
#endif /* NEED_ALIGNMENT */
}
inline void prof_fill_u4(char*   cursor,
			 int32_t data)
{
#ifdef NEED_ALIGNMENT
  memcpy((void*)cursor, (void*)&data, sizeof(int32_t));
#else
  int32_t* buf = (int32_t*)cursor;
  *buf = data;
#endif /* NEED_ALIGNMENT */
}
inline void prof_fill_float(char* cursor,
			    float data)
{
#ifdef NEED_ALIGNMENT
  memcpy((void*)cursor, (void*)&data, sizeof(float));
#else
  float* buf = (float*)cursor;
  *buf = data;
#endif /* NEED_ALIGNMENT */
}
inline void prof_fill_double(char*  cursor,
			     double data)
{
#ifdef NEED_ALIGNMENT
  memcpy((void*)cursor, (void*)&data, sizeof(double));
#else
  double* buf = (double*)cursor;
  *buf = data;
#endif /* NEED_ALIGNMENT */
}
inline void prof_fill_u8(char*   cursor,
			 int64_t data)
{
#ifdef NEED_ALIGNMENT
  memcpy((void*)cursor, (void*)&data, sizeof(int64_t));
#else
  int64_t* buf = (int64_t*)cursor;
  *buf = data;
#endif /* NEED_ALIGNMENT */
}
inline void prof_fill_timestamp(char*       cursor,
				timestamp_t time)
{
#ifdef SMURF
  uint64_t longy = time->seconds;
  longy *= 1000000;
  longy += time->microseconds;
#else
  uint64_t longy = time;
#endif

  /*fprintf(stderr, "%d %llu\n", sizeof(int64_t), longy);*/
  prof_fill_u8(cursor, longy);
}
inline void prof_fill_current_timestamp(char* cursor)
{
  timestamp_t now;
  jvmpiAgent_getCurrentTime(&now);
  prof_fill_timestamp(cursor, now);
}
inline void prof_fill_TID(char*                 cursor,
			  ThreadPrivateStorage* tps)
{
  jsThreadID_t data = tps->staticThreadId;
#ifdef NEED_ALIGNMENT
  memcpy((void*)cursor, (void*)&data, sizeof(jsThreadID_t));
#else
  jsThreadID_t* buf = (jsThreadID_t*)cursor;
  *buf = data;
#endif /* NEED_ALIGNMENT */
}
inline void prof_fill_OID(char*        cursor,
			  jsObjectID_t data)
{
  prof_fill_u4(cursor, data);
}
inline void prof_fill_CID(char*       cursor,
			  jsClassID_t data)
{
  prof_fill_u4(cursor, data);
}
inline void prof_fill_MID(char*        cursor,
			  jsMethodID_t data)
{
  prof_fill_u4(cursor, data);
}
inline unsigned short prof_fill_string(char*       cursor,
				       const char* string)
{
  int len = strlen(string);

  prof_fill_u2(cursor, len);
  cursor += 2;

  memcpy(cursor, string, len);

  return (unsigned short)len+2;
}
_inline void prof_fill_ValueTypeTag(char* cursor, jsValueTypeTag_t type)
{
  prof_fill_u1(cursor, type);
}
_inline char* prof_fill_byteValue(char* cursor, jsByteValue_t b)
{
  prof_fill_ValueTypeTag(cursor, SIGNATURE_BYTE);
  cursor += sizeof(jsValueTypeTag_t);

  prof_fill_u1(cursor, b);
  cursor += sizeof(jsByteValue_t);

  return cursor;
}
_inline char* prof_fill_booleanValue(char* cursor, jsBooleanValue_t b)
{
  prof_fill_ValueTypeTag(cursor, SIGNATURE_BOOLEAN);
  cursor += sizeof(jsValueTypeTag_t);

  prof_fill_boolean(cursor, b);
  cursor += sizeof(jsBooleanValue_t);

  return cursor;
}
_inline char* prof_fill_charValue(char* cursor, jsCharValue_t c)
{
  prof_fill_ValueTypeTag(cursor, SIGNATURE_CHAR);
  cursor += sizeof(jsValueTypeTag_t);

  prof_fill_u2(cursor, c);
  cursor += sizeof(jsCharValue_t);

  return cursor;
}
_inline char* prof_fill_shortValue(char* cursor, jsShortValue_t s)
{
  prof_fill_ValueTypeTag(cursor, SIGNATURE_SHORT);
  cursor += sizeof(jsValueTypeTag_t);

  prof_fill_u2(cursor, s);
  cursor += sizeof(jsShortValue_t);

  return cursor;
}
_inline char* prof_fill_intValue(char* cursor, jsIntValue_t i)
{
  prof_fill_ValueTypeTag(cursor, SIGNATURE_INT);
  cursor += sizeof(jsValueTypeTag_t);

  prof_fill_u4(cursor, i);
  cursor += sizeof(jsIntValue_t);

  return cursor;
}
_inline char* prof_fill_floatValue(char* cursor, jsFloatValue_t f)
{
  prof_fill_ValueTypeTag(cursor, SIGNATURE_FLOAT);
  cursor += sizeof(jsValueTypeTag_t);

  prof_fill_float(cursor, f);
  cursor += sizeof(jsFloatValue_t);

  return cursor;
}
_inline char* prof_fill_doubleValue(char* cursor, jsDoubleValue_t d)
{
  prof_fill_ValueTypeTag(cursor, SIGNATURE_DOUBLE);
  cursor += sizeof(jsValueTypeTag_t);

  prof_fill_double(cursor, d);
  cursor += sizeof(jsDoubleValue_t);

  return cursor;
}
_inline char* prof_fill_longValue(char* cursor, jsLongValue_t l)
{
  prof_fill_ValueTypeTag(cursor, SIGNATURE_LONG);
  cursor += sizeof(jsValueTypeTag_t);

  prof_fill_u8(cursor, l);
  cursor += sizeof(jsLongValue_t);

  return cursor;
}


/* hack for missing access bits: */
const short ACCESS_DEFAULT = 0x0000;
const short ACCESS_STATIC  = 0x0008;

#ifdef NEVER
/* left this in temporarily because it is used by some code that's ifdef'd out.
 * Find out from Richard if we can pull the other dead code. see printInterfaces. */

static _inline void printClassId(char* buffer, jobjectID clazz)
{
  HashEntry *classHashEntry = jvmpiAgent_FindSymbol((jint)clazz, Class_t);
  if(classHashEntry == NULL) {
    prof_fill_CID(buffer, NULL_CID);
  }
  else {
    prof_fill_CID(buffer, CLASS_ENTRY(classHashEntry)->static_id);
  }
}
#endif /* NEVER */

void BINARYTRACE_printFields(ThreadLocalStorage* tps,
			ClassEntry* classEntry,
			jint        numFields,
			int         startIndex,
			PI_Field*   fields,
			BOOL        isStatic) /* hack since don't have access bits*/
{
  char*     buffer = tps->buffer;
  char* bufferOrig = buffer;
  int i;

  for(i=0; i<numFields; i++) {
    buffer = bufferOrig;

    /* 1. event type */
    prof_fill_EventType(buffer, FieldDefine);
    buffer += sizeof(jsEventType_t);

    /* 2. class cid */
    prof_fill_CID(buffer, classEntry->static_id);
    buffer += sizeof(jsClassID_t);

    /* 3. field index */
    prof_fill_u4(buffer, i+startIndex);
    buffer += 4;

    /* 3. field id */
    prof_fill_u4(buffer, fields[i].fieldId);
    buffer += 4;

    /* 4. field name */
    buffer += prof_fill_string(buffer, fields[i].field_name);

    /* 5. field signature */
    buffer += prof_fill_string(buffer, fields[i].field_signature);

    /* 6. field access */
    prof_fill_u2(buffer, isStatic ? ACCESS_STATIC : ACCESS_DEFAULT); /* hacko */
    buffer += 2;

    jvmpiAgent_print(tps, tps->buffer, buffer-bufferOrig);
  }
}

unsigned short printInterfaces(char*       buffer,
			       ClassEntry* classEntry)
{
#ifdef NEVER
	/* What are we saving this for? */
  char *bufferOrig = buffer;
  int i;

 prof_fill_u2(buffer, classEntry->numInterfaces);
  buffer += 2;

  for(i=0; i<classEntry->numInterfaces; i++) {
    jobjectID interface = classEntry->interfaces[i];
    printClassId(buffer, interface);
    buffer += sizeof(jsClassID_t);
  }

  return buffer - bufferOrig;
#else /* NEVER */
  return 0;
#endif /* NEVER */
}

unsigned short BINARYTRACE_printClassDefine(char*       buffer,
				       ClassEntry* classEntry)
{
  /* 1. event type */
  prof_fill_EventType(buffer, ClassDefine);
  buffer += sizeof(jsEventType_t);

  /* 2. timestamp of the classload */
  if(_jvmpiAgent_Options.timestamp) {
    prof_fill_timestamp(buffer, classEntry->timestamp);
  }
  else {
    prof_fill_current_timestamp(buffer);
  }
  buffer += sizeof(jsTimestamp_t);

  /* 3. class cid */
  prof_fill_CID(buffer, classEntry->static_id);
  buffer += sizeof(jsClassID_t);

  /* 4. class oid */
  if(classEntry->classObject == NULL) {
    prof_fill_OID(buffer, NULL_OID);
  }
  else {
    prof_fill_OID(buffer, OBJECT_ENTRY(classEntry->classObject)->static_id);
  }
  buffer += sizeof(jsObjectID_t);

#if 0
  /* this would make it a ClassDefine2 */

  /* 5. loading thread */
  prof_fill_TID(buffer, NULL_TID); /* NMM FIXME */
  buffer += sizeof(jsThreadID_t);
#endif


  return sizeof(jsEventType_t)
    +    sizeof(jsTimestamp_t)
    +    sizeof(jsClassID_t)
    +    sizeof(jsObjectID_t);
}
/*
  Contents are: type, tick, oid, jsClsId, name_len, name
*/
unsigned short BINARYTRACE_printClassLoad(char*       buffer,
				     ClassEntry* classEntry)
{
  char *bufferOrig = buffer;

  BINARYTRACE_DEBUG(buffer, "CLASS LOAD");

  /* 1. event type */
  prof_fill_EventType(buffer, ClassLoad);
  buffer += sizeof(jsEventType_t);

  /* 2. timestamp of the classload */
  if(_jvmpiAgent_Options.timestamp) {
    prof_fill_timestamp(buffer, classEntry->timestamp);
  }
  else {
    prof_fill_current_timestamp(buffer);
  }
  buffer += sizeof(jsTimestamp_t);

  /* 3. class cid */
  prof_fill_CID(buffer, classEntry->static_id);
  buffer += sizeof(jsClassID_t);


  /* 4. instance size */
  prof_fill_u2(buffer, 0/*(short)classEntry->instanceSize*/);
  buffer += 2;

  /* 5. class name */
  buffer += prof_fill_string(buffer, classEntry->className);

  /* 6. num methods */
  prof_fill_u2(buffer, classEntry->numMethods);
  buffer += 2;

  /* 7. num static fields */
  prof_fill_u2(buffer, classEntry->numStaticFields);
  buffer += 2;

  /* 8. num instance fields */
  prof_fill_u2(buffer, classEntry->numInstanceFields);
  buffer += 2;

  /* 9. superclass */
  if (classEntry->superClassEntry) {
	prof_fill_CID(buffer, CLASS_ENTRY(classEntry->superClassEntry)->static_id);
  } else {
	prof_fill_CID(buffer, NULL_CID);
  }
  buffer += sizeof(jsClassID_t);

  /* 10. interfaces */
  buffer += printInterfaces(buffer, classEntry);

  return buffer - bufferOrig;
}
/*
  Contents are: tag, classId, methodId methodName, methodSignature
*/
unsigned short BINARYTRACE_printMethodDefine(char*        buffer,
					MethodEntry* methodEntry)
{
  unsigned short methodNameLength, signatureLength;

  BINARYTRACE_DEBUG(buffer, "METHOD DEFINE");

  /* 1. event type */
  prof_fill_EventType(buffer, MethodDefine);
  buffer += sizeof(jsEventType_t);

  /* 2. class id */
  {
    ClassEntry* classEntry = CLASS_ENTRY(methodEntry->classHashEntry);
    prof_fill_CID(buffer, classEntry->static_id);
    buffer += sizeof(jsClassID_t);
  }

  /* 3. method id */
  prof_fill_MID(buffer, methodEntry->static_id);
  buffer += sizeof(jsMethodID_t);

  /* 4. method name */
  methodNameLength = prof_fill_string(buffer, methodEntry->methodData.method_name);
  buffer += methodNameLength;

  /* 5. method signature */
  signatureLength = prof_fill_string(buffer, methodEntry->methodData.method_signature);
  buffer += signatureLength;

  /* 6. method access bits */
  prof_fill_u2(buffer, ACCESS_DEFAULT);
  /*buffer += 2;*/

  return sizeof(jsEventType_t)
    +    sizeof(jsClassID_t)
    +    sizeof(jsMethodID_t)
    +    methodNameLength
    +    signatureLength
    +    2;
}
/*
   Contents are: type, ticks, jsThreadId<-threadCounter, jsMethodId, jsObjId,
*/
unsigned short BINARYTRACE_printMethodEnter(char*          buffer,
				       StackEntry*    stackEntry)
{
  jsObjectID_t oid;
  BINARYTRACE_DEBUG(buffer, "METHOD ENTER");

  /* 1. event type */
  prof_fill_EventType(buffer, JavaMethodEntry);
  buffer += sizeof(jsEventType_t);

  /* 2. timestamp of the enter */
  prof_fill_timestamp(buffer, stackEntry->timestamp);
  buffer += sizeof(jsTimestamp_t);

  /* 3. thread id */
  prof_fill_TID(buffer, stackEntry->tps);
  buffer += sizeof(jsThreadID_t);

  /* 4. method id */
  prof_fill_u4(buffer, METHOD_ENTRY(stackEntry->methodHashEntry)->static_id);
  buffer += sizeof(jsMethodID_t);

  /* 5. object id */
  if(stackEntry->objectHashEntry == NULL) {
    oid = NULL_OID;
  }
  else {
    oid = OBJECT_ENTRY(stackEntry->objectHashEntry)->static_id;
  }
  prof_fill_OID(buffer, oid);

#ifdef BINARYTRACE_LINENUMBERED_INVOCATIONS
  buffer += sizeof(jsObjectID_t);

  /* 6. line number */
  prof_fill_u2(buffer, 0); /* NMM FIXME */
  /*buffer += 2;*/
#endif /* BINARYTRACE_LINENUMBERED_INVOCATIONS */

  return
#ifdef BINARYTRACE_LINENUMBERED_INVOCATIONS
    2
#endif /* BINARYTRACE_LINENUMBERED_INVOCATIONS */
    sizeof(jsEventType_t)
    +    sizeof(jsTimestamp_t)
    +    sizeof(jsThreadID_t)
    +    sizeof(jsMethodID_t)
    +    sizeof(jsObjectID_t);
}
unsigned short BINARYTRACE_printMethodExit(char*               buffer,
				      ThreadLocalStorage* tps,
				      timestamp_t         timeJustAfterGotControl)
{
  uint64_t exit_overhead, overheadSoFar, totalInvocationOverhead;
  timestamp_t now;
  BINARYTRACE_DEBUG(buffer, "METHOD EXIT");

  /* 1. event type */
  prof_fill_EventType(buffer, JavaMethodExit);
  buffer += sizeof(jsEventType_t);

  /* 2. timestamp of the exit */
  jvmpiAgent_getCurrentTime(&now);
  prof_fill_timestamp(buffer, now);
  buffer += sizeof(jsTimestamp_t);

  /* 3. overhead compensation */
#ifdef BINARYTRACE_OVERHEAD
  exit_overhead = now-timeJustAfterGotControl;
  overheadSoFar = tps->stackEntry[tps->tos].cumulative_overhead;
  totalInvocationOverhead = overheadSoFar+exit_overhead;
#else
  totalInvocationOverhead = 0;
#endif /* BINARYTRACE_OVERHEAD */
  prof_fill_u8(buffer, totalInvocationOverhead);
  buffer += 8;

  /* 4. thread id */
  prof_fill_TID(buffer, tps);
  /*buffer += sizeof(jsThreadID_t);*/

  return sizeof(jsEventType_t)
    +    sizeof(jsTimestamp_t)
    +    8
    +    sizeof(jsThreadID_t);
}

/*
  Contents are: type, tick, jsObjId, threadName
*/
unsigned short BINARYTRACE_printThreadStart(char*               buffer,
				       ThreadLocalStorage* tps)
{
  unsigned short lengthOfThreadName;

  BINARYTRACE_DEBUG(buffer, "THREAD_START");

  /* 1. event type */
  prof_fill_EventType(buffer, ThreadStart);
  buffer += sizeof(jsEventType_t);

  /* 2. timestamp of thread start */
  prof_fill_current_timestamp(buffer);
  buffer += sizeof(jsTimestamp_t);

  /* 3. thread id */
  prof_fill_TID(buffer, tps);
  buffer += sizeof(jsThreadID_t);

  /* 4. thread name */
  lengthOfThreadName = prof_fill_string(buffer, tps->threadName);
  /* buffer += lengthOfThreadName; */

  return sizeof(jsEventType_t)
    +    sizeof(jsTimestamp_t)
    +    sizeof(jsThreadID_t)
    +    lengthOfThreadName;
}
/* Contents: type, ticks, objectId */
unsigned short BINARYTRACE_printObjectFree(char*      buffer,
				      HashEntry* objectHashEntry)
{
  BINARYTRACE_DEBUG(buffer, "OBJECT FREE");

  prof_fill_EventType(buffer, ObjectFree);
  buffer += sizeof(jsEventType_t);

  prof_fill_current_timestamp(buffer);
  buffer += sizeof(jsTimestamp_t);

  prof_fill_OID(buffer, (unsigned long)(OBJECT_ENTRY(objectHashEntry)->static_id));
  /*buffer += sizeof(jsObjectID_t);*/

  return sizeof(jsEventType_t) + sizeof(jsTimestamp_t) + sizeof(jsObjectID_t);
}
unsigned short
BINARYTRACE_printWitnessedObjectAllocation(char*                 buffer,
				      ThreadPrivateStorage* creatingThread,
				      HashEntry*            objectHashEntry,
				      HashEntry*            classHashEntry,
				      timestamp_t           allocTime)
{
  char* bufferOrig = buffer;
  ObjectEntry* newObject = OBJECT_ENTRY(objectHashEntry);
  BOOL isArray = newObject->is_array != JVMPI_NORMAL_OBJECT;

  /* 1. type of event */
  if(!isArray) {
    prof_fill_EventType(buffer, WitnessedObjectCreation);
  }
  else {
    prof_fill_EventType(buffer, WitnessedArrayCreation);
  }
  buffer += sizeof(jsEventType_t);


  /* 2. time of creation */
  prof_fill_timestamp(buffer, allocTime);
  buffer += sizeof(jsTimestamp_t);

  /* 3. element type, for array objects */
  if(newObject->is_array == JVMPI_CLASS) {
    prof_fill_CID(buffer, CLASS_ENTRY(classHashEntry)->static_id);
    buffer += sizeof(jsClassID_t);
  }
  else if(isArray) {
    prof_fill_u1(buffer, jvmpi_to_jni(newObject->is_array));
    buffer += sizeof(char);
  }

  /* 4. OID */
  prof_fill_OID(buffer, newObject->static_id);
  buffer += sizeof(jsObjectID_t);

  /* 5. CID */
  if(!isArray) {
    prof_fill_CID(buffer, CLASS_ENTRY(classHashEntry)->static_id);
    buffer += sizeof(jsClassID_t);
  }
  else {
    prof_fill_u4(buffer, newObject->size);
    buffer += 4;
  }

  prof_fill_TID(buffer, creatingThread);
  buffer += sizeof(jsThreadID_t);

  return buffer-bufferOrig;
}
/* Contents: type, ticks, jsObjId, jsClsId */
unsigned short BINARYTRACE_printObjectAllocation(char*      buffer,
					    HashEntry* objectHashEntry,
					    HashEntry* classHashEntry)
{
  ObjectEntry* objectEntry = OBJECT_ENTRY(objectHashEntry);
  BINARYTRACE_DEBUG(buffer, "OBJECT ALLOCATION");

  switch(objectEntry->is_array) {
  case JVMPI_NORMAL_OBJECT:
    {
      /* instances */
      prof_fill_EventType(buffer, ObjectFirstSeen);
      buffer += sizeof(jsEventType_t);

      prof_fill_current_timestamp(buffer);
      buffer += sizeof(jsTimestamp_t);

      prof_fill_OID(buffer, objectEntry->static_id);
      buffer += sizeof(jsObjectID_t);

      prof_fill_CID(buffer, CLASS_ENTRY(classHashEntry)->static_id);
      /*buffer += sizeof(jsClassID_t);*/

      return sizeof(jsEventType_t)
	+    sizeof(jsTimestamp_t)
	+    sizeof(jsObjectID_t)
	+    sizeof(jsClassID_t);
    }

  case JVMPI_CLASS:
    {
      /* arrays of objects */
      prof_fill_EventType(buffer, ArrayOfObjectsFirstSeen);
      buffer += sizeof(jsEventType_t);

      prof_fill_current_timestamp(buffer);
      buffer += sizeof(jsTimestamp_t);

      prof_fill_OID(buffer, objectEntry->static_id);
      buffer += sizeof(jsObjectID_t);

      prof_fill_CID(buffer, CLASS_ENTRY(classHashEntry)->static_id);
      buffer += sizeof(jsClassID_t);

      prof_fill_u4(buffer, objectEntry->size);
      /* buffer += 4; */

      return sizeof(jsEventType_t)
	+    sizeof(jsTimestamp_t)
	+    sizeof(jsObjectID_t)
	+    sizeof(jsClassID_t)
	+    4;
    }

  default:
    {
      /* arrays of primitives */
      prof_fill_EventType(buffer, ArrayOfPrimitivesFirstSeen);
      buffer += sizeof(jsEventType_t);

      prof_fill_current_timestamp(buffer);
      buffer += sizeof(jsTimestamp_t);

      prof_fill_u1(buffer, jvmpi_to_jni((char) objectEntry->is_array));
      buffer += 1;

      prof_fill_OID(buffer, objectEntry->static_id);
      buffer += sizeof(jsObjectID_t);
	
      prof_fill_u4(buffer, objectEntry->size);
      /* buffer += 4; */
	
      return sizeof(jsEventType_t)
	+    sizeof(jsTimestamp_t)
	+    1
	+    sizeof(jsObjectID_t)
	+    4;
    }
  }
}

/* Contents: type, tick, jsClsId */
unsigned short BINARYTRACE_printClassUnload(char* buffer,
				       HashEntry* classHashEntry)
{
  BINARYTRACE_DEBUG(buffer, "CLASS UNLOAD");

  prof_fill_EventType(buffer, ClassUnload);
  buffer += sizeof(jsEventType_t);

  prof_fill_current_timestamp(buffer);
  buffer += sizeof(jsTimestamp_t);

  prof_fill_CID(buffer, CLASS_ENTRY(classHashEntry)->static_id);
  /*buffer += sizeof(jsClassID_t);*/

  return sizeof(jsEventType_t)
    +    sizeof(jsTimestamp_t)
    +    sizeof(jsClassID_t);
}
/* Contents: type, ticks, jsThreadId */
unsigned short BINARYTRACE_printThreadEnd(char*               buffer,
				     ThreadLocalStorage* tps)
{
  BINARYTRACE_DEBUG(buffer, "THREAD END");

  prof_fill_EventType(buffer, ThreadExit);
  buffer += sizeof(jsEventType_t);

  prof_fill_current_timestamp(buffer);
  buffer += sizeof(jsTimestamp_t);

  prof_fill_TID(buffer, tps);
  /*buffer += sizeof(jsThreadID_t);*/

  return sizeof(jsEventType_t)
    +    sizeof(jsTimestamp_t)
    +    sizeof(jsThreadID_t);
}
/* Contents: type, tick */
unsigned short BINARYTRACE_printGenericTimestampedEvent(char*         buffer,
						   jsEventType_t event)
{
  prof_fill_EventType(buffer, event);
  buffer += sizeof(jsEventType_t);

  prof_fill_current_timestamp(buffer);
  /* buffer += sizeof(jsTimestamp_t); */

  return sizeof(jsEventType_t)
    +    sizeof(jsTimestamp_t);
}
unsigned short BINARYTRACE_printGcStart(char* buffer)
{
  BINARYTRACE_DEBUG(buffer, "GC START");
  return BINARYTRACE_printGenericTimestampedEvent(buffer, GCStart);
}
unsigned short BINARYTRACE_printGcFinish(char* buffer)
{
  BINARYTRACE_DEBUG(buffer, "GC FINISH");
  return BINARYTRACE_printGenericTimestampedEvent(buffer, GCFinish);
}
BOOL isBigEndian() {
  long i = 0x44332211;
  unsigned char* a = (unsigned char*) &i;
  int end = (*a != 0x11);
  fprintf(stderr, "[Watson: detected %s-endian platform]\n",
	  ((end==1)?"big":"little"));
  return end==1;
}
unsigned short BINARYTRACE_printEndOfXMLHeader(char* buffer)
{
  char* bufferOrig = buffer;

  /* 1. some termination characters, so we know XML header is done */
  prof_fill_u1(buffer, 0xD);
  buffer += 1;
  prof_fill_u1(buffer, 0xE);
  buffer += 1;
  prof_fill_u1(buffer, 0xA);
  buffer += 1;
  prof_fill_u1(buffer, 0xD);
  buffer += 1;

  /* 2. boolean indicating the endianness of this platform */
  prof_fill_boolean(buffer, isBigEndian());
  buffer += sizeof(jsBooleanValue_t);

  /* 3. short indicating the binary trace format version */
  prof_fill_u2(buffer, BINARYTRACE_TRACE_FORMAT_VERSION);
  buffer += 2;

  /* 4. boolean indicating whether enter events will include line
     numbers */
#ifdef BINARYTRACE_LINENUMBERED_INVOCATIONS
  prof_fill_boolean(buffer, TRUE);
#else
  prof_fill_boolean(buffer, FALSE);
#endif /* BINARYTRACE_LINENUMBERED_INVOCATIONS */
  buffer += sizeof(jsBooleanValue_t);

  /* 5. minimum tick count in the trace */
  prof_fill_timestamp(buffer, _startTime);
  buffer += sizeof(jsTimestamp_t);

  /* 6. ticks per microsecond of the tick counts */
  {
    /* at the end of this file */
    prof_fill_u4(buffer, _ticksPerMicrosecond);
    buffer += 4;
  }

  return buffer - bufferOrig;
}
void BINARYTRACE_printTraceHeader(ThreadLocalStorage* tps)
{
  if (!_jvmpiAgent_suspendIO) {
    char* buffer = tps->buffer;
    char* bufferOrig = buffer;

    if (!_jvmpiAgent_Options.standalone) {
      /* jinsight viz expects ACK as first byte when connected live */
      prof_fill_u1(buffer, 1);
      buffer += 1;
    }

    prof_fill_u1(buffer, 'w');
    buffer += 1;

    {
      unsigned short numBytes = buffer - bufferOrig;
      jvmpiAgent_print(tps, tps->buffer, numBytes);
    }
  }
}
void BINARYTRACE_printTraceEnd(ThreadLocalStorage* tps)
{
  char* buffer = tps->buffer;

  prof_fill_EventType(buffer, TraceEnd);
  buffer += sizeof(jsEventType_t);

  prof_fill_u4(buffer, 0xDEAD);
  buffer += 4;

  prof_fill_u4(buffer, 0xDEAD);
  /*buffer += 4;*/

  {
    unsigned short numBytes =
      sizeof(jsEventType_t)
      + 4
      + 4;
    jvmpiAgent_print(tps, tps->buffer, numBytes);
  }
}

void BINARYTRACE_printBOB(ThreadLocalStorage* tps)
{
  char* buffer = tps->buffer;

  prof_fill_EventType(buffer, BOBEvent);
  buffer += sizeof(jsEventType_t);

  prof_fill_current_timestamp(buffer);
  /* buffer += sizeof(jsTimestamp_t); */

  jvmpiAgent_print(tps, tps->buffer, 1+sizeof(jsTimestamp_t));
}
void BINARYTRACE_printEOB(ThreadLocalStorage* tps)
{
  char* buffer = tps->buffer;
  prof_fill_EventType(buffer, EOBEvent);
  buffer += sizeof(jsEventType_t);

  prof_fill_current_timestamp(buffer);
  /* buffer += sizeof(jsTimestamp_t); */

  jvmpiAgent_print(tps, tps->buffer, 1+sizeof(jsTimestamp_t));
}
unsigned short BINARYTRACE_printArrayReference(char* buffer,
					  unsigned long parentOID,
					  unsigned long childOID)
{
   if (TRUE || !_jvmpiAgent_suspendIO) {
    char* bufferOrig = buffer;

    prof_fill_EventType(buffer, ArrayRefs);
    buffer += sizeof(jsEventType_t);

    prof_fill_OID(buffer, parentOID);
    buffer += sizeof(jsObjectID_t);

    prof_fill_u4(buffer, 1);
    buffer += 4;

    prof_fill_OID(buffer, childOID);
    buffer += sizeof(jsObjectID_t);

    return buffer-bufferOrig;
  }

  return 0;
}
unsigned short BINARYTRACE_printClassReference(char* buffer,
					  unsigned long parentCID,
					  unsigned long childOID)
{
  if (!_jvmpiAgent_suspendIO) {
    char* bufferOrig = buffer;

    prof_fill_EventType(buffer, GC_StaticRoot);
    buffer += sizeof(jsEventType_t);

    prof_fill_CID(buffer, parentCID);
    buffer += sizeof(jsClassID_t);

    prof_fill_OID(buffer, childOID);
    buffer += sizeof(jsObjectID_t);

    prof_fill_OID(buffer, NULL_OID);
    buffer += sizeof(jsObjectID_t);

    return buffer-bufferOrig;
  }

  return 0;
}
unsigned short BINARYTRACE_printObjectReference(char* buffer,
					   unsigned long parentOID,
					   unsigned long childOID)
{
  if (!_jvmpiAgent_suspendIO) {
    char* bufferOrig = buffer;

    prof_fill_EventType(buffer, ObjectRefs);
    buffer += sizeof(jsEventType_t);

    prof_fill_OID(buffer, parentOID);
    buffer += sizeof(jsObjectID_t);

    prof_fill_OID(buffer, childOID);
    buffer += sizeof(jsObjectID_t);

    prof_fill_OID(buffer, NULL_OID);
    buffer += sizeof(jsObjectID_t);

    return buffer-bufferOrig;
  }

  return 0;
}
void BINARYTRACE_printGeneration(ThreadLocalStorage* tps)
{
  char* buffer = tps->buffer;
  char* bufferOrig = buffer;

  prof_fill_EventType(buffer, Generation);
  buffer += sizeof(jsEventType_t);

  prof_fill_current_timestamp(buffer);
  buffer += sizeof(jsTimestamp_t);

  jvmpiAgent_print(tps, tps->buffer, buffer-bufferOrig);
}
void BINARYTRACE_printUnknownRoot(ThreadLocalStorage* tps,
			     ObjectEntry*        unknown)
{
  char* buffer     = tps->buffer;
  char* bufferOrig = buffer;

  prof_fill_EventType(buffer, GC_UnknownRoot);
  buffer += sizeof(jsEventType_t);

  prof_fill_OID(buffer, unknown->static_id);
  buffer += sizeof(jsObjectID_t);

  jvmpiAgent_print(tps, tps->buffer, buffer-bufferOrig);
}
void BINARYTRACE_printJNIGlobalRoot(ThreadLocalStorage* tps,
			       ObjectEntry* parent,
			       ObjectEntry* child)
{
  char* buffer     = tps->buffer;
  char* bufferOrig = buffer;

  prof_fill_EventType(buffer, GC_JNI_GlobalRoot);
  buffer += sizeof(jsEventType_t);

  prof_fill_OID(buffer, parent->static_id);
  buffer += sizeof(jsObjectID_t);

  prof_fill_OID(buffer, child->static_id);
  buffer += sizeof(jsObjectID_t);

  jvmpiAgent_print(tps, tps->buffer, buffer-bufferOrig);
}
void BINARYTRACE_printJNILocalRoot(ThreadLocalStorage* tps,
			      ObjectEntry* object,
			      ThreadLocalStorage* localToThisThread,
			      int stackDepth)
{
  char* buffer     = tps->buffer;
  char* bufferOrig = buffer;

  prof_fill_EventType(buffer, GC_JNI_LocalRoot);
  buffer += sizeof(jsEventType_t);

  prof_fill_TID(buffer, localToThisThread);
  buffer += sizeof(jsThreadID_t);

  prof_fill_OID(buffer, object->static_id);
  buffer += sizeof(jsObjectID_t);

  jvmpiAgent_print(tps, tps->buffer, buffer-bufferOrig);
}
void BINARYTRACE_printJavaStackRoot(ThreadLocalStorage* tps,
			       ThreadLocalStorage* rootedToThisThread,
			       ObjectEntry*        object,
			       int                 depth)
{
  char* buffer     = tps->buffer;
  char* bufferOrig = buffer;

  prof_fill_EventType(buffer, GC_JavaStackRoot);
  buffer += sizeof(jsEventType_t);

  prof_fill_TID(buffer, rootedToThisThread);
  buffer += sizeof(jsThreadID_t);

  prof_fill_OID(buffer, object->static_id);
  buffer += sizeof(jsObjectID_t);

  jvmpiAgent_print(tps, tps->buffer, buffer-bufferOrig);
}
void BINARYTRACE_printNativeStackRoot(ThreadLocalStorage* tps,
				 ThreadLocalStorage* rootedToThisThread,
				 ObjectEntry* object)
{
  char* buffer     = tps->buffer;
  char* bufferOrig = buffer;

  prof_fill_EventType(buffer, GC_NativeStackRoot);
  buffer += sizeof(jsEventType_t);

  prof_fill_TID(buffer, rootedToThisThread);
  buffer += sizeof(jsThreadID_t);

  prof_fill_OID(buffer, object->static_id);
  buffer += sizeof(jsObjectID_t);

  jvmpiAgent_print(tps, tps->buffer, buffer-bufferOrig);
}
void BINARYTRACE_printStickyClassRoot(ThreadLocalStorage* tps,
				 ObjectEntry*        clazzObject)
{
  char* buffer     = tps->buffer;
  char* bufferOrig = buffer;

  prof_fill_EventType(buffer, GC_StickyClassRoot);
  buffer += sizeof(jsEventType_t);

  prof_fill_OID(buffer, clazzObject->static_id);
  buffer += sizeof(jsObjectID_t);

  jvmpiAgent_print(tps, tps->buffer, buffer-bufferOrig);
}
void BINARYTRACE_printThreadRoot(ThreadLocalStorage* tps,
			    ThreadLocalStorage* theThread,
			    ObjectEntry*        theThreadObject)
{
  char* buffer     = tps->buffer;
  char* bufferOrig = buffer;

  prof_fill_EventType(buffer, GC_ThreadRoot);
  buffer += sizeof(jsEventType_t);

  prof_fill_TID(buffer, theThread);
  buffer += sizeof(jsThreadID_t);

  prof_fill_OID(buffer, theThreadObject->static_id);
  buffer += sizeof(jsObjectID_t);

  jvmpiAgent_print(tps, tps->buffer, buffer-bufferOrig);
}
void BINARYTRACE_printMonitorRoot(ThreadLocalStorage* tps,
			     ObjectEntry*        monitorObject)
{
  char* buffer     = tps->buffer;
  char* bufferOrig = buffer;

  prof_fill_EventType(buffer, GC_MonitorRoot);
  buffer += sizeof(jsEventType_t);

  prof_fill_OID(buffer, monitorObject->static_id);
  buffer += sizeof(jsObjectID_t);

  jvmpiAgent_print(tps, tps->buffer, buffer-bufferOrig);
}

/* #include "watson_fieldvalues.c" */

#endif /* BINARY_TRACE */
