/* ClassFile.h
   Copyright (C) 2005-2008 Free Software Foundation, Inc.

This file is part of Mysaifu JVM

Mysaifu JVM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.

Mysaifu JVM 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
General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING.  If not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA.
*/


#ifndef CLASSFILE_H_INCLUDED
#define CLASSFILE_H_INCLUDED

/**
 * クラスファイル内のデータ定義
 */
typedef unsigned __int8		u1;
typedef unsigned __int16	u2;
typedef unsigned __int32	u4;

#include "java_utf8.h"

/**
 * 前方参照
 */
struct ClassFile;
struct class_loader;
struct static_data_status;

/**
 * frame構造体
 */
struct frame;

/**
 * コンスタント・プール構造体
 */
struct cp_info {
};

/**
 * コンスタント・プールのtagに入る値
 */
#define	CONSTANT_Utf8				1
#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

// コンスタント・プールのtag値ここまで

/**
 * フィールド参照情報
 */
struct CONSTANT_Fieldref_info {
	/**
	 * クラスの名前
	 */
	java_utf8*	class_name;

	/**
	 * フィールドの名前
	 */
	java_utf8*	field_name;

	/**
	 * フィールドディスクリプタ
	 */
	java_utf8*	field_descriptor;

	/**
	 * フィールドを保持しているClassFile
	 */
	ClassFile*	class_file;

	/**
	 * 対応するフィールドID
	 */
	jfieldID	field_id;

	/**
	 * フィールドのオブジェクト内における位置
	 */
	unsigned int field_position;
};

struct method_info;

/**
 * メソッド参照情報
 */
struct CONSTANT_Methodref_info {
	/**
	 * クラスの名前
	 */
	java_utf8* class_name;

	/**
	 * メソッドの名前
	 */
	java_utf8* method_name;

	/**
	 * メソッドのディスクリプタ
	 */
	java_utf8* method_descriptor;
	
	/**
	 * method_infoキャッシュ
	 * invokestatic/invokespecial/invokestatic命令実行時に使用する
	 */
	method_info* target_method_info_cache;

	/**
	 * メソッド･テーブルインデックス
	 * invokevirtual命令実行時に使用する
	 * -1が特別な意味を持つため、u2ではなくintになっている
	 */
	int method_table_index;

	/**
	 * パラメータ数
	 * (-1 を特別な値として扱っているため、型は int になっている）
	 */
	int parameters_count;
};

/**
 * Stringオブジェクト参照情報
 */
//struct CONSTANT_String_info {
//	/**
//	 * UTF-8文字列
//	 */
//	java_utf8*	utf8;
//
//	/**
//	 * 対応するStringオブジェクトの参照。存在しない場合はNULL
//	 */
//	jobject string_reference;
//};

/**
 * 属性
 */
struct attribute_info {
};

/**
 * 例外ハンドラ情報（コードアトリビュートの一部）
 */
typedef struct exception_handler_info_t {
	u2 start_pc;
    u2 end_pc;
    u2 handler_pc;
    u2 catch_type;
} exception_handler_info;

/**
 * LineNumberTableアトリビュートの要素
 */
struct line_number_table {
	u2 start_pc;	     
	u2 line_number;
};

/**
 * LineNumberTableアトリビュート
 */
struct LineNumberTable_attribute {
	/**
	 * テーブル数
	 */
    u2 line_number_table_length;

	/**
	 * 行テーブル
	 */
	line_number_table* table;
};

/**
 * コードアトリビュート
 */
struct Code_attribute {
    u2 max_stack;
    u2 max_locals;
    u4 code_length;
    u1* code;
    u2 exception_table_length;
    exception_handler_info* exception_table;

	LineNumberTable_attribute* linenumbertable_attribute;
};

/**
 * 例外アトリビュート
 */
struct Exceptions_attribute {
	u2 number_of_exceptions;
	u2* exception_index_table;
};

/**
 * 内部クラスアトリビュート
 */
struct classes_info {
	u2 inner_class_info_index;	     
	u2 outer_class_info_index;	     
	u2 inner_name_index;	     
	u2 inner_class_access_flags;	     
};

struct InnerClasses_attribute {
    u2 number_of_classes;
	classes_info* classes;
};

/**
 * フィールド情報
 */
struct field_info {
	/**
	 * フィールド名
	 */
	java_utf8*	name;

	/**
	 * ディスクリプタ
	 */
	java_utf8* descriptor;

	/**
	 * フィールドを宣言しているClassFile
	 */
	ClassFile* declaring_ClassFile;

	/**
	 * アクセスフラグ
	 */
	u2 access_flags;

	/**
	 * constant_pool内のインデックス値。
	 */
	u2 constantvalue_index;

	/**
	 * クラスオブジェクトまたはインスタンスデータ内での位置
	 * 各フィールドのサイズ境界に配置される。
	 */
	u2 position;

	/**
	 * Signatureのインデックス
	 */
	u2 signature_index;

	/**
	 * クラスオブジェクトまたはインスタンスデータ内で占めるサイズ（バイト単位）
	 */
	u1 size;
};

/**
 * フィールドテーブル。以下の情報を管理する
 * ・field_info構造体
 * ・フィールドに参照値が入っているかどうか（4バイト単位）
 */
struct field_table {
	/**
	 * 全フィールド数
	 */
	u2 fields_count;
	
	/**
	 * 総サイズ（バイト単位）
	 */
	u2 total_size;
	
	/**
	 * フィールドテーブルの要素
	 */
	field_info**	elements;

   /**
	* 参照値が入っているかどうかのフラグ（32ビット単位）
	*/
	bool* reference_flags;
};

/**
 * メソッド情報
 */
struct method_info {
	/**
	 * アクセスフラグ
	 */
	u2 access_flags;

	/**
	 * Signatureのインデックス
	 */
	u2 signature_index;

	/**
	 * メソッド名
	 */
	const java_utf8*	name;
	
	/**
	 * ディスクリプタ
	 */
	const java_utf8* descriptor;
	
	/**
	 * コードアトリビュート
	 * ネイティブメソッドの場合は、ネイティブ関数のポインタ
	 */
	Code_attribute* code_attribute;
	
	/**
	 * 例外アトリビュート
	 */
	Exceptions_attribute* exceptions_attribute;

	/**
	 * パラメータ数(longとdoubleは"2" それ以外は"1")
	 * -1を特別な値として扱っているため、型はu2ではなく int になっている
	 */
	int parameters_count;

	/**
	 * 戻り値のタイプ
	 */
	const java_utf8* return_type;

	/**
	 * method_infoを保持しているClassFile
	 */
	ClassFile*		declaring_ClassFile;

};

/**
 * メソッド・テーブル
 * クラスが保有する以下のインスタンスメソッドに関する情報を保持する
 * ・自分自身のメソッドのうち、以下の条件を満たすメソッド
 *   <init>メソッドではない
 *   privateメソッドではない
 * ・スーパークラスのうち、以下の条件を満たすメソッド
 *   <init>メソッドでない
 *   privateメソッドではない
 *
 * スーパークラスのメソッドテーブルの並び順と、
 * 派生クラスのメソッドテーブルの並び順は同一にする必要がある。
 */
struct method_table {
	/**
	 * メソッド数
	 */
	u2 methods_count;
	
	/**
	 * 要素
	 */
	method_info** elements;

};

/**
 * クラスファイルのステータス
 */
enum ClassFileStatus {
	CLASS_FILE_LOADING,			// ロード中
	CLASS_FILE_LOADED,			// ロードされた
	CLASS_FILE_VERIFYING,		// ベリファイ中
	CLASS_FILE_VERIFIED			// ベリファイ完了
};

/**
 * クラスファイル情報
 */
struct ClassFile {
	/**
	 * 定義ローダ
	 */
	class_loader*	defining_loader;
	
	/**
	 * staticデータの状態
	 */
	static_data_status* static_data_stat;

	/**
	 * アクセスフラグ。ACC_* 定数が使用される
	 */
	u2 access_flags;

	/**
	 * コンスタントプールの数
	 */
	u2 constant_pool_count;

	/**
	 * コンスタントプール。
	 * 配列の添え字は1からconstant_pool_count-1までが有効な値となる。
	 * 添え字0は使用されていないため、仮想マシンが内部的に使用することとする。
	 */
	cp_info** constant_pool;
	
	/**
	 * コンスタントプールのtag
	 */
	u1* constant_pool_tags;

	/**
	 * このクラス名。
	 */
	const java_utf8* this_class_name;

	/**
	 * スーパークラス名。
	 */
	const java_utf8* super_class_name;

	/**
	 * このクラスが実装しているインタフェース名を示す、コンスタントプールのインデックス値
	 */
	u2* interfaces;

	/**
	 * このクラスが実装しているインタフェースの数
	 */
	u2 interfaces_count;

	/**
	 * このクラスのフィールド数
	 */
	u2 fields_count;

	/**
	 * このクラスのメソッド数
	 */
	u2 methods_count;

	/**
	 * ソースファイル名のインデックス
	 */
	u2 sourcefile_index;
	
	/**
	 * Signatureのインデックス
	 */
	u2 signature_index;

	/**
	 * このクラスのフィールド情報
	 */
	field_info* fields;

	/**
	 * このクラスのメソッド情報
	 */
	method_info* methods;

	/**
	 * InnerClassesアトリビュート
	 */
	InnerClasses_attribute* innerclasses_attribute;
	
	/**
	 * このクラスファイルのステータス
	 */
	ClassFileStatus status;

	/**
	 * staticフィールドテーブル
	 */
	field_table static_field_table;

	/**
	 * インスタンスフィールドテーブル
	 */
	field_table instance_field_table;

	/**
	 * メソッドテーブル
	 * privateメソッドおよび <init>, <clinit> メソッドは格納されない。
	 */
	method_table mtable;

	/**
	 * このクラスがファイナライザを保有している場合true
	 */
	bool has_finalizer;
	
	/**
	 * スーパークラスのClassFile
	 */
	ClassFile* superclass_ClassFile;

	/**
	 * インタフェースのClassFile
	 */
	ClassFile** interfaces_ClassFiles;

};

/**
 * アクセスフラグ定数
 */
#define ACC_PUBLIC			0x0001
#define ACC_PRIVATE			0x0002
#define ACC_PROTECTED		0x0004
#define ACC_STATIC			0x0008
#define ACC_FINAL			0x0010
#define ACC_SUPER			0x0020
#define ACC_SYNCHRONIZED	0x0020
#define ACC_VOLATILE		0x0040
#define ACC_BRIDGE			0x0040
#define ACC_TRANSIENT		0x0080
#define ACC_VARARGS			0x0080
#define ACC_NATIVE			0x0100
#define ACC_INTERFACE		0x0200
#define ACC_ABSTRACT		0x0400
#define ACC_STRICT			0x0800
#define ACC_SYNTHETIC		0x1000
#define ACC_ANNOTATION		0x2000
#define	ACC_ENUM			0x4000

// Mysaifu JVM固有のアクセスフラグ
#define	ACC_EMPTY			0x8000

/**
 * アクセスフラグ判定関数
 */
inline bool is_public(u2 access_flags) {
	return (access_flags & ACC_PUBLIC) != 0;
}

inline bool is_protected(u2 access_flags) {
	return (access_flags & ACC_PROTECTED) != 0;
}

inline bool is_private(u2 access_flags) {
	return (access_flags & ACC_PRIVATE) != 0;
}

inline bool is_static(u2 access_flags) {
	return (access_flags & ACC_STATIC) != 0;
}

inline bool is_interface(u2 access_flags) {
	return (access_flags & ACC_INTERFACE) != 0;
}

inline bool is_abstract(u2 access_flags) {
	return (access_flags & ACC_ABSTRACT) != 0;
}

inline bool is_synchronized(u2 access_flags) {
	return (access_flags & ACC_SYNCHRONIZED) != 0;
}

inline bool is_final(u2 access_flags) {
	return (access_flags & ACC_FINAL) != 0;
}

inline bool is_volatile(u2 access_flags) {
	return (access_flags & ACC_VOLATILE) != 0;
}

inline bool is_native(u2 access_flags) {
	return (access_flags & ACC_NATIVE) != 0;
}

/**
 * コンスタントプール情報を取得する
 */
inline cp_info* get_cp_info(ClassFile* cfile, u2 index, u1 tag) {
	assert(index < cfile->constant_pool_count);
	cp_info* info = cfile->constant_pool[index];
	assert(info != NULL && cfile->constant_pool_tags[index] == tag);
	return info;
}

/**
 * 指定されたインデックスに対応する java_utf8 構造体へのポインタを
 * 返す。
 *
 * @param	cfile	ClassFile構造体へのポインタ
 * @param	index	constant_pool内のインデックス値
 * @return	java_utf8構造体へのポインタ。取得できない場合はNULL
 */
inline java_utf8* get_java_utf8(ClassFile* cfile, u2 index) {
	return (java_utf8*) get_cp_info(cfile, index, CONSTANT_Utf8);
}

/**
 * 指定されたインデックスに対応する CONSTANT_Class_info 構造体で定義された
 * クラス名を返す
 *
 * @param	cfile	ClassFile構造体へのポインタ
 * @param	index	constant_pool内のインデックス値
 * @return	クラス名
 */
inline java_utf8* get_CONSTANT_Class_info(ClassFile* cfile, u2 index) {
	assert(cfile->constant_pool_tags[index] == CONSTANT_Class);
	cp_info* cinfo = get_cp_info(cfile, index, CONSTANT_Class);
	if ((unsigned int) cinfo & 0x80000000) {
		// 最上位ビットがたっている場合は、すでにresolveされたClassFile*への
		// ポインタが入っている
		ClassFile* cfile = (ClassFile*) ((unsigned int) cinfo & ~0x80000000);
		return cfile->this_class_name;
	} else {
		return get_java_utf8(cfile, (u2) cinfo); 
	}
}

/**
 * 指定されたインデックスに対応する CONSTANT_Fieldref_info 構造体へのポインタを
 * 返す。
 *
 * @param	cfile	ClassFile構造体へのポインタ
 * @param	index	constant_pool内のインデックス値
 * @return	Fieldref_info構造体へのポインタ。取得できない場合はNULL
 */
inline CONSTANT_Fieldref_info* get_CONSTANT_Fieldref_info(ClassFile* cfile, u2 index) {
	return (CONSTANT_Fieldref_info*) get_cp_info(cfile, index, CONSTANT_Fieldref);
}

/**
 * 指定されたインデックスに対応する Methodref_info 構造体へのポインタを
 * 返す。
 *
 * @param	cfile	ClassFile構造体へのポインタ
 * @param	index	constant_pool内のインデックス値
 * @return	Methodref_info構造体へのポインタ。取得できない場合はNULL
 */
inline CONSTANT_Methodref_info* get_CONSTANT_Methodref_info(ClassFile* cfile, u2 index) {
	return (CONSTANT_Methodref_info*) get_cp_info(cfile, index, CONSTANT_Methodref);
}

/**
 * コード・アトリビュートを取得する
 * ネイティブ関数の場合は、解決済みのネイティブ関数のポインタを返す。
 */
inline Code_attribute* get_Code_attribute(ClassFile* cfile, method_info* minfo) {
	return minfo->code_attribute;
}


/**
 * ClassFile関連の変数を初期化する
 */
void init_ClassFile_settings();

/**
 * 指定されたバッファの内容をパースしてClassFile構造体を作成する
 *
 * @param	loader		クラスローダ
 * @param	buff		バッファ
 * @param	buff_length	バッファサイズ
 */
ClassFile* parse_ClassFile(frame* frm, class_loader* loader, const char* buff, size_t buff_length);

/**
 * 指定されたクラスファイルに割り当てられたメモリを開放する
 */
void free_ClassFile(ClassFile* cfile);

/**
 * 指定されたインデックスに対応する CONSTANT_Class_info 構造体で定義された
 * クラス名を返す
 *
 * @param	cfile	ClassFile構造体へのポインタ
 * @param	index	constant_pool内のインデックス値
 * @return	クラス名
 */
const java_utf8* get_CONSTANT_Class_info(ClassFile* cfile, u2 index);

/**
 * 指定されたインデックスに対応する CONSTANT_Fieldref_info 構造体へのポインタを
 * 返す。
 *
 * @param	cfile	ClassFile構造体へのポインタ
 * @param	index	constant_pool内のインデックス値
 * @return	Fieldref_info構造体へのポインタ。取得できない場合はNULL
 */
CONSTANT_Fieldref_info* get_CONSTANT_Fieldref_info(ClassFile* cfile, u2 index);

/**
 * 指定されたインデックスに対応する Methodref_info 構造体へのポインタを
 * 返す。
 *
 * @param	cfile	ClassFile構造体へのポインタ
 * @param	index	constant_pool内のインデックス値
 * @return	Methodref_info構造体へのポインタ。取得できない場合はNULL
 */
CONSTANT_Methodref_info* get_CONSTANT_Methodref_info(ClassFile* cfile, u2 index);

/**
 * 指定されたインデックスに対応する java_utf8 構造体へのポインタを
 * 返す。
 *
 * @param	cfile	ClassFile構造体へのポインタ
 * @param	index	constant_pool内のインデックス値
 * @return	java_utf8構造体へのポインタ。取得できない場合はNULL
 */
java_utf8* get_java_utf8(ClassFile* cfile, u2 index);

/**
 * 指定されたフィールドIDに対応するインスタンスフィールドの
 * field_info 構造体へのポインタを返す
 *
 * @param	cfile	ClassFile構造体へのポインタ
 * @param	fid		フィールドID
 * @return	field_info構造体へのポインタ。取得できない場合はNULL。
 */
field_info* get_field_info(ClassFile* cfile, jfieldID fid);
field_info* get_static_field_info(ClassFile* cfile, jfieldID fid);

/**
 * 指定されたmethod_info構造体に対応するCode_attribute構造体へのポインタを返す。
 *
 * @param	cfile	ClassFile構造体へのポインタ
 * @param	minfo	method_info構造体へのポインタ
 * @return	対応するCode_attribute構造体へのポインタ。取得できなかった場合はNULL
 */
Code_attribute* get_Code_attribute(ClassFile* cfile, method_info* minfo);

/**
 * 指定されたメソッドディスクリプタのパラメータ数を解釈する
 * longとdoubleは２とカウントする
 */
u2 parse_parameters_count(const java_utf8* mdesc);

/**
 * 指定されたメソッドの戻り値タイプを返す。
 */
const char* get_return_type(method_info* minfo);

/**
 * 指定されたクラスファイル内に、指定された名前およびディスクリプタを持つメソッドがあるか
 * 検索する
 *
 * @param	cfile	検索対象となるクラス。
 * @param	name	検索対象となるメソッドの名前。
 * @param	desc	検索対象となるメソッドのディスクリプタ。
 * @return	検索結果。一致するメソッドが存在しなかった場合はNULL。
 */
method_info* find_declaring_method_info(ClassFile* cfile, const java_utf8* name, const java_utf8* desc);

/**
 * 配列のクラスファイルを作成する
 *
 * @param	class_name	配列のクラス名
 * @return	対応するClassFile構造体へのポインタ
 */
ClassFile* create_array_ClassFile(class_loader* l, const java_utf8* class_name, u2 access_flags);

/**
 * プリミティブクラスファイルを作成する
 *
 * @param	class_name	プリミティブクラス名
 * @return	対応するClassFile構造体へのポインタ
 */
ClassFile* create_primitive_ClassFile(const java_utf8* class_name);

/**
 * クラスファイルの prepare 処理を行う
 */
bool prepare_ClassFile(frame* current_frame,
					   ClassFile* cfile,
					   ClassFile* super_class_file,
					   ClassFile** interfaces);


/**
 * staticフィールドIDを返す
 */
jfieldID get_static_field_id(ClassFile* cfile, const java_utf8* field_name, const java_utf8* field_desc);

/**
 * フィールドIDを返す
 */
jfieldID get_field_id(ClassFile* cfile, const java_utf8* field_name, const java_utf8* field_desc);

/**
 * メソッドIDを返す
 *
 */
jmethodID get_method_id(const ClassFile* cfile, const java_utf8* method_name, const java_utf8* method_desc);

/**
 * メソッドIDに対応するmethod_infoを返す。
 */
method_info* get_method_info(ClassFile* cfile, jmethodID mid);

/**
 * このクラスがファイナライザを持っているかを返す。
 * Object.finalize()をオーバーライドしている場合、trueを返す。
 *
 * @param	cfile	クラスファイル
 * @return	ファイナライザを持っている場合true。
 */
inline bool has_finalizer(ClassFile* cfile) {
	return cfile->has_finalizer;
}

/**
 * 指定されたクラスが配列型のクラスであるかを返す
 */
inline bool is_array_class(ClassFile* cfile) {
	return cfile->this_class_name[0] == '[';
}

/**
 * 指定されたクラスがプリミティブ型配列クラスかを返す
 */
inline bool is_primitive_array_class(ClassFile* cfile) {
	if (is_array_class(cfile)) {
		if (cfile->this_class_name[1] != '['
			&& cfile->this_class_name[1] != 'L') {
			return true;
		}
	}
	return false;
}

/**
 * 指定されたクラスの構成要素を表す文字列を返す
 * プリミティブ型クラスの場合は、以下の文字列を返す。
 * boolean型 - Z
 * char型 - C
 * short型 - S
 * int型 - I
 * long型 - J
 * float型 - F
 * double型 - D 
 * 参照型クラスの場合、そのクラス名を返す。
 * 例）配列クラス名が[java/lang/String; の場合、java/lang/String を返す。
 * 例２）配列クラス名が [[I の場合、[I を返す。
 */
const java_utf8* get_array_component_name(ClassFile* cfile);
const java_utf8* get_array_component_name(const char* name);

/**
 * SourceFile_attributeを返す。
 */
const java_utf8* get_SourceFile(ClassFile* cfile);

/**
 * LineNumberを返す
 */
int get_LineNumber(Code_attribute* code, unsigned int pc);

/**
 * 指定されたクラス名がプリミティブクラス名かを返す。
 * プリミティブクラス名は以下の９種類である。
 * void
 * boolean
 * byte
 * char
 * short
 * int
 * long
 * float
 * double
 *
 */
bool is_primitive_class_name(java_utf8* class_name);

/**
 * スーパークラスのClassFile*構造体を返す
 */
inline ClassFile* get_superclass_ClassFile(ClassFile* cfile) {
	return cfile->superclass_ClassFile;
}

/**
 * 指定されたインデックスに対応するインタフェースのClassFile構造体を返す
 */
inline ClassFile* get_interface_ClassFile(ClassFile* cfile, u2 index) {
	return cfile->interfaces_ClassFiles[index];
}

/**
 * 渡された文字列をメソッドディスクリプタとみなし、
 * トークンの長さを返す。
 * トークンが見つからなかった場合は -1 を返す。
 */
int get_token_length_of_descriptor(const char* descriptor);

/**
 * 指定されたトークンからクラス名を抽出し、intern された文字列に変換して
 * 返す
 */
const java_utf8* intern_class_name(const char* token, int length);

/**
 * 指定されたクラス from から、クラス target の access_flags を持つ
 * クラス／メソッド／フィールドにアクセス可能かを判定する
 */
bool is_accessible(frame* current_frame, ClassFile* from, ClassFile* target, u2 access_flags);

/**
 * 「特別な」ポインタかどうかを調べる。
 * Windows Mobileでは、アプリケーションが2GBより上位の仮想アドレス空間が割り当てられないことに
 * 依存している
 */
#define IS_SPECIAL_POINTER(p)		((unsigned int) (p) & 0x80000000)
#define MAKE_SPECIAL_POINTER(p)		((void*)((unsigned int) (p) | 0x80000000))
#define MAKE_NORMAL_POINTER(p)		((void*)((unsigned int) (p) & ~0x80000000))

/**
 * 指定されたconstant_pool_index が指しているClassFileをresolveする
 */
ClassFile* resolve_ClassFile(frame* current_frame,
							 ClassFile* cfile,
							 u2 constant_pool_index);

/**
 * resolveされたClassFileを返す
 */
inline ClassFile* get_resolved_ClassFile(ClassFile* cfile, u2 constant_pool_index) {
	assert(IS_SPECIAL_POINTER(cfile->constant_pool[constant_pool_index]));
	return (ClassFile*) MAKE_NORMAL_POINTER(cfile->constant_pool[constant_pool_index]);
}

/**
 * フィールドID, メソッドIDのビットマスク
 * 有効なフィールドIDはこのビットを立てておく。
 * (無効な値をNULLとするために必要）
 */
#define	FIELD_ID_MASK	0x80000000
#define METHOD_ID_MASK	0x80000000

/**
 * インデックス値をフィールドIDに変換するマクロ
 */
#define	INDEX_TO_FIELD_ID(i)	((jfieldID) (i | FIELD_ID_MASK))

/**
 * フィールドIDをインデックス値に変換するマクロ
 */
#define	FIELD_ID_TO_INDEX(i)	((unsigned int)i & ~FIELD_ID_MASK)

/**
 * 非staticフィールド情報が格納されたフィールドテーブルを返す
 *
 * @return	フィールドテーブル。フィールドテーブルが初期化されていない場合はNULL
 */
inline field_table* get_field_table(ClassFile* cfile) {
	return &cfile->instance_field_table;
}

/**
 * staticフィールド情報が格納されたフィールドテーブルを返す。
 */
inline field_table* get_static_field_table(ClassFile* cfile) {
	return &cfile->static_field_table;
}

/**
 * 指定されたフィールドIDに対応する field_info 構造体へのポインタを返す
 *
 * @param	cfile	ClassFile構造体へのポインタ
 * @param	fid		フィールドID
 * @return	field_info構造体へのポインタ。取得できない場合はNULL。
 */
inline field_info* get_field_info(ClassFile* cfile, jfieldID fid) {
	field_table* tab = &cfile->instance_field_table;
	int index = FIELD_ID_TO_INDEX(fid);
	field_info* e = tab->elements[index];
	return e;
}

/**
 * 指定されたフィールドIDに対応する field_info 構造体へのポインタを返す
 *
 * @param	cfile	ClassFile構造体へのポインタ
 * @param	fid		フィールドID
 * @return	field_info構造体へのポインタ。取得できない場合はNULL。
 */
inline field_info* get_static_field_info(ClassFile* cfile, jfieldID fid) {
	field_table* tab = &cfile->static_field_table;
	int index = FIELD_ID_TO_INDEX(fid);
	field_info* e = tab->elements[index];
	return e;
}

/**
 * 指定されたClassFile構造体に対応するmethod_tableを返す。
 */
inline method_table* get_method_table(const ClassFile* cfile) {
	return &(((ClassFile*) (cfile))->mtable);
}

/**
 * 指定されたクラスが保持しているstaticフィールドの合計サイズを返す
 */
inline unsigned int get_static_fields_size(ClassFile* cfile) {
	field_table* tab = get_static_field_table(cfile);
	return tab->total_size;
}

/**
 * 指定されたクラスが保持している非staticフィールドの合計サイズを返す
 */
inline unsigned int get_fields_size(ClassFile* cfile) {
	field_table* tab = get_field_table(cfile);
	return tab->total_size;
}

/**
 * 指定されたクラスのインスタンスデータ内における、「参照フラグ」を返す。
 */
inline bool* get_static_field_reference_flags(ClassFile* cfile) {
	field_table* tab = get_static_field_table(cfile);
	return tab->reference_flags;
}

/**
 * 指定されたクラスのインスタンスデータ内における、「参照フラグ」を返す。
 */
inline bool* get_field_reference_flags(ClassFile* cfile) {
	field_table* tab = get_field_table(cfile);
	return tab->reference_flags;
}

/**
 * 指定されたメソッドのパラメータ数（ローカル変数上必要となる数）を返す
 *
 * @param	minfo	method_info構造体へのポインタ
 */
inline u2 get_parameters_count(method_info* minfo) {
	return (minfo->parameters_count == -1)
			? (u2) (minfo->parameters_count = parse_parameters_count(minfo->descriptor))
			: (u2) minfo->parameters_count;
}

inline u2 get_parameters_count(CONSTANT_Methodref_info* methodref) {
	return (methodref->parameters_count == -1)
			? (u2) (methodref->parameters_count = parse_parameters_count(methodref->method_descriptor))
			: (u2) methodref->parameters_count;
}

/**
 * 指定されたクラスの名前を返す。
 */
inline const java_utf8* get_class_name(ClassFile* cfile) {
	return cfile->this_class_name;
}

/**
 * 指定されたクラスのスーパークラス名を返す。
 * スーパークラスが存在しない場合hNULLを返す。
 */
inline const java_utf8* get_super_class_name(ClassFile* cfile) {
	return cfile->super_class_name;
}

/**
 * 指定されたクラスで、指定された名前／シグニチャを持つメソッドが宣言されているかを調べ、
 * 宣言されている場合にはそのmethod_infoを返す
 * 見つからなかった場合は NULL を返す
 */
inline method_info* get_declared_method_info(ClassFile* cfile, const java_utf8* name, const java_utf8* desc) {
	method_info* declared_methods = cfile->methods;
	for (u2 i = 0; i < cfile->methods_count; ++i) {
		method_info* minfo = declared_methods++;
		java_utf8* mname = minfo->name;
		java_utf8* mdesc = minfo->descriptor;
		if (name == mname && desc == mdesc) {
			return minfo;
		}
	}
	return NULL;
}		

/**
 * 指定された名前／シグニチャを持つメソッドを、メソッド・テーブルから検索し、
 * そのインデックス値を返す。
 * 見つからなかった場合、-1 を返す。
 */
inline int get_method_table_index(ClassFile* cfile, const java_utf8* name, const java_utf8* desc) {
	method_table* mtab = get_method_table(cfile);
	for (u2 i = 0; i < mtab->methods_count; ++i) {
		method_info* minfo = mtab->elements[i];
		java_utf8* mname = minfo->name;
		java_utf8* mdesc = minfo->descriptor;
		if (name == mname && desc == mdesc) {
			return i;
		}
	}
	return -1;
}

/**
 * 指定されたインデックス値を持つメソッドのmethod_infoを返す
 * 検索は、メソッドテーブルに対して行われる
 */
inline method_info* get_method_info_by_table_index(ClassFile* cfile, int method_table_index) {
	method_table* mtab = get_method_table(cfile);
	assert(method_table_index >= 0 && method_table_index < mtab->methods_count);
	return mtab->elements[method_table_index];
}

/**
 * 指定されたクラスの構成要素を表す文字列を返す
 * プリミティブ型クラスの場合は、以下の文字列を返す。
 * boolean型 - Z
 * char型 - C
 * short型 - S
 * int型 - I
 * long型 - J
 * float型 - F
 * double型 - D 
 * 参照型クラスの場合、そのクラス名を返す。
 * 例１）配列クラス名が[Ljava/lang/String; の場合、java/lang/String を返す。
 * 例２）配列クラス名が [[I の場合、[I を返す。
 *
 * 指定されたクラスファイルが配列型でない場合、NULLを返す。
 */
inline const java_utf8* get_array_component_name(ClassFile* cfile) {
	return get_array_component_name(cfile->this_class_name);
}

#endif