/* -*- Mode: C; c-file-style:"gnu"; indent-tabs-mode:nil -*-
   runtime.h - Runtime header, containing all external api's to japhar.
   Created: Chris Toshok <toshok@hungry.com>, 24-Oct-1999. */
/*
  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
*/

#ifndef japhar_runtime_h
#define japhar_runtime_h

#include "nspr.h"
#include "plhash.h"
#include "plstr.h"
#include "zipfile.h"

PR_BEGIN_EXTERN_C

/*
 * typedefs to make the rest of this file compile smoothly
 */
typedef struct japhar_object japhar_object;

typedef struct _StackFrame StackFrame;

typedef struct HungryVM HungryVM;
typedef struct HungryEnv HungryEnv;
typedef struct HungryJIT HungryJIT;

typedef struct MethodStruct MethodStruct;
typedef struct FieldStruct FieldStruct;
typedef struct ClazzFile ClazzFile;

typedef void (PR_CALLBACK *ClazzFileFunc)(ClazzFile *cf, void *arg);

typedef union {
  PRUint8        z;
  PRInt8         b;
  PRUint16       c;
  PRInt16        s;
  PRInt32        i;
  PRInt64        j;
  float          f;
  PRFloat64      d;
  japhar_object* l;
} InterpValue;

typedef enum {
  eClasspathEntryUnknown, /* error value -- means not a directory,
                             zip, or jar file */
  eClasspathEntryDirectory,
  eClasspathEntryZIP,
  eClasspathEntryJAR
} HVMClasspathEntryType;

typedef struct {
  HVMClasspathEntryType type;
  char *path;
  struct ZipFile zip; /* used for zip's and jar's */
} HVMClasspathEntry;

typedef struct{
  HVMClasspathEntry *entries;
  int num_entries;
  int alloc_entries;
} HVMClasspath;

typedef void
(PR_CALLBACK *HVMClasspathEntryFunc)(HVMClasspathEntry *entry, void *arg);

#define JSIG_BOOLEAN 'Z'
#define JSIG_BYTE    'B'
#define JSIG_CHAR    'C'
#define JSIG_SHORT   'S'
#define JSIG_INT     'I'
#define JSIG_LONG    'J'
#define JSIG_FLOAT   'F'
#define JSIG_DOUBLE  'D'
#define JSIG_OBJECT  'L'
#define JSIG_ARRAY   '['
#define JSIG_VOID    'V'

#define JSIG_LONG2   'K'
#define JSIG_DOUBLE2 'E'

typedef union HVMSignatureUnion HVMSignature;

typedef enum {
  eSigTagPrimitive,
  eSigTagClass,
  eSigTagMethod,
  eSigTagArray
} HVMSigTag;

typedef struct {
  HVMSigTag tag;
} HVMAnySigStruct;

typedef struct {
  HVMSigTag tag;
  char type;
} HVMPrimitiveSigStruct;

typedef struct {
  HVMSigTag tag;
  char *java_class; /* e.g., java/lang/String */
} HVMClassSigStruct;

typedef struct {
  HVMSigTag tag;
  char *return_type;
  int num_params;
  char *params[256];
} HVMMethodSigStruct;

typedef struct {
  HVMSigTag tag;
  HVMSignature *subtype;
} HVMArraySigStruct;

union HVMSignatureUnion {
  HVMAnySigStruct any;
  HVMPrimitiveSigStruct prim;
  HVMClassSigStruct clazz;
  HVMMethodSigStruct method;
  HVMArraySigStruct array;
};

/************************************************************************
 *
 * VM Startup/Shutdown
 */

/*
 * HVM_VMAllocate/HVM_VMInitialize are called from HVM_StartupVM.
 * they need to be exported since our JNI necessarily does VM startup
 * in two stages.  look in jniinvoc.c - i'd like to hide these
 * functions and make everything nice and happy.  maybe later.
 */
PR_EXTERN( PRBool )
HVM_VMAllocate(HungryVM **p_new_vm, HungryEnv **p_new_env);

PR_EXTERN( PRBool )
HVM_VMInitialize(HungryVM *new_vm, HungryEnv *new_env);

PR_EXTERN( PRBool )
HVM_VMStartup(HungryVM **p_new_vm, HungryEnv **p_new_env);
PR_EXTERN( void )
HVM_VMShutdown(HungryVM *hvm);

PR_EXTERN( void )
HVM_ThreadInit(HungryVM *hvm, HungryEnv *henv,
               PRBool is_primordial,
               char *name,
               japhar_object* threadgroup,
               int priority);
/*
 * Getting/Setting the HungryEnv associated with a native thread
 */
PR_EXTERN( void )
HVM_ThreadSetEnv(HungryEnv *env);
PR_EXTERN( HungryEnv * )
HVM_ThreadGetEnv(void);


/************************************************************************
 *
 * Allocation routines that go through the garbage collector interface.
 */
PR_EXTERN( void* )
HVM_Malloc (PRSize size);

PR_EXTERN( void* )
HVM_Calloc (PRSize nmemb, PRSize size);

PR_EXTERN( void* )
HVM_Realloc (void *ptr, PRSize size);

PR_EXTERN( void )
HVM_Free (void *ptr);

PR_EXTERN( void* )
HVM_Strdup (void *ptr);

/* routines that throw OutOfMemoryError if the allocation fails. */
PR_EXTERN( void* )
jmalloc(HungryEnv *henv, PRSize size);

PR_EXTERN( void* )
jcalloc(HungryEnv *henv, PRSize nmemb, PRSize size);

PR_EXTERN( void )
jfree(HungryEnv *henv, void *ptr);

PR_EXTERN( void* )
jrealloc(HungryEnv *henv, void *ptr, PRSize size);

PR_EXTERN( char* )
jstrdup(HungryEnv *henv, const char *str);


/************************************************************************
 *
 * Object operations
 */
PR_EXTERN( japhar_object* )
HVM_ObjectNew(HungryEnv *henv, ClazzFile* cf);

PR_EXTERN( japhar_object* )
HVM_ObjectClone(HungryEnv *henv, japhar_object* obj);

PR_EXTERN( PRBool )
HVM_ObjectIsInstanceOf(HungryEnv *henv, japhar_object* obj,
                       ClazzFile *cf);

PR_EXTERN( PRBool )
HVM_ObjectIsReference(HungryEnv *henv, japhar_object* obj);

PR_EXTERN( japhar_object* )
HVM_ObjectGetReference(HungryEnv *henv,
                       japhar_object* obj);

PR_EXTERN( void* )
HVM_ObjectGetNativeState(japhar_object* object_ref);

PR_EXTERN( void )
HVM_ObjectSetNativeState(japhar_object* obj, void *native_state);

/************************************************************************
 *
 * Classes
 */
PR_EXTERN( ClazzFile* )
HVM_ClassFind(HungryEnv *henv, const char *class_name);

PR_EXTERN( ClazzFile* )
HVM_ClassDefine(HungryEnv *henv, const PRUint8 *buf, PRUint32 buflen);

PR_EXTERN( ClazzFile* )
HVM_ClassFindLoaded(HungryEnv *henv, char *class_name);

PR_EXTERN( ClazzFile* )
HVM_ClassFindPrimitive(HungryEnv *henv, char *class_name);

PR_EXTERN( japhar_object* )
clazzfile_to_jclass(HungryEnv *henv, ClazzFile* cf);

PR_EXTERN( ClazzFile* )
jclass_to_clazzfile(HungryEnv *henv, japhar_object* cls);

PR_EXTERN( PRBool )
HVM_ClassIsArray(HungryEnv *henv, ClazzFile *cf);

PR_EXTERN( PRBool )
HVM_ClassIsPrimitive(HungryEnv *henv, ClazzFile *cf);

PR_EXTERN( PRBool )
HVM_ClassIsInterface(HungryEnv *henv, ClazzFile *cf);

PR_EXTERN( PRUint32 )
HVM_ClassGetNumLoaded(HungryEnv *henv);

PR_EXTERN( void )
HVM_ClassGetLoaded(HungryEnv *henv, japhar_object **classes);

PR_EXTERN( void )
HVM_ClassForEachLoaded(HungryVM *hvm, ClazzFileFunc func, void *arg);

PR_EXTERN( void )
HVM_ClassDumpLoaded(HungryEnv *henv);


/************************************************************************
 *
 * Method operations
 */
PR_EXTERN( MethodStruct* )
HVM_MethodFind(HungryEnv *henv, ClazzFile *cf,
               const char *name, const char *sig);

PR_EXTERN( MethodStruct* )
HVM_MethodFindStatic(HungryEnv *henv, ClazzFile *cf,
                     const char *name, const char *sig);

PR_EXTERN( InterpValue )
HVM_MethodCallA(HungryEnv *henv, MethodStruct *method,
                japhar_object* obj, InterpValue *args);

PR_EXTERN( InterpValue )
HVM_MethodCallStaticA(HungryEnv *henv,
                      MethodStruct *method, InterpValue *args);

PR_EXTERN( InterpValue )
HVM_MethodCall (HungryEnv *henv, MethodStruct *method,
                japhar_object* obj, ... );

PR_EXTERN( InterpValue )
HVM_MethodCallStatic (HungryEnv *henv,
                      MethodStruct *method,
                      ... );

/************************************************************************
 *
 * Field operations
 */
PR_EXTERN( FieldStruct* )
HVM_FieldFind(HungryEnv *henv, ClazzFile *cf,
              const char *name, const char *sig);

PR_EXTERN( FieldStruct* )
HVM_FieldFindStatic(HungryEnv *henv, ClazzFile *cf,
                    const char *name, const char *sig);

PR_EXTERN( void )
HVM_FieldSet(japhar_object* obj, FieldStruct *field, InterpValue value);

PR_EXTERN( void )
HVM_FieldSetStatic(ClazzFile *clazz, FieldStruct *field, InterpValue value);

PR_EXTERN( void )
HVM_FieldGet(japhar_object* obj, FieldStruct *field, InterpValue *value);

PR_EXTERN( void )
HVM_FieldGetStatic(ClazzFile *clazz, FieldStruct *field, InterpValue *value);

/************************************************************************
 *
 * Array operations
 */
PR_EXTERN( japhar_object* )
HVM_ArrayCreate(HungryEnv *henv, PRUint32 length,
                char *element_classname);

PR_EXTERN( japhar_object* )
HVM_ArrayClone(HungryEnv *henv, japhar_object* array);

PR_EXTERN( japhar_object* )
HVM_ArrayNew(HungryEnv *henv, PRUint32 n_elem,
             ClazzFile *array_type);

PR_EXTERN( japhar_object* )
HVM_ArrayNewMulti (HungryEnv *henv, PRUint32 *n_elems,
                   int dimensions, ClazzFile *);

PR_EXTERN( ClazzFile* )
HVM_ArrayGetElementType(HungryEnv *henv, ClazzFile *array_type);

PR_EXTERN( PRUint32 )
HVM_ArrayGetLength(japhar_object* arrayref);

PR_EXTERN( void* )
HVM_ArrayGetBody(japhar_object* arrayref);


/************************************************************************
 *
 * Classpaths
 */

/* Create a new classpath */
PR_EXTERN( HVMClasspath* )
HVM_ClasspathNew();

/* Add a path to a classpath.  the spec can contain multiple path
   entries, separated by PATH_SEPARATOR (in arch.h) */
PR_EXTERN( PRStatus )
HVM_ClasspathAddPath(HVMClasspath *cp, const char *spec);

/* Remove a path from a classpath.  the spec can contain multiple path
   entries, separated by PATH_SEPARATOR (in arch.h) */
PR_EXTERN( PRStatus )
HVM_ClasspathRemovePath(HVMClasspath *cp, const char *spec);

/* Build a classpath containing all .zip/.jar files in the
   japhar/share directory */
PR_EXTERN( HVMClasspath* )
HVM_ClasspathGetSystemClasspath();

/* Build a classpath from the user's classpath setting -- usually the
   CLASSPATH environment variable */
PR_EXTERN( HVMClasspath* )
HVM_ClasspathGetUserClasspath();

/* add all the entries from cp2 to cp1, returning a pointer to cp1. */
PR_EXTERN( HVMClasspath* )
HVM_ClasspathConcat(HVMClasspath *cp1, HVMClasspath *cp2);

/* call FUNC for each entry in the supplied classpath */
PR_EXTERN( void )
HVM_ClasspathForEachEntry(HVMClasspath *cp,
                          HVMClasspathEntryFunc func,
                          void *arg);

/* convert a classpath to a string.  caller should deallocate with
   PR_DELETE. */
PR_EXTERN( char* )
HVM_ClasspathToString(HVMClasspath *cp);

/* free memory associated with a classpath */
PR_EXTERN( PRStatus )
HVM_ClasspathDestroy(HVMClasspath *cp);


/************************************************************************
 *
 * Exceptions
 */
PR_EXTERN( void )
HVM_ExceptionCleanup(HungryEnv *henv, japhar_object* exception);

PR_EXTERN( void )
HVM_ExceptionPrintBacktrace(HungryEnv *henv, japhar_object* throwable_ref);

PR_EXTERN( void )
HVM_ExceptionFillInBacktraceFromStack(HungryEnv *henv,
                                      japhar_object* throwable_ref);

/*
 * This should be used by all runtime methods to throw an exception.
 * NULL == msg is accepted.
 */
PR_EXTERN( void )
HVM_ExceptionThrow(HungryEnv *henv,
                   const char *exception_name,
                   const char *format, ...);
PR_EXTERN( void )
HVM_ExceptionThrowWithClass(HungryEnv *henv, ClazzFile *cf, const char *msg);
PR_EXTERN( japhar_object* )
HVM_ExceptionCreate(HungryEnv *henv, ClazzFile *cf, const char *msg);
PR_EXTERN( void )
HVM_ExceptionThrowWithStackFrame(HungryEnv *henv, japhar_object* exception,
                                 StackFrame *f);


/************************************************************************
 *
 * Java/C strings
 */
PR_EXTERN( japhar_object* )
HVM_StringFromCString(HungryEnv *henv, const char *str);

PR_EXTERN( char* )
HVM_StringToCString(HungryEnv *henv, japhar_object* jstr);

PR_EXTERN( PRUint32 )
HVM_StringGetLength(HungryEnv *henv, japhar_object* jstr);

PR_EXTERN( PRUint32 )
HVM_StringGetUTFLength(HungryEnv *henv, japhar_object* jstr);

PR_EXTERN( japhar_object* )
HVM_StringGetValue(HungryEnv *henv, japhar_object* jstr);

PR_EXTERN( PRUint32 )
HVM_StringGetOffset(HungryEnv *henv, japhar_object* jstr);

/************************************************************************
 *
 * Signatures
 */

PR_EXTERN( HVMSignature* )
HVM_SigParseFromJavaSig(HungryEnv *henv, char *sig_string);
PR_EXTERN( char* )
HVM_SigFormatPrimitiveTypeToC(HungryEnv *henv, char sig_prim_type);
PR_EXTERN( char* )
HVM_SigFormatReturnTypeToC(HungryEnv *henv, HVMSignature* method_sig);
PR_EXTERN( char* )
HVM_SigFormatToC(HungryEnv *henv, HVMSignature* sig);
PR_EXTERN( char* )
HVM_SigFormatStrToC(HungryEnv *henv, char *sig_str);
PR_EXTERN( char* )
HVM_SigFormatToJavaSig(HungryEnv *henv, HVMSignature* sig);
PR_EXTERN( char* )
HVM_SigFormatToJavaSource(HungryEnv *henv, HVMSignature* sig);
PR_EXTERN( char* )
HVM_SigFormatStrToJavaSource(HungryEnv *henv, char *sig_str);
PR_EXTERN( char* )
HVM_SigFormatStrToNativeName(HungryEnv *henv, char *sig_str);
PR_EXTERN( char* )
HVM_SigFormatToNativeName(HungryEnv *henv, HVMSignature* sig);
PR_EXTERN( char* )
HVM_SigFormatStringToNativeName(HungryEnv *henv, const char *sig_str);
PR_EXTERN( int )
HVM_SigFormatStringToNativeName_buf(HungryEnv *henv, const char *sig_str,
                                    char *buf, int buf_len);
PR_EXTERN( int )
HVM_SigSizeInBytes(HungryEnv *henv, HVMSignature* sig);
PR_EXTERN( int )
HVM_SigSizeInWords(HungryEnv *henv, HVMSignature* sig);
PR_EXTERN( int )
HVM_SigSizeofStrInBytes(char *sig);
PR_EXTERN( int )
HVM_SigSizeofStrInWords(HungryEnv *henv, char *sig);

PR_EXTERN( int )
HVM_SigNumParams(HungryEnv *henv, HVMSignature* sig);
PR_EXTERN( char )
HVM_SigToUnionSelector(HungryEnv *henv, HVMSignature* sig);
PR_EXTERN( char )
HVM_SigStrToUnionSelector(HungryEnv *henv, char *str);
PR_EXTERN( void )
HVM_SigFree(HungryEnv *henv, HVMSignature* sig);

PR_EXTERN( int )
HVM_SigIsVoid(HungryEnv *henv, HVMSignature* sig);
PR_EXTERN( int )
HVM_SigEqualStr(HungryEnv *henv, char *sig1, char *sig2);
PR_EXTERN( int )
HVM_SigEqual(HungryEnv *henv, HVMSignature* sig1, HVMSignature* sig2);

/************************************************************************
 *
 * Garbage Collection
 */
PR_EXTERN( void )
HVM_GCCollect(HungryVM *hvm);

PR_EXTERN( void )
HVM_GCRunFinalizers(HungryVM *hvm);

PR_EXTERN( void )
HVM_GCAddRoot(HungryVM *hvm, japhar_object *root);

PR_EXTERN( void )
HVM_GCRemoveRoot(HungryVM *hvm, japhar_object *root);

PR_EXTERN( PRUint64 )
HVM_GCGetFreeMemory(HungryVM *hvm);

PR_EXTERN( PRUint64 )
HVM_GCGetTotalMemory(HungryVM *hvm);

/************************************************************************
 *
 * Monitors
 */
PR_EXTERN( PRBool )
HVM_MonitorEnter(HungryEnv *henv, japhar_object *obj);

PR_EXTERN( PRBool )
HVM_MonitorExit(HungryEnv *henv, japhar_object *obj);

PR_EXTERN( PRBool )
HVM_MonitorWait(HungryEnv *henv, japhar_object *obj, PRIntervalTime timeout);

PR_EXTERN( PRBool )
HVM_MonitorNotifyOne(HungryEnv *henv, japhar_object *obj);

PR_EXTERN( PRBool )
HVM_MonitorNotifyAll(HungryEnv *henv, japhar_object *obj);

/************************************************************************/

/* some handy #defined classes, just to guard against typos */
#define java_lang_ArithmeticException "java/lang/ArithmeticException"
#define java_lang_ArrayIndexOutOfBoundsException \
        "java/lang/ArrayIndexOutOfBoundsException"
#define java_lang_Class "java/lang/Class"

#define java_lang_ClassCastException "java/lang/ClassCastException"

#define java_lang_ExceptionInInitializerError \
        "java/lang/ExceptionInInitializerError"

#define java_lang_IllegalMonitorStateException \
        "java/lang/IllegalMonitorStateException"

#define java_lang_IncompatibleClassChangeError \
        "java/lang/IncompatibleClassChangeError"

#define java_lang_InternalError          "java/lang/InternalError"
#define java_lang_InstantiationException "java/lang/InstantiationException"

#define java_lang_NoClassDefFoundError "java/lang/NoClassDefFoundError"
#define java_lang_NoSuchFieldException "java/lang/NoSuchFieldException"
#define java_lang_NoSuchMethodError    "java/lang/NoSuchMethodError"
#define java_lang_NullPointerException "java/lang/NullPointerException"
#define java_lang_Object               "java/lang/Object"
#define java_lang_OutOfMemoryError     "java/lang/OutOfMemoryError"
#define java_lang_RuntimeException     "java/lang/RuntimeException"
#define java_lang_String               "java/lang/String"
#define java_lang_System               "java/lang/System"
#define java_lang_Thread               "java/lang/Thread"
#define java_lang_ThreadGroup          "java/lang/ThreadGroup"
#define java_lang_Throwable            "java/lang/Throwable"
#define java_lang_UnsatisfiedLinkError "java/lang/UnsatisfiedLinkError"
#define java_lang_VirtualMachineError  "java/lang/VirtualMachineError"
#define java_lang_ref_Reference        "java/lang/ref/Reference"
#define java_lang_reflect_Constructor  "java/lang/reflect/Constructor"
#define java_lang_reflect_Field        "java/lang/reflect/Field"
#define java_lang_reflect_Method       "java/lang/reflect/Method"

/************************************************************************/

/*
** some handy macros for converting strings.
*/
#define japhar_translate_str(str,from,to) \
do { \
  PRUint32 i; \
 \
  for (i = 0; i < PL_strlen(str); i ++) \
    if (str[i] == (from)) \
      str[i] = (to); \
} while(0)

#define slashes_to_dots(str)        japhar_translate_str (str, '/', '.')
#define dots_to_slashes(str)        japhar_translate_str (str, '.', '/')
#define slashes_to_underscores(str) japhar_translate_str (str, '/', '_')
#define dots_to_underscores(str)    japhar_translate_str (str, '.', '_')

PR_END_EXTERN_C

#endif /* japhar_runtime_h */
