/* -*- Mode: C; c-file-style: "gnu" -*-
   interp.h -- java interpreter definitions.
   Created: Chris Toshok <toshok@hungry.com>, 13-Aug-1997
 */
/*
  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 _interp_h
#define _interp_h

#include "objects.h"
#include "sig.h"
#include "ClazzFile.h"

#ifdef __cplusplus
extern "C" {
#endif

  typedef struct {
    SigPrimType tag;
    jvalue value;
  } JavaStackItem;

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

  typedef struct _StackFrame StackFrame;

  typedef struct JThreadInfo {
    /* A reference to the java thread which represents
       this native thread. */
    jobject java_thread;

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

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

    char *name;
    JavaStackItem return_value;
    jint current_state;  /* whether we're suspended, running, etc, etc. */
    HThread thread_id;
    JNIEnv *thread_env; /* the JNIEnv for this thread. */
  } JThreadInfo;

  typedef struct {
    char *key;
    char *value;
  } propertySpec;

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

  /* access macros */
#define STATE(t) (t)->current_state
#define TOPFRAME(t) (t)->top_frame
#define PRIORITY(t) (t)->priority
#define NAME(t) (t)->name

#define FRAME_NATIVE			0x01
#define FRAME_HASCLASSLOADER	0x02

  struct _StackFrame {
    int frame_size;
    int depth;

    unsigned char flags;

    MethodStruct *method;
    JThreadInfo *thread_info;
    JNIEnv *jni_env;

    int pc;
    int wide_vindex_set;

#ifdef DEBUG
    char *className;
    char *methodName;
    char *methodSig;
#endif

    void **opstack_top;

    jobject this_pointer;
    JavaStackItem vars[1];
  };

  /* access macros */

#define PARENT(f) (StackFrame*)(((char*)f) + f->frame_size)
#define ENV(f) (f)->jni_env
#define THREAD_INFO(f) (f)->thread_info
#define STACKDEPTH(f) (f)->depth

#define THISPTR(f) (f)->this_pointer

#ifdef DEBUG
#define CLASSNAME(f) (f)->className
#define METHODNAME(f) (f)->methodName
#define METHODSIG(f) (f)->methodSig
#endif

#define METHOD(f) (f)->method
#define CODE(f) (f)->method->code
#define EXCEPTIONS(f) (f)->method->exceptions
#define NUMEXCEPTIONS(f) (f)->method->num_exception_blocks
#define PC(f) (f)->pc
#define WIDE(f) (f)->wide_vindex_set
#define VARS(f) (f)->vars

#define OPSTACK(f) THREAD_INFO(f)->op_stack
#define OPSTACK_TOP(f) (f)->opstack_top

  void suspend_thread(jobject obj, JThreadInfo *thread_info);
  void resume_thread(jobject obj, JThreadInfo *thread_info);

  jboolean setup_stackframes(JThreadInfo *thread_info);
  StackFrame *create_frame_for_method(JThreadInfo *thr_info, 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,
			jvalue *args, /* must match the number in the signature. */
			jobject obj); /* NULL for a static call. */

  StackFrame* push_frame(JThreadInfo *thr_info, int num_vars);
  void pop_frame(JThreadInfo *thr_info);
  StackFrame *get_frame_parent(StackFrame *f);

  void do_native_method_call(JNIEnv *env, MethodStruct *);

  jvalue CallJavaMethod(JNIEnv *env, MethodStruct *method, jobject obj, jvalue *args);
  jvalue CallStaticJavaMethod(JNIEnv *env, MethodStruct *method, jvalue *args);

  void interp_loop(StackFrame *current_frame);

  void set_instance_field(japhar_obj obj, FieldStruct *field, jvalue value);
  void set_static_field(ClazzFile *clazz, FieldStruct *field, jvalue value);

  void get_instance_field(japhar_obj obj, FieldStruct *field, jvalue *value);
  void get_static_field(ClazzFile *clazz, FieldStruct *field, jvalue *value);

#define get_next_u1(f) (CODE(f)[ PC(f) ++ ])

  extern void maybe_enter_monitor_for_method(JNIEnv *env,
					     MethodStruct *method,
					     japhar_obj this_obj);
  extern void maybe_exit_monitor_for_method(JNIEnv *env,
					    MethodStruct *method,
					    japhar_obj this_obj);
  extern void maybe_push_return_value(StackFrame *f);

  extern void push_item_from_constant_pool (StackFrame *f, int index);
  extern void do_method_call (StackFrame *this_frame, MethodStruct *method);

#ifdef PROFILING
  typedef void (*interp_func_t)(StackFrame*);
#endif

  typedef struct opcode_struct {
    char name[26];
#ifdef PROFILING
    interp_func_t func;
#endif
    int num_bytes_needed;
    int num_stack_items_before;
    int num_stack_items_after;
  } opcode;

  /*
   * (byte1 << 8) | byte2
   */
  static inline u2
  get_next_u2(StackFrame *f)
  {
    u2 value;
    value  = get_next_u1(f) << 8;
    value |= get_next_u1(f);
    return value;
  }

  /*
   * (byte1 << 24) | (byte2 << 16) | (byte3 << 8) | byte4
   */
  static inline u4
  get_next_u4(StackFrame *f)
  {
    long value;

    value  = get_next_u1(f) << 24;
    value |= get_next_u1(f) << 16; 
    value |= get_next_u1(f) << 8; 
    value |= get_next_u1(f); 

    return value;
  }

#ifdef __cplusplus
};
#endif

#endif /* INTERP_H */
