/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode:nil -*-
   sig.c -- signature mangling functions.
   Created: Chris Toshok <toshok@hungry.com>
 */
/*
  This file is part of Japhar, the GNU Virtual Machine for Java Bytecodes.
  Japhar is a project of The Hungry Programmers, GNU, and OryxSoft.

  Copyright (C) 1997, 1998, 1999 The Hungry Programmers

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Library General Public
  License as published by the Free Software Foundation; either
  version 2 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Library General Public License for more details.

  You should have received a copy of the GNU Library General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "runtimeint.h"
#include "arch.h"
#include "compat.h"

extern PRLogModuleInfo* sigLm;

static HVMSignature *sig_parse_internal(HungryEnv *henv, char *sig_string);

static HVMSignature *
sig_parse_primitive(HungryEnv *henv, char *sig_string)
{
  HVMSignature *prim_sig = PR_MALLOC(sizeof(HVMSignature));
  
  prim_sig->any.tag = eSigTagPrimitive;

  prim_sig->prim.type = *sig_string;

  return prim_sig;
}

static HVMSignature *
sig_parse_class(HungryEnv *henv, char *sig_string)
{
  HVMSignature *class_sig = PR_MALLOC(sizeof(HVMSignature));
  char *semicolon;

  class_sig->any.tag = eSigTagClass;

  PR_ASSERT(*sig_string == 'L');
  sig_string ++;

  semicolon = PL_strchr(sig_string, ';');
  
  class_sig->clazz.java_class = 
    PR_MALLOC(sizeof(char) * (semicolon - sig_string) + 1);

  PL_strncpy(class_sig->clazz.java_class,
          sig_string, semicolon - sig_string);

  class_sig->clazz.java_class[ semicolon - sig_string ] = 0;

  return class_sig;
}

static HVMSignature *
sig_parse_method(HungryEnv *henv, char *sig_string)
{
  HVMSignature *method_sig = PR_MALLOC(sizeof(HVMSignature));

  method_sig->any.tag = eSigTagMethod;

  PR_ASSERT(*sig_string == '(');
  sig_string ++;

  method_sig->method.num_params = 0;
    
  while (*sig_string != ')')
    {
      method_sig->method.params [ method_sig->method.num_params ++ ] = sig_string;
      if (*sig_string == '[')
        {
          /* handle array parameter - find the end: if it's L, go
            until we hit the ;.  if it's anything else, stop. */
          while (*sig_string == '[')
            sig_string ++;
        }

      if (*sig_string == 'L')
        {
          /* handle class parameter */
          while (*sig_string != ';')
            sig_string ++;
          sig_string ++; /* skip the ; */
        }
      else
        sig_string ++;
    }

  sig_string ++;

  method_sig->method.return_type = sig_string;

  return method_sig;
}

static HVMSignature *
sig_parse_array(HungryEnv *henv, char *sig_string)
{
  HVMSignature *array_sig = PR_MALLOC(sizeof(HVMSignature));

  array_sig->any.tag = eSigTagArray;

  PR_ASSERT(*sig_string == '[');
  sig_string ++;
  
  array_sig->array.subtype = sig_parse_internal(henv, sig_string);

  return array_sig;
}

static HVMSignature *
sig_parse_internal(HungryEnv *henv, char *sig_string)
{
  switch(*sig_string)
    {
    case '(':
      return sig_parse_method(henv, sig_string);
      break;
    case '[':
      return sig_parse_array(henv, sig_string);
      break;
    case 'L':
      return sig_parse_class(henv, sig_string);
      break;
    default:
      return sig_parse_primitive(henv, sig_string);      
      break;
    }
}

PR_IMPLEMENT(HVMSignature*)
HVM_SigParseFromJavaSig(HungryEnv *henv, char *sig_string)
{
  char *foo = sig_string;

  return sig_parse_internal(henv, foo);
}

PR_IMPLEMENT(char*)
HVM_SigFormatReturnTypeToC(HungryEnv *henv, HVMSignature *sig)
{
  PR_ASSERT(sig->any.tag == eSigTagMethod);
  return HVM_SigFormatStrToC(henv, sig->method.return_type);
}

static char *
sig_format_method_to_c(HungryEnv *henv, HVMSignature *sig)
{
  static char working_string[1024];
  int i;
  
  PL_strcpy(working_string, "(");

  for (i = 0; i < sig->method.num_params; i ++)
    {
      PL_strcat(working_string, HVM_SigFormatStrToC(henv, sig->method.params[i]));
      if (i < sig->method.num_params - 1)
        PL_strcat (working_string, ", ");
    }

  PL_strcat(working_string, ")");

  return working_string;
}

static char *
sig_format_method_str_to_c(HungryEnv *henv, char *sig_str)
{
  static char working_string[1024];

#if 0
  int i;
  
  PL_strcpy(working_string, "(");

  for (i = 0; i < sig->method.num_params; i ++)
    {
      strcat(working_string, HVM_SigFormatStrToC(henv, sig->method.params[i]));
      if (i < sig->method.num_params - 1)
        strcat (working_string, ", ");
    }

  strcat(working_string, ")");
#endif

  return working_string;
}

static char *
sig_format_array_to_c(HungryEnv *henv, HVMSignature *sig)
{
  switch (sig->array.subtype->any.tag)
    {
    case eSigTagPrimitive:
      switch (sig->array.subtype->prim.type)
        {
        case JSIG_INT:
          return "jintArray";
          break;
        case JSIG_LONG:
          return "jlongArray";
          break;
        case JSIG_DOUBLE:
          return "jdoubleArray";
          break;
        case JSIG_SHORT:
          return "jshortArray";
          break;
        case JSIG_BYTE:
          return "jbyteArray";
          break;
        case JSIG_CHAR:
          return "jcharArray";
          break;
        case JSIG_BOOLEAN:
        case JSIG_FLOAT:
        case JSIG_OBJECT:
        case JSIG_VOID:
          {
            HVM_ExceptionThrow(henv, java_lang_RuntimeException,
                            "sig.c/sig_format_array_to_c()[1]");
            return NULL;
          }
        default:
          PR_ASSERT(0);
          break;
        }
    case eSigTagArray:
    case eSigTagClass:
      return "jobjectArray";
    case eSigTagMethod:
      {
        HVM_ExceptionThrow(henv, java_lang_RuntimeException,
                        "sig.c/sig_format_array_to_c()[2]");
        return NULL;
      }
    default:
      PR_ASSERT(0);
      break;
    }

  return NULL;
}

static char *
sig_format_array_str_to_c(HungryEnv *henv, char *sig_str)
{
  sig_str ++;
  switch (*sig_str)
    {
    case 'I':
      return "jintArray";
    case 'J':
      return "jlongArray";
    case 'D':
      return "jdoubleArray";
    case 'S':
      return "jshortArray";
    case 'B':
      return "jbyteArray";
    case 'C':
      return "jcharArray";
    case 'L':
    case '[':
      return "jobjectArray";
    default:
      return "jarray";
    }
}

PR_IMPLEMENT(char*)
HVM_SigFormatPrimitiveTypeToC(HungryEnv *henv, char sig_prim_type)
{
  switch(sig_prim_type)
    {
    case JSIG_BYTE:
      return "jbyte";
      break;
    case JSIG_CHAR:
      return "jchar"; /* ? */
      break;
    case JSIG_SHORT:
      return "jshort";
      break;
    case JSIG_BOOLEAN:
      return "jboolean";
      break;
    case JSIG_FLOAT:
      return "jfloat";
      break;
    case JSIG_INT:
      return "jint";
      break;
    case JSIG_LONG:
      return "jlong";
      break;
    case JSIG_DOUBLE:
      return "jdouble";
      break;
    case JSIG_VOID:
      return "void";
      break;
    case JSIG_OBJECT:
      return "jobject";
      break;
    default:
      fprintf (stderr, "unhandled case -- yell at toshok\n");
      exit(1);
    }
}


PR_IMPLEMENT(char*)
HVM_SigFormatPrimitiveTypeStrToC(HungryEnv *henv, char *sig_str)
{
  switch(*sig_str)
    {
    case 'B':
      return "jbyte";
      break;
    case 'C':
      return "jchar"; /* ? */
      break;
    case 'S':
      return "jshort";
      break;
    case 'Z':
      return "jboolean";
      break;
    case 'F':
      return "jfloat";
      break;
    case 'I':
      return "jint";
      break;
    case 'J':
      return "jlong";
      break;
    case 'D':
      return "jdouble";
      break;
    case 'V':
      return "void";
      break;
    case 'L':
      return "jobject";
      break;
    default:
      fprintf (stderr, "unhandled case -- yell at toshok\n");
      exit(1);
    }
}


static char *
sig_format_class_to_c(HungryEnv *henv, HVMSignature *sig)
{
  if (!PL_strcmp(sig->clazz.java_class, java_lang_String))
    return "jstring";
  else
    return "jobject";
}

static char *
sig_format_class_str_to_c(HungryEnv *henv, char *sig_str)
{
  if (!PL_strcmp(sig_str, "Ljava/lang/String;"))
    return "jstring";
  else
    return "jobject";
}

PR_IMPLEMENT(char*)
HVM_SigFormatStrToC(HungryEnv *henv, char *sig_str)
{
  switch (*sig_str)
    {
    case '(':
      return sig_format_method_str_to_c(henv, sig_str);
    case '[':
      return sig_format_array_str_to_c(henv, sig_str);
    case 'L':
      return sig_format_class_str_to_c(henv, sig_str);
    default:
      return HVM_SigFormatPrimitiveTypeStrToC(henv, sig_str);
    }
}

PR_IMPLEMENT(char*)
HVM_SigFormatToC(HungryEnv *henv, HVMSignature *sig)
{
  switch(sig->any.tag)
    {
    case eSigTagMethod:
      return sig_format_method_to_c(henv, sig);
      break;
    case eSigTagArray:
      return sig_format_array_to_c(henv, sig);
      break;
    case eSigTagClass:
      return sig_format_class_to_c(henv, sig);
      break;
    case eSigTagPrimitive:
      return HVM_SigFormatPrimitiveTypeToC(henv, sig->prim.type);
      break;
    }

  {
    HVM_ExceptionThrow(henv, java_lang_RuntimeException,
                       "sig.c/HVM_SigFormatToC()");
    return NULL;
  }
}


PR_IMPLEMENT(char*)
HVM_SigFormatToJavaSig(HungryEnv *henv, HVMSignature *sig)
{
  char buf[2000];

  switch (sig->any.tag)
    {
    case eSigTagClass:
      {
        PR_snprintf(buf, 2000, "L%s;", sig->clazz.java_class);
        break;
      }
    case eSigTagPrimitive:
      {
        switch (sig->prim.type)
          {
          case JSIG_BOOLEAN:
            PL_strcpy(buf, "Z");
            break;
          case JSIG_BYTE:
            PL_strcpy(buf, "B");
            break;
          case JSIG_CHAR:
            PL_strcpy(buf, "C");
            break;
          case JSIG_SHORT:
            PL_strcpy(buf, "S");
            break;
          case JSIG_INT:
            PL_strcpy(buf, "I");
            break;
          case JSIG_FLOAT:
            PL_strcpy(buf, "F");
            break;
          case JSIG_DOUBLE:
            PL_strcpy(buf, "D");
            break;
          case JSIG_LONG:
            PL_strcpy(buf, "J");
            break;
          case JSIG_VOID:
            PL_strcpy(buf, "V");
            break;
          case JSIG_OBJECT:
            abort();
            break;
          default:
            PR_ASSERT(0);
            break;
          }
        break;
      }
    case eSigTagArray:
      {
        PL_strcpy(buf, "[");
        PL_strcat(buf, HVM_SigFormatToJavaSig(henv, sig->array.subtype));
        break;
      }
    case eSigTagMethod:
      {
#if 0
        int i;
        PL_strcpy(buf, "(");
        for (i = 0; i < sig->method.num_params; i ++)
          strcat(buf, HVM_SigFormatStrToJavaSig(henv, sig->method.params[i]));
        strcat(buf, ")");
        strcat(buf, HVM_SigFormatStrToJavaSig(henv, sig->method.return_type));
#endif
        break;
      }
    }

  return PL_strdup(buf);
}

PR_IMPLEMENT(char*)
HVM_SigFormatToStrJavaSig(HungryEnv *henv, char *sig_str)
{
  return PL_strdup(sig_str);
}

PR_IMPLEMENT(char*)
HVM_SigFormatToJavaSource(HungryEnv *henv, HVMSignature *sig)
{
  char buf[2000];

  switch (sig->any.tag)
    {
    case eSigTagClass:
      {
        PR_snprintf(buf, sizeof(buf), "%s", sig->clazz.java_class);
        slashes_to_dots(buf);
        break;
      }
    case eSigTagPrimitive:
      {
        switch (sig->prim.type)
          {
          case JSIG_BOOLEAN:
            PL_strcpy(buf, "boolean");
            break;
          case JSIG_BYTE:
            PL_strcpy(buf, "byte");
            break;
          case JSIG_CHAR:
            PL_strcpy(buf, "char");
            break;
          case JSIG_SHORT:
            PL_strcpy(buf, "short");
            break;
          case JSIG_INT:
            PL_strcpy(buf, "int");
            break;
          case JSIG_FLOAT:
            PL_strcpy(buf, "float");
            break;
          case JSIG_DOUBLE:
            PL_strcpy(buf, "double");
            break;
          case JSIG_LONG:
            PL_strcpy(buf, "long");
            break;
          case JSIG_VOID:
            PL_strcpy(buf, "void");
            break;
          case JSIG_OBJECT:
            abort();
            break;
          default:
            PR_ASSERT(0);
            break;
          }
        break;
      }
    case eSigTagArray:
      {
        PL_strcpy(buf, HVM_SigFormatToJavaSource(henv, sig->array.subtype));
        PL_strcat(buf, "[]");
        break;
      }
    case eSigTagMethod:
      {
#if 0
        int i;
        PL_strcpy(buf, "(");
        for (i = 0; i < sig->method.num_params; i ++)
          PL_strcat(buf, HVM_SigFormatToJavaSource(henv, sig->method.params[i]));
        PL_strcat(buf, ")");
        PL_strcat(buf, HVM_SigFormatToJavaSource(henv, sig->method.return_type));
        break;
#endif
      }
    }

  return PL_strdup(buf);
}

PR_IMPLEMENT(int)
HVM_SigFormatStringToNativeName_buf(HungryEnv *henv, const char *sig_str, char *buf, int buf_len)
{
  PRUint32 i;
  int j;

  j = 0;
  buf[0] = 0;
  for (i = 0; i < PL_strlen(sig_str); i ++)
    {
      if (sig_str[i] == '/')
        {
          buf[j++] = '_';
          if (j == buf_len)
            return -1;
          buf[j] = 0;
        }
      else if (sig_str[i] == '_')
        {
          if (buf_len - 3 == j)
            return -1;
          PL_strcat(buf, "_1");
          j += 2;
        }
      else if (sig_str[i] == ';')
        {
          if (buf_len - 3 == j)
            return -1;
          PL_strcat(buf, "_2");
          j += 2;
        }
      else if (sig_str[i] == '[')
        {
          if (buf_len - 3 == j)
            return -1;
          PL_strcat(buf, "_3");
          j += 2;
        }
      else if (isalnum(sig_str[i]))
        {
          buf[j++] = sig_str[i];
          if (j == buf_len)
            return -1;
          buf[j] = 0;
        }
      else if (sig_str[i] == '(')
        {
          continue;
        }
      else if (sig_str[i] == ')')
        {
          break; /* XXX */
        }
      else
        {
          char buf3[7];
          if (buf_len - j == 6)
            return -1;
          sprintf(buf3, "_%05X", sig_str[i]);
          PL_strcat(buf, buf3);
          j += 6;
        }
    }
  
  buf[j++] = 0;
  return 0;
}

PR_IMPLEMENT(char*)
HVM_SigFormatStringToNativeName(HungryEnv *henv, const char *sig_str)
{
  char buf2[1000];

  HVM_SigFormatStringToNativeName_buf(henv, sig_str, buf2, sizeof(buf2));
  return PL_strdup(buf2);
}

PR_IMPLEMENT(char*)
HVM_SigFormatToNativeName(HungryEnv *henv, HVMSignature *sig)
{
  char buf[2000];
  int i;

  switch (sig->any.tag)
    {
    case eSigTagMethod:
      {
        buf[0] = 0;
        
        for (i = 0; i < sig->method.num_params; i ++)
          {
            char *param_sig = HVM_SigFormatStrToNativeName(henv,
                                                           sig->method.params[i]);

            PL_strcat(buf, param_sig);
            PR_DELETE(param_sig);
          }
        break;
      }
    case eSigTagPrimitive:
      return HVM_SigFormatToJavaSig(henv, sig);
      break;
    case eSigTagClass:
      {
        char *hacked_class;

        hacked_class = HVM_SigFormatStringToNativeName(henv, sig->clazz.java_class);

        PR_snprintf(buf, sizeof(buf), "L%s_2", hacked_class);

        PR_DELETE(hacked_class);
      }
      break;
    case eSigTagArray:
      {
        char *subtype = HVM_SigFormatToNativeName(henv, sig->array.subtype);
        PR_snprintf(buf, sizeof(buf), "_3%s", subtype);
        PR_DELETE(subtype);
      }
      break;
    }

  return PL_strdup(buf);
}

PR_IMPLEMENT(char*)
HVM_SigFormatStrToNativeName(HungryEnv *henv, char *sig_str)
{
  char buf[2000];

  switch (*sig_str)
    {
    case '(':
      {
        buf[0] = 0;

        sig_str ++;
        while (*sig_str != ')')
          {
            char *param_sig = HVM_SigFormatStrToNativeName(henv, sig_str);

            switch(*sig_str)
              {
              case '[':
                /* handle array parameter - find the end: if it's L, go
                   until we hit the ;.  if it's anything else, stop. */
                while (*sig_str == '[')
                  sig_str ++;
                
                if (*sig_str == 'L')
                  {
                    while (*sig_str != ';')
                      sig_str ++;
                    sig_str ++; /* skip the ; */
                  }
                else
                  sig_str ++;
                break;
              case 'L':
                /* handle class parameter */
                while (*sig_str != ';')
                  sig_str ++;
                sig_str ++; /* skip the ; */
                break;
              default:
                sig_str++;
                break;
              }

            PR_DELETE(param_sig);
          }
        break;
      }
    case 'L':
      {
        char *hacked_class;
        hacked_class = HVM_SigFormatStringToNativeName(henv, sig_str + 1);
        PR_snprintf(buf, sizeof(buf), "L%s_2", hacked_class);
        PR_DELETE(hacked_class);
        break;
      }
    case '[':
      {
        char *subtype = HVM_SigFormatStrToNativeName(henv, sig_str + 1);
        PR_snprintf(buf, sizeof(buf), "_3%s", subtype);
        PR_DELETE(subtype);
        break;
      }
    default:
      buf[0] = *sig_str;
      buf[1] = 0;
      break;
    }

  return PL_strdup(buf);
}


PR_IMPLEMENT(int)
HVM_SigSizeInBytes(HungryEnv *henv, HVMSignature *sig)
{
  switch (sig->any.tag)
    {
    case eSigTagPrimitive:
      switch (sig->prim.type)
        {
        case JSIG_BYTE:
        case JSIG_CHAR:
        case JSIG_SHORT:
        case JSIG_INT:
        case JSIG_BOOLEAN:
        case JSIG_FLOAT:
          return 4;
          break;
        case JSIG_DOUBLE:
        case JSIG_LONG:
          return 8;
          break;
        case JSIG_OBJECT:
          return 4;
          break;
        case JSIG_VOID:
          return 0;
          break;
        default:
          PR_ASSERT(0);
        }
    case eSigTagClass:
      return 4;
    case eSigTagMethod:
      PR_LOG(sigLm, PR_LOG_DEBUG,
             ("trying to take the size of a method. this is wrong.\n"));
      return 4;
    case eSigTagArray:
      return 4;
    }

  return 0; /* keep cc happy */
}

PR_IMPLEMENT(int)
HVM_SigSizeofStrInBytes(char *sig)
{
  switch (*sig)
    {
    case 'B':
      return sizeof(PRInt8);
    case 'C':
      return sizeof(PRUint16);
    case 'S':
      return sizeof(PRInt16);
    case 'I':
      return sizeof(PRInt32);
    case 'Z':
      return sizeof(PRUint8);
    case 'F':
      return sizeof(float);
    case 'L':
    case '[':
      return sizeof(japhar_object*);
    case 'D':
      return sizeof(PRFloat64);
    case 'J':
      return sizeof(PRInt64);
    case 'V':
      return 0;
    default:
      printf ("%c is not a valid sig type\n", *sig);
      PR_ASSERT(0);
      return 0; /* keep cc happy */
    }
}

PR_IMPLEMENT(int)
HVM_SigSizeofStrInWords(HungryEnv *henv, char *sig)
{
  switch (*sig)
    {
    case 'B':
    case 'C':
    case 'S':
    case 'I':
    case 'Z':
    case 'F':
    case 'L':
    case '[':
      return 1;
    case 'D':
    case 'J':
      return 2;
    case 'V':
      return 0;
    default:
      printf ("%c is not a valid sig type\n", *sig);
      PR_ASSERT(0);
      return 0; /* keep cc happy */
    }
}

PR_IMPLEMENT(int)
HVM_SigSizeInWords(HungryEnv *henv, HVMSignature *sig)
{
  switch (sig->any.tag)
    {
    case eSigTagPrimitive:
      switch (sig->prim.type)
        {
        case JSIG_BYTE:
        case JSIG_CHAR:
        case JSIG_SHORT:
        case JSIG_INT:
        case JSIG_BOOLEAN:
        case JSIG_FLOAT:
          return 1;
          break;
        case JSIG_DOUBLE:
        case JSIG_LONG:
          return 2;
          break;
        case JSIG_OBJECT:
          return 1;
          break;
        case JSIG_VOID:
          return 0;
          break;
        default:
          PR_ASSERT(0);
        }
    case eSigTagClass:
      return 1;
    case eSigTagMethod:
      PR_LOG(sigLm, PR_LOG_DEBUG,
             ("trying to take the size of a method. this is wrong.\n"));
      return 1;
    case eSigTagArray:
      return 1;
    }

  return 0; /* keep cc happy */
}

PR_IMPLEMENT(int)
HVM_SigNumParams(HungryEnv *henv, HVMSignature *sig)
{
  PR_ASSERT(sig->any.tag == eSigTagMethod);

  return sig->method.num_params;
}

static void
sig_free_primitive(HungryEnv *henv, HVMSignature *sig)
{
  PR_DELETE(sig);
}

static void
sig_free_class(HungryEnv *henv, HVMSignature *sig)
{
  PR_DELETE(sig->clazz.java_class);
  PR_DELETE(sig);
}

static void
sig_free_method(HungryEnv *henv, HVMSignature *sig)
{
  PR_DELETE(sig);
}

static void
sig_free_array(HungryEnv *henv, HVMSignature *sig)
{
  HVM_SigFree(henv, sig->array.subtype);
  PR_DELETE(sig);
}

PR_IMPLEMENT(void)
HVM_SigFree(HungryEnv *henv, HVMSignature *sig)
{
  switch (sig->any.tag)
    {
    case eSigTagPrimitive:
      sig_free_primitive(henv, sig);
      break;
    case eSigTagClass:
      sig_free_class(henv, sig);
      break;
    case eSigTagMethod:
      sig_free_method(henv, sig);
      break;
    case eSigTagArray:
      sig_free_array(henv, sig);
      break;
    }
}

PR_IMPLEMENT(int) 
HVM_SigIsVoid(HungryEnv *henv, HVMSignature *sig)
{
  if (sig->any.tag != eSigTagPrimitive)
    return 0;

  if (sig->prim.type != JSIG_VOID)
    return 0;

  return 1;
}

PR_IMPLEMENT(int)
HVM_SigEqualStr(HungryEnv *henv, char *sig1, char *sig2)
{
  if (*sig1 == '[')
    {
      /* XX This must be implemented. */
      HVM_ExceptionThrow(henv, java_lang_InternalError,
                            "HVM_SigEqualStr(array, ...) unimplemented");
      return 0;
    }
  else if (*sig1 == 'L')
    {
      while (*sig1 != ';')
        {
          if (*sig1 != *sig2)
            return 0;

          sig1 ++;
          sig2 ++;
        }

      return 1;
    }
  else
    return *sig1 == *sig2;
}

PR_IMPLEMENT(int)
HVM_SigEqual(HungryEnv *henv, HVMSignature *sig1, HVMSignature *sig2)
{
  if (sig1->any.tag != sig2->any.tag)
    return 0;
  
  switch (sig1->any.tag)
    {
    case eSigTagPrimitive:
      return sig1->prim.type == sig2->prim.type;
      break;
    case eSigTagClass:
      return !PL_strcmp(sig1->clazz.java_class, sig2->clazz.java_class);
      break;
    case eSigTagArray:
      return HVM_SigEqual(henv, sig1->array.subtype, sig2->array.subtype);
      break;
    case eSigTagMethod:
      {
        int i;
                
        if (sig1->method.num_params != sig2->method.num_params)
          return 0;
        if (!HVM_SigEqualStr(henv, sig1->method.return_type, sig2->method.return_type))
          return 0;
                
        for (i = 0; i < sig1->method.num_params; i ++)
          if (!HVM_SigEqualStr(henv, sig1->method.params[i], sig2->method.params[i]))
            return 0;
                
        return 1;
      }
    default:
      PR_ASSERT(0);
      return 0;
    }
}

PR_IMPLEMENT(char)
HVM_SigStrToUnionSelector(HungryEnv *henv, char *str)
{
  switch (*str)
    {
    case JSIG_BOOLEAN:
    case JSIG_INT:
      return 'i';
      break;
    case JSIG_SHORT:
      return 's';
      break;
    case JSIG_CHAR:
      return 'c';
      break;
    case JSIG_BYTE:
      return 'b';
      break;
    case JSIG_FLOAT:
      return 'f';
      break;
    case JSIG_LONG:
      return 'j';
      break;
    case JSIG_DOUBLE:
      return 'd';
      break;
    case JSIG_OBJECT:
      return 'l';
      break;
    case JSIG_ARRAY:
      return 'l';
      break;
    }

  return 0; /* keep cc happy */
}

PR_IMPLEMENT(char)
HVM_SigToUnionSelector(HungryEnv *henv, HVMSignature *sig)
{
  switch (sig->any.tag)
    {
    case eSigTagPrimitive:
      switch(sig->prim.type)
        {
        case JSIG_BOOLEAN:
        case JSIG_INT:
          return 'i';
          break;
        case JSIG_SHORT:
          return 's';
          break;
        case JSIG_CHAR:
          return 'c';
          break;
        case JSIG_BYTE:
          return 'b';
          break;
        case JSIG_FLOAT:
          return 'f';
          break;
        case JSIG_LONG:
          return 'j';
          break;
        case JSIG_DOUBLE:
          return 'd';
          break;
        case JSIG_OBJECT:
          return 'l';
          break;
        default:
          PR_ASSERT(0);
        }
    case eSigTagClass:
    case eSigTagArray:
      return 'l';
      break;
    case eSigTagMethod:
      fprintf (stderr, "error... methods don't have a union selector\n");
      exit(1);
      break;
    }

  return 0; /* keep cc happy */
}
