/* -*- Mode: C; c-file-style:"gnu"; indent-tabs-mode:nil -*-
   ClazzFile.h -- the in memory representation of .class files.
   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 CLAZZFILE_H
#define CLAZZFILE_H

#include "runtime.h"
#include "ffi.h"

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

PR_BEGIN_EXTERN_C

/* Access control stuff */
#define ACC_PUBLIC       0x0001 /* Visible to everyone */
#define ACC_PRIVATE      0x0002 /* Visible only to the defining class */
#define ACC_PROTECTED    0x0004 /* Visible to subclasses */
#define ACC_STATIC       0x0008 /* Variable or method is static */
#define ACC_FINAL        0x0010 /* No further subclassing, overriding
                                   or assignment after initialization */
#define ACC_SYNCHRONIZED 0x0020 /* Wrap use in monitor lock */
#define ACC_VOLATILE     0x0040 /* Can't cache */
#define ACC_TRANSIENT    0x0080 /* Not to be written or read by a 
                                   persistent object manager */
#define ACC_NATIVE       0x0100 /* Implemented in a language other than java */
#define ACC_INTERFACE    0x0200 /* Is an interface */
#define ACC_ABSTRACT     0x0400 /* No body provided */

#define ACC_ARRAY        0x0800 /* The ClazzFile is actually an array class */
#define ACC_PRIMITIVE    0x1000 /* The ClazzFile represents a primitive type */

#define HAS_CLINIT       0x2000 /* This ClazzFile has a <clinit> method. */

/* extra flags */
#define FLAG_DEPRECATED 0x0001
#define FLAG_SYNTHETIC  0x0002

#define VALUE_UNRESOLVED 0xdeadbeef

#define RESOLVED(v) ((v) != VALUE_UNRESOLVED)
#define UNRESOLVED(v) ((v) == VALUE_UNRESOLVED)

typedef struct ExceptionBlock {
  PRUint16 start_pc;
  PRUint16 end_pc;
  PRUint16 handler_pc;
  PRUint16 catch_clazz_index;
  ClazzFile *catch_clazz;
} ExceptionBlock;

extern ClazzFile *ExceptionBlock_getHandlerClazz(HungryEnv *henv,
                                                 ClazzFile *clazz, ExceptionBlock *block);

typedef struct LineNumberBlock {
  PRUint16 start_pc;

  PRUint16 line_number;
} LineNumberBlock;

typedef struct LocalVariableEntry {
  PRUint16 start_pc;
  PRUint16 end_pc;

  char *name;
  char *sig_str;

  PRUint16 slot;
} LocalVariableEntry;

typedef InterpValue* (*NativeFunc)(void/*JNIEnv*/*, InterpValue*);

struct MethodStruct {
  ClazzFile *clazz;

  int index; /* index into the method table for normal methods, and
                into the InterfaceTuple's array of MethodStruct*'s
                for interface methods */

  char *name;
  char *sig_str;

#ifdef HAVE_LIBFFI
  unsigned int cif_created : 1;
  ffi_cif cif;
#endif
  /* if jni_call is PR_TRUE, send a JNIEnv* as the first param.  otherwise, send the
     HungryEnv* */
  PRBool jni_call;
  NativeFunc native_func;

  PRUint16 access_flags;

  PRUint16 flags;

  /* the number of words from the stack that need to be
     popped when calling this method. */
  PRUint32 num_param_words;

  PRUint32 num_params;

  /* the actual code for the method */
  PRUint8 *code;
  PRUint32 code_length;

  PRUint16 max_stack;
  PRUint16 max_locals;

  PRUint16 num_local_variables;
  LocalVariableEntry *local_variables;

  PRUint16 num_line_number_blocks;
  LineNumberBlock *line_numbers;

  PRUint16 num_throwable_exceptions;
  PRUint16 *throwable_exception_indices;
  ClazzFile **throwable_exceptions;

  PRUint16 num_exception_blocks;
  ExceptionBlock *exceptions;
};

struct FieldStruct {
  ClazzFile *clazz; /* the class this field is in. */
  char *name;
  char *sig_str;
  int sig_size_in_bytes;

  PRUint16 access_flags;

  PRUint16 flags;

  /* the offset into the instance_data fields if the field is not
     static, and the static_data fields if it is. */
  PRUint32 field_offset;

  PRBool has_constant_value;
  PRUint16 constant_value_index;
  InterpValue constant_value;
};

#define CONSTANT_Utf8                   1
#define CONSTANT_Unicode                2
#define CONSTANT_Integer                3
#define CONSTANT_Float                  4
#define CONSTANT_Long                   5
#define CONSTANT_Double                 6
#define CONSTANT_Class                  7
#define CONSTANT_String                 8
#define CONSTANT_Fieldref               9
#define CONSTANT_Methodref              10
#define CONSTANT_InterfaceMethodref     11
#define CONSTANT_NameAndType            12

#define CONSTANT_RESOLVED               0x100

typedef struct {
  PRUint16 tag;
  PRUint16 name_index;
} ClassConstant;
typedef struct {
  PRUint16 tag;
  char *name;
  ClazzFile* clazz;
} ResolvedClassConstant;

typedef struct {
  PRUint16 tag;
  PRUint16 class_index;
  PRUint16 name_and_type_index;
} FieldrefConstant;
typedef struct {
  PRUint16 tag;
  FieldStruct *field;
} ResolvedFieldrefConstant;

typedef struct {
  PRUint16 tag;
  PRUint16 class_index;
  PRUint16 name_and_type_index;
} MethodrefConstant;
typedef struct {
  PRUint16 tag;
  ClazzFile *clazz;
  char *name;
  char *sig_str;

  MethodStruct *virtual_method;
  MethodStruct *nonvirtual_method;
  MethodStruct *static_method;
} ResolvedMethodrefConstant;

typedef struct {
  PRUint16 tag;
  PRUint16 class_index;
  PRUint16 name_and_type_index;
} InterfaceMethodrefConstant;
typedef struct {
  PRUint16 tag;

  char *sig_str;
  char *name;

  MethodStruct *method;
} ResolvedInterfaceMethodrefConstant;

typedef struct {
  PRUint16 tag;
  PRUint16 string_index;
} StringConstant;
typedef struct {
  PRUint16 tag;
  void *string;
} ResolvedStringConstant;

typedef struct {
  PRUint16 tag;
  PRUint32 bytes;
} IntegerConstant;
/* there is no resolved integer constant since there is no more efficient storage for
     it. */

typedef struct {
  PRUint16 tag;
  PRUint32 bytes;
} FloatConstant;
typedef struct {
  PRUint16 tag;
  float value;
} ResolvedFloatConstant;

typedef struct {
  PRUint16 tag;
  PRUint32 high_bytes;
  PRUint32 low_bytes;
} LongConstant;
typedef struct {
  PRUint16 tag;
  PRInt64 value;
} ResolvedLongConstant;

typedef struct {
  PRUint16 tag;
  PRUint32 high_bytes;
  PRUint32 low_bytes;
} DoubleConstant;
typedef struct {
  PRUint16 tag;
  double value;
} ResolvedDoubleConstant;

typedef struct {
  PRUint16 tag;
  PRUint16 name_index;
  PRUint16 signature_index;
} NameAndTypeConstant;
/* there is no ResolvedNameAndTypeConstant since NameAndType constants
     go away when things are resolved. */

typedef struct {
  PRUint16 tag;
  PRUint16 length;
  PRUint8 *bytes;
} Utf8Constant;
typedef struct {
  PRUint16 tag;
  char *value;
} ResolvedUtf8Constant;

typedef struct {
  PRUint16 tag;
  PRUint16 length;
  PRUint16 *bytes;
} UnicodeConstant;
/* there is no ResolvedUnicodeConstant since there is really no more efficient
     way to store them. */

typedef struct {
  PRUint16 tag;
} GenericConstant;

typedef union {
  GenericConstant               generic;

  ClassConstant                 clazz_info;
  ResolvedClassConstant         res_clazz_info;

  FieldrefConstant              fieldref_info;
  ResolvedFieldrefConstant      res_fieldref_info;

  MethodrefConstant             methodref_info;
  ResolvedMethodrefConstant res_method_info;

  InterfaceMethodrefConstant    interfacemethodref_info;
  ResolvedInterfaceMethodrefConstant    res_interfacemethodref_info;

  StringConstant                string_info;
  ResolvedStringConstant        res_string_info;

  IntegerConstant               integer_info;

  FloatConstant                 float_info;
  ResolvedFloatConstant         res_float_info;

  LongConstant                  long_info;
  ResolvedLongConstant          res_long_info;

  DoubleConstant                double_info;
  ResolvedDoubleConstant        res_double_info;

  NameAndTypeConstant           nameandtype_info;

  Utf8Constant                  utf8_info;
  ResolvedUtf8Constant          res_utf8_info;

  UnicodeConstant               unicode_info;
} ConstantPoolEntry;

typedef struct {
  ClazzFile *interface;
  MethodStruct **methods;
} InterfaceTuple;

enum {
  CLASS_NOT_INITIALIZED,
  CLASS_INIT_IN_PROGRESS,
  CLASS_INIT_FINISHED,
  CLASS_INIT_FAILED
};


struct ClazzFile {
  japhar_object* classloader;
  japhar_object* jcls;

  PRUint16 major;
  PRUint16 minor;

  PRUint16 access_flags;

  PRUint16 flags;

  char *class_name;

  char *source_filename;

  PRUint16 constant_pool_count;
  ConstantPoolEntry *constants;

  PRUint16 superclass_index;
  ClazzFile *superclass;

  PRUint16 num_interfaces;
  InterfaceTuple *interface_tuples;

  PRUint16 num_innerclasses;
  PRUint16 *innerclass_indices;
  ClazzFile **innerclasses;

  PRUint16 num_fields;
  PRUint16 num_instance_fields;
  PRUint16 num_static_fields;
  FieldStruct **fields;
  FieldStruct *field_pool;
  PRUint32 size_of_instance_field_block;

  PRUint16 num_methods;
  PRUint16 num_static_methods;
  PRUint16 num_instance_methods;

  MethodStruct **vmethods;
  MethodStruct **smethods;

  MethodStruct *methods;

  char *static_fields;
  PRUint32 size_of_static_field_block;

  PRUint32 nesting_level;

  PRUint32 initialization_state;
  PRThread* initializing_thread;
  PRMonitor* monitor;

#if WITH_SPORTSMODEL
  SMObjectClass *gc_data;
#endif
};

/* Defind in libruntime/clparse.c */
ClazzFile *parse_class(HungryEnv *henv, char *name);

void class_finalize(ClazzFile *clazz);

/* resolving methods */
char *ResolveUtf8(HungryEnv *henv, ClazzFile *clazz, ConstantPoolEntry *constant);
char *ResolveClassName(HungryEnv *henv, ClazzFile *clazz, ConstantPoolEntry *constant);
ClazzFile *ResolveClass(HungryEnv *henv, ClazzFile *clazz, ConstantPoolEntry *constant);
FieldStruct *ResolveFieldRef(HungryEnv *henv, ClazzFile *clazz, ConstantPoolEntry *constant);
MethodStruct *ResolveNonVirtualMethodRef(HungryEnv *henv, ClazzFile *clazz,
                                         ConstantPoolEntry *constant);
MethodStruct *ResolveStaticMethodRef(HungryEnv *henv, ClazzFile *clazz,
                                     ConstantPoolEntry *constant);
PR_EXTERN(MethodStruct*) GetMethodByNameAndSig(HungryEnv *henv, ClazzFile *clazz,
                                               char *method_name, char *sig_str);
int GetMethodByName(HungryEnv *henv, ClazzFile *clazz,
                    char *method_name, MethodStruct ***methods);
MethodStruct* ResolveVirtualMethod(HungryEnv *henv, ClazzFile *clazz,
                                   ConstantPoolEntry *constant, char **name);
MethodStruct *ResolveInterfaceMethod(HungryEnv *henv, ClazzFile *clazz,
                                     ConstantPoolEntry *constant, char **name);
MethodStruct *GetMethodForVirtualMethod(HungryEnv *henv, ClazzFile *clazz,
                                        MethodStruct *virtual_method);
MethodStruct *GetMethodForInterfaceMethod(HungryEnv *henv, ClazzFile *clazz,
                                          MethodStruct *interface_method);
void *ResolveString(HungryEnv *henv, ClazzFile *clazz, ConstantPoolEntry *constant);
char *ResolveStringAsCString(HungryEnv *henv, ClazzFile *clazz, ConstantPoolEntry *constant);

/*extern char *getClassName(HungryEnv *henv, ClazzFile *clazz);*/
#define getClassName(env, clazz) ((clazz)->class_name)

char *getSuperClassName(HungryEnv *henv, ClazzFile *clazz);
PR_EXTERN(ClazzFile*) getSuperClass(HungryEnv *henv, ClazzFile *clazz);
ClazzFile *getInnerclass(HungryEnv *henv, ClazzFile *clazz, int index);
ClazzFile *getThrowableException(HungryEnv *henv,
                                 MethodStruct *method,
                                 int index);

PR_EXTERN(PRBool) HVM_ClassIsAssignableFrom(HungryEnv *henv, ClazzFile *clazz1, ClazzFile *clazz2);

PR_END_EXTERN_C

#endif /* CLAZZFILE_H */

