/* -*- Mode: C; c-file-style:"gnu"; indent-tabs-mode:nil -*-
   runtimeint.h - All private api calls.
   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_runtimeint_h
#define japhar_runtimeint_h

#include "nspr.h"
#include "plhash.h"
#include "ClazzFile.h"
#include "runtime.h"

#if WITH_SPORTSMODEL
#include "smobj.h"
#endif

PR_BEGIN_EXTERN_C

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

/* data associated with all thrown exceptions (using the
   HVM_*ObjectState interface) */
typedef struct BackTraceLevel {
  char *classname;
  MethodStruct *method;
  char *filename;
  PRUint16 pc;
  struct BackTraceLevel *prev;
  struct BackTraceLevel *next;
} BackTraceLevel;

typedef struct {
  BackTraceLevel *head;
  BackTraceLevel *tail;
} ExceptionInfo;

/*
 * Interpreter-loop level structures and calls.
 */
typedef struct {
  char tag;
  InterpValue value;
} JavaStackItem;

typedef struct {
  void **stack_bottom;
  void **stack_top;
  void **high_water;
} OpStack;

struct HungryVM {
  /* backpointer used to store the JavaVM, if we're compiled to use JNI */
  void*               vm;

  /* the version of JNI used for this JavaVM */
  PRInt32               _version;

  /* queue pointers */
  HungryVM*             next;
  HungryVM*             prev;

  PRMonitor*            _mon;

  /* used by the garbage collector */
  PLHashTable*          _roots;

  /* a hook for a function that redirects all VM messages. */
  PRInt32 (*vfprintf)(FILE *fp, const char *format, va_list args);
  void (*exit)(PRInt32 code);   /* a VM exit hook. */
  void (*abort)(void);          /* a VM abort hook. */

  char                  *_classpath;
  HVMClasspath          *_cp;

  PLHashTable           *_loaded_classes;

  PRBool                _finalizers_on_exit;
  HungryEnv             *_envs;
  HungryEnv             *_initial_env;

#define VERBOSE_JNI     0x01
#define VERBOSE_CLASS   0x02
#define VERBOSE_GC      0x04
#define VERBOSE_METHOD  0x08
#define VERBOSE_DLL     0x10
  PRUint32              _verbose_flags;
};

struct HungryEnv {
  HungryEnv *prev;
  HungryEnv *next;

  /* the thread's name */
  char *                name;

  /* backpointer to the vm */
  HungryVM*             vm;

  /* backpointer used to store the JNIEnv, if we're compiled to use JNI */
  void*               thread_env;

  /* back pointer to our thread. */
  PRThread*             thread_id;

  /* our current exception. */
  japhar_object*        _exception;

  /* the jit state. */
  HungryJIT             *_jit;

  /* A reference to the java thread which represents
     this native thread. */
  japhar_object* java_thread;

  /* the highest address possible for this thread's stack. */
  StackFrame* stack_highwater;
  /* the lowest address -- the address where the thread stack is
     allocated. We use this to check for depth == 0 */
  StackFrame* stack_lowwater;

  StackFrame* top_frame;

  OpStack *op_stack; /* this thread's operand stack */

  JavaStackItem return_value;
  PRUint32 current_state;  /* whether we're suspended, running, etc, etc. */
};

/* possible thread state settings */
#define STATE_RUNNING           0x00
#define STATE_INTERRUPTED       0x01
#define STATE_SUSPENDED         0x02
#define STATE_FINISHED          0x03

#define FRAME_NATIVE            0x01
#define FRAME_HASCLASSLOADER    0x02

struct _StackFrame {
  struct _StackFrame    *parent;
  int depth;

  unsigned char flags;

  MethodStruct  *method;
  HungryEnv             *_env;

  int                   pc;

  void**                opstack_top;

  japhar_object*        this_pointer;
  JavaStackItem vars[1];
};

/*
 * Objects are layed out in the following way (on a 32 bit machine):
 *
 *       +0 / object's hashcode           /
 *       +4 / object's native state       /
 *       +8 / object's ClazzFile*         /
 *          / fields for java.lang.Object / packed and aligned properly.
 *          / fields for subclass         /
 *                          ..
 *          / fields for deepest subclass /
 *
 * fields are layed on in parent class-subclass order, so the offset
 * for java.lang.Object fields are lower (at a lower offset) than
 * those for java.lang.String.
 *
 * Also, the addition of the hashcode field permits the use of copying
 * collectors.  The first time the object is asked for its hashcode,
 * it calculates it (from it's address) and stores it in that field.
 * from that point on it just returns it, regardless of it's address.
 *
 */

struct japhar_object {
#if WITH_SPORTSMODEL
  SMObjStruct super;
#endif
  PRInt32 hash_code;
  void *native_state;

  ClazzFile *clazz;

  char fields; /* isn't really a char -- we use a pointer to this to
                  actually get at the fields. */
};

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

/*
 * Routines and information about "fake" array classes
 */
#define ARRAY_LENGTH_INDEX      0
#define ARRAY_TYPE_INDEX        1
#define ARRAY_BODY_INDEX        2
#define ARRAY_ELSIZE_INDEX      3

ClazzFile* createFakeArrayClass(HungryEnv *env, const char *class_name);
ClazzFile* createFakeArrayRemoveDimension(HungryEnv *env, ClazzFile* array);


/*
 * Useful routine for converting a japhar_object array to an InterpValue array
 */
InterpValue *objects_to_values(HungryEnv *henv, japhar_object* jarr);


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

/*
 * Internal Exception stuff
 */

void toplevel_exception_handler(HungryEnv *henv, japhar_object* throwable_ref);

int method_pc_to_line_number(HungryEnv *henv, MethodStruct *method,
                             PRUint16 pc);

/* in abort.c:  used to offer a java stacktrace on fatal signals. */
void fatal_signal_handler(int);
void abort(void);
void abort_with_message(const char *msg);


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

void suspend_thread(japhar_object* obj, HungryEnv *henv);
void resume_thread(japhar_object* obj, HungryEnv *henv);

StackFrame *create_frame_for_method(HungryEnv *henv, MethodStruct *info);
void destroy_frame (StackFrame *f);

void fill_local_vars_from_stack (StackFrame *df, /* destination frame */
                                 int num_words_needed,
                                 int static_p); /* is this a static call? */
void fill_local_vars (StackFrame *df, /* destinatin frame */
                      MethodStruct *method,
                      InterpValue *args, /* must match the number in
                                            the signature. */
                      japhar_object* obj); /* NULL for a static call. */

StackFrame* push_frame(HungryEnv *henv, int num_vars);
void pop_frame(HungryEnv *henv);

void do_native_method_call(HungryEnv *henv, MethodStruct *);

void interp_loop(StackFrame *current_frame);

void push_item_from_constant_pool (StackFrame *f, int index);


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

/*
 * internal method related calls
 */
void do_method_call (StackFrame *this_frame, MethodStruct *method);

void maybe_enter_monitor_for_method(HungryEnv *henv,
                                    MethodStruct *method,
                                    japhar_object* this_obj);
void maybe_exit_monitor_for_method(HungryEnv *henv,
                                   MethodStruct *method,
                                   japhar_object* this_obj);

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

/*
 * Classes
 */
ClazzFile* find_class_on_classpath(HungryEnv *henv,
                                   const char *dotted_class_name,
                                   const char *class_name,
                                   HVMClasspath *classpath);

void initialize_system_classloader(HungryVM *hvm);
void destroy_system_classloader(HungryVM *hvm);

void add_loaded_class(HungryEnv *henv, ClazzFile *classfile);
void delete_loaded_class(HungryEnv *henv, char *name);

void initialize_class(HungryEnv *henv, ClazzFile* cf);
void calculate_instance_field_offsets(HungryEnv *henv, ClazzFile *cf);

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

/*
 * internal garbage collector calls
 */

void init_collector(HungryVM *hvm);
void shutdown_collector(HungryVM *hvm, PRBool finalize);
PRSize object_size_without_fields(void);
japhar_object* HVM_GCAllocObject(HungryEnv *henv, ClazzFile *cf);
japhar_object* HVM_GCCloneObject(HungryEnv *henv, japhar_object *old_obj);

PR_END_EXTERN_C

#endif /* japhar_runtimeint_h */
