/* -*- Mode: C; c-file-style: "gnu" -*-
   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 "jni.h"
#include "native-threads.h"
#include <sig.h>

#ifdef __cplusplus
extern "C" {
#endif

  typedef jboolean u1;
  typedef jchar u2;
  typedef juint u4;

  /* 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

  /* forward definition to make some things happy. */
  typedef struct ClazzFile ClazzFile;

#define VALUE_UNRESOLVED 0xdeadbeef

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

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

  extern ClazzFile *ExceptionBlock_getHandlerClazz(JNIEnv *env,
						   ClazzFile *clazz, ExceptionBlock *block);

  typedef struct LineNumberBlock {
    u2 start_pc;

    u2 line_number;
  } LineNumberBlock;

  typedef struct LocalVariableEntry {
    u2 start_pc;
    u2 end_pc;

    char *name;
    Signature *sig;

    u2 slot;
  } LocalVariableEntry;

  typedef jvalue* (*NativeFunc)(JNIEnv*, jvalue*);

  typedef struct MethodStruct {
    ClazzFile *clazz;
    char *name;
    char *sig_str;

    NativeFunc native_func;
    jbyte *jit_addr; /* if this is a jitted method, this will be non-null. */

    u2 access_flags;

    u2 flags;

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

    /* the actual code for the method */
    u1 *code;
    u4 code_length;

    u2 max_stack;
    u2 max_locals;

    u2 num_local_variables;
    LocalVariableEntry *local_variables;

    u2 num_line_number_blocks;
    LineNumberBlock *line_numbers;

    u2 num_throwable_exceptions;
    u2 *throwable_exception_indices;
    ClazzFile **throwable_exceptions;

    u2 num_exception_blocks;
    ExceptionBlock *exceptions;
  } MethodStruct;

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

    u2 access_flags;

    u2 flags;

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

    int has_constant_value;
    u2 constant_value_index;
    jvalue constant_value;

    SigPrimType java_type;

  } FieldStruct;

#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 {
    u2 tag;
    u2 name_index;
  } ClassConstant;
  typedef struct {
    u2 tag;
    char *name;
    ClazzFile* clazz;
  } ResolvedClassConstant;

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

  typedef struct {
    u2 tag;
    u2 class_index;
    u2 name_and_type_index;

    MethodStruct *nonvirtual_method;
    MethodStruct *static_method;
  } MethodrefConstant;
  typedef struct {
    u2 tag;
    ClazzFile *clazz;
    char *sig_str;
    char *name;
  
    MethodStruct *nonvirtual_method;
    MethodStruct *static_method;
  } ResolvedMethodrefConstant;

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

    char *sig_str;
    char *name;

    MethodStruct *method;
  } ResolvedInterfaceMethodrefConstant;

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

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

  typedef struct {
    u2 tag;
    u4 bytes;
  } FloatConstant;
  typedef struct {
    u2 tag;
    float value;
  } ResolvedFloatConstant;

  typedef struct {
    u2 tag;
    u4 high_bytes;
    u4 low_bytes;
  } LongConstant;
  typedef struct {
    u2 tag;
    jlong value;
  } ResolvedLongConstant;

  typedef struct {
    u2 tag;
    u4 high_bytes;
    u4 low_bytes;
  } DoubleConstant;
  typedef struct {
    u2 tag;
    double value;
  } ResolvedDoubleConstant;

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

  typedef struct {
    u2 tag;
    u2 length;
    u1 *bytes;
  } Utf8Constant;
  typedef struct {
    u2 tag;
    char *value;
  } ResolvedUtf8Constant;

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

  typedef struct {
    u2 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;

  enum {
    CLASS_NOT_INITIALIZED,
    CLASS_INIT_IN_PROGRESS,
    CLASS_INIT_FINISHED,
    CLASS_INIT_FAILED
  };

  struct ClazzFile {
    jobject classloader;
    jobject jcls;

    u2 major;
    u2 minor;

    u2 access_flags;

    u2 flags;

    char *class_name;

    char *source_filename;

    u2 constant_pool_count;
    ConstantPoolEntry *constants;

    u2 superclass_index;
    ClazzFile *superclass;

    u2 num_interfaces;
    u2 *interface_indices;
    ClazzFile **interfaces;

    u2 num_innerclasses;
    u2 *innerclass_indices;
    ClazzFile **innerclasses;

    u2 num_fields;
    jint num_instance_fields;
    jint num_static_fields;
    FieldStruct **fields;
    FieldStruct *field_pool;
    int size_of_instance_field_block;
  
    u2 num_methods;
    MethodStruct **methods;
    MethodStruct *method_pool;

    char *static_fields;
    int size_of_static_field_block;

    jint nesting_level;

    jint initialization_state;
    HThread initializing_thread;
    HMonitor monitor;

    jboolean interfaces_resolved;
    ClazzFile **resolved_interfaces;
    int num_resolved_interfaces;
  };

  /* Defind in libruntime/clparse.c */
  extern ConstantPoolEntry *get_constant(ClazzFile *clazz, int index);
  extern ClazzFile *define_class(JNIEnv *env, unsigned char *buf, int buflen);
  extern ClazzFile *parse_class(JNIEnv *env, char *name);

  extern void class_finalize(ClazzFile *clazz);

  /* resolving methods */
  extern char *ResolveUtf8(JNIEnv *env, ClazzFile *clazz, ConstantPoolEntry *constant);
  extern char *ResolveClassName(JNIEnv *env, ClazzFile *clazz, ConstantPoolEntry *constant);
  extern ClazzFile *ResolveClass(JNIEnv *env, ClazzFile *clazz, ConstantPoolEntry *constant);
  extern FieldStruct *ResolveFieldRef(JNIEnv *env, ClazzFile *clazz, ConstantPoolEntry *constant);
  extern MethodStruct *ResolveNonVirtualMethodRef(JNIEnv *env, ClazzFile *clazz,
						  ConstantPoolEntry *constant);
  extern MethodStruct *ResolveStaticMethodRef(JNIEnv *env, ClazzFile *clazz,
					      ConstantPoolEntry *constant);
  extern MethodStruct *GetMethodByNameAndSig(JNIEnv *env, ClazzFile *clazz,
					     char *method_name, char *sig_str);
  extern int GetMethodByName(JNIEnv *env, ClazzFile *clazz,
			     char *method_name, MethodStruct ***methods);
  extern void ResolveMethod(JNIEnv *env, ClazzFile *clazz, ConstantPoolEntry *constant, char **name, char **sig_str);
  extern void ResolveInterfaceMethod(JNIEnv *env, ClazzFile *clazz, ConstantPoolEntry *constant, char **name, char **sig_str);
  extern void *ResolveString(JNIEnv *env, ClazzFile *clazz, ConstantPoolEntry *constant);
  extern char *ResolveStringAsCString(JNIEnv *env, ClazzFile *clazz, ConstantPoolEntry *constant);

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

  extern char *getSuperClassName(JNIEnv *env, ClazzFile *clazz);
  extern ClazzFile *getSuperClass(JNIEnv *env, ClazzFile *clazz);
  extern ClazzFile *getInnerclass(JNIEnv *env, ClazzFile *clazz, int index);
  extern ClazzFile *getThrowableException(JNIEnv *env,
					  MethodStruct *method,
					  int index);

  extern jboolean is_assignable_from(JNIEnv *env, ClazzFile *clazz1, ClazzFile *clazz2);

#ifdef __cplusplus
};
#endif

#endif /* CLAZZFILE_H */

