/* ClassFile.cpp
   Copyright (C) 2005 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.
*/

#include "StdAfx.h"
#include "ClassFile.h"
#include "class_loader.h"
#include "java_utf8.h"
#include "common_funcs.h"
#include "instruction.h"

/**
 * クラスファイル内のマジックナンバー
 */
#define	MAGIC	0xCAFEBABE

/**
 * サポートするクラスバージョンの最小値／最大値
 */
#define MINIMUM_VERSION	((45 << 16) | 3)
#define MAXIMUM_VERSION ((50 << 16) | 0)

/**
 * アトリビュート名
 */
static const java_utf8* g_Code_name;					// "Code"
static const java_utf8* g_ConstantValue_name;			// "ConstantValue"
static const java_utf8* g_SourceFile_name;				// "SourceFile"
static const java_utf8* g_LineNumberTable_name;			// "LineNumberTable"
static const java_utf8* g_Exceptions_name;				// "Exceptions"
static const java_utf8* g_InnerClasses_name;			// "InnerClasses"
static const java_utf8* g_Signature_name;				// "Signature"
static const java_utf8* g_RuntimeVisibleAnnotations;	// "RuntimeVisibleAnnotations"
static const java_utf8* g_RuntimeVisibleParameterAnnotations;	// "RuntimeVisibleParameterAnnotations"

/**
 * プリミティブクラス名
 */
static const java_utf8* g_primitive_class_names[9];

// static関数
static bool check_constant_pool_consistency(ClassFile* cfile);
static void init_utf8_references(ClassFile* cfile_p);
static inline u1 load_u1(const char*);
static inline u2 load_u2(const char*);
//static inline u4 load_u4(const char*);
static unsigned int load_attributes(const char* buff, size_t buffleft, u2 attributes_count, cp_info** constant_pool, method_info* minfo, PermanentHeap* heap);
static unsigned int load_attributes(const char* buff, size_t buffleft, u2 attributes_count, cp_info** constant_pool, field_info* finfo);
static unsigned int load_attributes(const char* buff, size_t buffleft, u2 attributes_count, cp_info** constant_pool, Code_attribute* code_attribute, PermanentHeap* heap);
static unsigned int load_attributes(const char* buff, size_t buffleft, u2 attributes_count, ClassFile* cfile, PermanentHeap* heap);
static java_utf8* get_attribute_name(ClassFile* cfile, u2 attribute_name_index);

/**
 * インタフェースに関するロード制約を追加する
 */
static bool process_loading_constraints(frame* frm,
												  ClassFile* interface_cfile,
												  method_table* mtable);

/**
 * フィールドテーブルを初期化する
 *
 * @param	cfile				ClassFile構造体へのポインタ。
 * @param	super_class_file	スーパークラスのファイル
 */
static void init_field_table(ClassFile* cfile,
							 ClassFile* super_class_file,
							 ClassFile** interfaces,
							 u2 interface_count);

/**
 * メソッド・テーブルを初期化する
 *
 * @param	cfile				ClassFile構造体へのポインタ。
 * @param	superclass_file		スーパークラスのClassFile構造体へのポインタ。
 * @return	初期化に成功した場合true。
 */
static bool init_method_table(frame* frm,
							  ClassFile* cfile,
							  ClassFile* superclass_file,
							  ClassFile** interfaces,
							  u2 interfaces_count);

/**
 * 指定されたバッファから、u1をロードする
 */
static inline u1 load_u1(const char* buff) {
	return (u1)*buff;
}

/**
 * 指定されたバッファから、u2をロードする
 */
static inline u2 load_u2(const char* buff) {
	return (u2) buff[0] << 8 | (buff[1] & 0xff);
}

/**
 * 指定されたバッファから、u4をロードする
 * (inline展開されないので、マクロとして定義する）
 */
#define load_u4(buff) \
	(u4) (((u4) buff[0] << 24) \
			| (((u4) buff[1] << 16) & 0xff0000) \
			| (((u4) buff[2] << 8) & 0xff00) \
			| (buff[3] & 0xff)) 

/**
 * ClassFile関連の変数を初期化する
 */
void init_ClassFile_settings() {
	g_Code_name = intern_utf8("Code");
	g_ConstantValue_name = intern_utf8("ConstantValue");
	g_SourceFile_name = intern_utf8("SourceFile");
	g_LineNumberTable_name = intern_utf8("LineNumberTable");
	g_Exceptions_name = intern_utf8("Exceptions");
	g_InnerClasses_name = intern_utf8("InnerClasses");

	g_Signature_name = intern_utf8("Signature");
	
	g_RuntimeVisibleAnnotations = intern_utf8("RuntimeVisibleAnnotations");
	g_RuntimeVisibleParameterAnnotations = intern_utf8("RuntimeVisibleParameterAnnotations");

	g_primitive_class_names[0] = intern_utf8("void");
	g_primitive_class_names[1] = intern_utf8("boolean");
	g_primitive_class_names[2] = intern_utf8("byte");
	g_primitive_class_names[3] = intern_utf8("char");
	g_primitive_class_names[4] = intern_utf8("short");
	g_primitive_class_names[5] = intern_utf8("int");
	g_primitive_class_names[6] = intern_utf8("long");
	g_primitive_class_names[7] = intern_utf8("float");
	g_primitive_class_names[8] = intern_utf8("double");
}

/**
 * 指定されたClassFile構造体に割り当てられたメモリを解放する
 */
void free_ClassFile(ClassFile* cfile) {
	// ToDo:実装する
}

/**
 * 指定されたバッファの内容を読み込み、ClassFile構造体に格納する
 */
ClassFile* parse_ClassFile(frame* frm,
						   class_loader* loader,
						   const char* buff,
						   size_t bufflen) {
	ClassFile* cfile_p = NULL;
	size_t buffleft = bufflen;
	bool verify = needs_verify(loader);
	PermanentHeap* heap = get_heap_of_class_loader(loader);

// バッファサイズチェック用マクロ
#define CHECK_BUFFER_SIZE(len) { \
		if (buffleft < (len)) { \
			assert(false); \
			free_ClassFile(cfile_p); \
			throw_exception(frm, "java/lang/ClassFormatError", "Class file is truncated"); \
			return NULL; \
		} \
		buffleft -= (len); \
	}

	// 最初の時点で、bufflen は以下のサイズ分必要
	// u4 magic
	// u2 minor_version 
	// u2 major_version
	// u2 constant_pool_count
	CHECK_BUFFER_SIZE(sizeof(u4) + sizeof(u2) + sizeof(u2) + sizeof(u2));

	// magicをチェックする
	u4 magic = load_u4(buff);
	buff += sizeof(u4);
	if (magic != MAGIC) {
		// 不正なmagicの場合はリターンする
		return NULL;
	}

	// ClassFile構造体を確保する
//	cfile_p = (ClassFile*) calloc(sizeof(ClassFile), 1);
	cfile_p = (ClassFile*) heap->allocate(sizeof(ClassFile));
	if (cfile_p == NULL) {
		// メモリ不足
		fatal_error(FATAL_ERROR_NO_MEMORY);
	}
	
	cfile_p->defining_loader = loader;
	cfile_p->status = CLASS_FILE_LOADING;

	// version
	if (verify) {
		u2 minor_version = load_u2(buff);
		u2 major_version = load_u2(buff + sizeof(u2));
		u4 version = (u4) major_version << 16 | (u4) minor_version;
		if (version < MINIMUM_VERSION /* || version > MAXIMUM_VERSION */ ) {
			// サポートしていないバージョン
			char* msg = (char*) malloc(64);
			if (! msg) {
				fatal_error(FATAL_ERROR_NO_MEMORY);
			}
			_snprintf(msg,
					  64 - 1,
					  "Unsupported major.minor version %d.%d",
					  major_version,
					  minor_version);
			msg[63] = '\0';
			throw_exception(frm, "java/lang/UnsupportedClassVersionError", msg);
			free(msg);
			
			free_ClassFile(cfile_p);
			return NULL;
		}
	}
	buff += (sizeof(u2) + sizeof(u2));

	// constant_pool_countを読み込む
	cfile_p->constant_pool_count = load_u2(buff);
	buff += sizeof(u2);
	
	// constant_poolを読み込む
	size_t size = sizeof(cp_info*) * cfile_p->constant_pool_count;
	// コンスタントプール領域用のメモリを確保する
	// char* tmp = (char*) calloc(size + sizeof(u1) * cfile_p->constant_pool_count, 1);
	char* tmp = (char*) heap->allocate(size + sizeof(u1) * cfile_p->constant_pool_count);
    if (tmp == NULL) {
		// メモリ不足
		fatal_error(FATAL_ERROR_NO_MEMORY);
	}
	cfile_p->constant_pool = (cp_info**) tmp;
	cfile_p->constant_pool_tags = (u1*) (tmp + size);
	
	// constant_pool を読み込む
	// （添え字は１から始まることに注意）
	for (int i = 1; i < cfile_p->constant_pool_count; ++i) {
		CHECK_BUFFER_SIZE(sizeof(u1));
		const u1 tag = (u1)(*buff);
		buff++;
		
		cfile_p->constant_pool_tags[i] = tag;
		switch (tag) {
			case CONSTANT_Utf8:
			{
				CHECK_BUFFER_SIZE(sizeof(u2));
				u2 length = load_u2(buff);
				buff += sizeof(u2);

				// UTF-8文字列を「インターン」した結果を格納する
				CHECK_BUFFER_SIZE(length);
				cfile_p->constant_pool[i] = (cp_info*) intern_utf8(buff, length);
				buff += length;

				break;
			}

			case CONSTANT_Integer:
			{
				// 値をそのまま格納する
				CHECK_BUFFER_SIZE(sizeof(u4));
				cfile_p->constant_pool[i] = (cp_info*) load_u4(buff);
				buff += sizeof(u4);

				break;
			}

			case CONSTANT_Float:
			{
				// 値をそのまま格納する
				cfile_p->constant_pool[i] = (cp_info*) load_u4(buff);
				CHECK_BUFFER_SIZE(sizeof(u4));
				buff += sizeof(u4);
	
				break;
			}

			case CONSTANT_Long:
			case CONSTANT_Double:
			{
				// 値をそのまま格納する
				CHECK_BUFFER_SIZE(sizeof(u4) + sizeof(u4));
				cfile_p->constant_pool[i + 1] = (cp_info*) load_u4(buff);	// 上位32ビット
				buff += sizeof(u4);
				cfile_p->constant_pool[i] = (cp_info*) load_u4(buff);		// 下位32ビット
				buff += sizeof(u4);
				i++;	// 2スロット消費する

				break;
			}

			case CONSTANT_Class:
			{
				// インデックス値をそのまま格納する
				CHECK_BUFFER_SIZE(sizeof(u2));
				cfile_p->constant_pool[i] = (cp_info*) load_u2(buff);
				buff += sizeof(u2);

				break;
			}

			case CONSTANT_String:
			{
				CHECK_BUFFER_SIZE(sizeof(u2));
				cfile_p->constant_pool[i] = (cp_info*) load_u2(buff);	// とりあえずインデックス値を入れておく
				buff += sizeof(u2);

				break;
			}

			case CONSTANT_Fieldref:
			{
//				CONSTANT_Fieldref_info* fieldref
//					= (CONSTANT_Fieldref_info*) calloc(sizeof(CONSTANT_Fieldref_info), 1);
				CONSTANT_Fieldref_info* fieldref
					= (CONSTANT_Fieldref_info*) heap->allocate(sizeof(CONSTANT_Fieldref_info));
				if (fieldref == NULL) {
					fatal_error(FATAL_ERROR_NO_MEMORY);
				}
				
				CHECK_BUFFER_SIZE(sizeof(u2) + sizeof(u2));
				fieldref->class_name = (java_utf8*) load_u2(buff);	// とりあえずインデックス値を入れておく
				buff += sizeof(u2);
				fieldref->field_name = (java_utf8*) load_u2(buff);	// とりあえずインデックス値を入れておく
				buff += sizeof(u2);
				
				cfile_p->constant_pool[i] = (cp_info*) fieldref;

				break;
			}

			case CONSTANT_Methodref:
			{
//				CONSTANT_Methodref_info* methodref
//					= (CONSTANT_Methodref_info*) calloc(sizeof(CONSTANT_Methodref_info), 1);
				CONSTANT_Methodref_info* methodref
					= (CONSTANT_Methodref_info*) heap->allocate(sizeof(CONSTANT_Methodref_info));
				if (methodref == NULL) {
					fatal_error(FATAL_ERROR_NO_MEMORY);
				}
				
				CHECK_BUFFER_SIZE(sizeof(u4));
				u4 tmp = load_u4(buff);
				buff += sizeof(u4);

				methodref->class_name = (java_utf8*) (tmp >> 16);	// とりあえずインデックス値を入れておく
				methodref->method_name = (java_utf8*) (u2) tmp;		// とりあえずインデックス値を入れておく
				
				// パラメータ数に -1 を設定しておく。
				methodref->parameters_count = -1;
				
				// メソッドテーブルインデックスに-1を設定しておく。
				methodref->method_table_index = -1;

				cfile_p->constant_pool[i] = (cp_info*) methodref;
			
				break;
			}

			case CONSTANT_InterfaceMethodref:
			{
				CHECK_BUFFER_SIZE(sizeof(u2) + sizeof(u2));
				u2 class_index = load_u2(buff);
				buff += sizeof(u2);
				u2 name_and_type_index = load_u2(buff);
				buff += sizeof(u2);
				
				// 下位16ビットに class_indexを、上位16ビットに name_and_type_index をそれぞれ格納する
				cfile_p->constant_pool[i] = (cp_info*) (((u4) name_and_type_index << 16) | class_index);

				break;
			}

			case CONSTANT_NameAndType:
			{
				CHECK_BUFFER_SIZE(sizeof(u2) + sizeof(u2));
				u2 name = load_u2(buff);
				buff += sizeof(u2);
				u2 desc = load_u2(buff);
				buff += sizeof(u2);

				// 下位16ビットに name_index を、上位16ビットに descriptor_index をそれぞれ格納する
				u4 value = (u4) (((u4) desc << 16) | name);
				cfile_p->constant_pool[i] = (cp_info*) value;
				break;
			}
			default:
				// 解釈できないタグ
				DBG(_T("FATAL: Unknown cp->tag"));
				assert(false);
				free_ClassFile(cfile_p);
				return NULL;
		}
	}

	// バッファサイズをチェックする
	// access_flags
	// this_class
	// super_class
	// interfaces_count
	CHECK_BUFFER_SIZE(sizeof(u2) + sizeof(u2) + sizeof(u2) + sizeof(u2));

	// access_flags
	cfile_p->access_flags = load_u2(buff);
	buff += sizeof(u2);

	// this_class
	cfile_p->this_class_name = (java_utf8*) load_u2(buff);	// とりあえずインデックス値を入れておく
	buff += sizeof(u2);

	// super_class
	cfile_p->super_class_name = (java_utf8*) load_u2(buff);	// とりあえずインデックス値を入れておく
	buff += sizeof(u2);

	// interfaces_count
	cfile_p->interfaces_count = load_u2(buff);
	buff += sizeof(u2);

	// interfaces
//	cfile_p->interfaces = (u2*) malloc(sizeof(u2) * cfile_p->interfaces_count);
	cfile_p->interfaces = (u2*) heap->allocate(sizeof(u2) * cfile_p->interfaces_count);
	if (cfile_p->interfaces == NULL) {
		fatal_error(FATAL_ERROR_NO_MEMORY);
	}
	CHECK_BUFFER_SIZE(sizeof(u2) * cfile_p->interfaces_count);
	{
		for (int j = 0; j < cfile_p->interfaces_count; ++j) {
			*(cfile_p->interfaces + j) = load_u2(buff);
			buff += sizeof(u2);
		}
	}
	
	// fields_count
	CHECK_BUFFER_SIZE(sizeof(u2));
	cfile_p->fields_count = load_u2(buff);
	buff += sizeof(u2);

	// fields
	// 固定長なので、1回のmalloc()で確保する
//	cfile_p->fields = (field_info*) malloc(sizeof(field_info) * cfile_p->fields_count);
	cfile_p->fields = (field_info*) heap->allocate(sizeof(field_info) * cfile_p->fields_count);
	if (! cfile_p->fields) {
		fatal_error(FATAL_ERROR_NO_MEMORY);
	} else {
		for (int j = 0; j < cfile_p->fields_count; ++j) {
			CHECK_BUFFER_SIZE(sizeof(u2) + sizeof(u2) + sizeof(u2) + sizeof(u2));
			field_info* info = &cfile_p->fields[j];
			info->access_flags = load_u2(buff);
			buff += sizeof(u2);
			info->name = (java_utf8*) load_u2(buff);		// とりあえずインデックス値を入れておく
			buff += sizeof(u2);
			info->descriptor = (java_utf8*) load_u2(buff);	// とりあえずインデックス値を入れておく
			buff += sizeof(u2);
			u2 attributes_count = load_u2(buff);
			buff += sizeof(u2);

			info->constantvalue_index = 0;	// 0で初期化しておく
			
			info->declaring_ClassFile = cfile_p;

			// アトリビュートを読み込む
			if (attributes_count) {
				size_t length = load_attributes(buff,
												buffleft,
												attributes_count,
												cfile_p->constant_pool,
												info);
				CHECK_BUFFER_SIZE(length);
				buff += length;
			}
		}
	}

	// methods_count
	CHECK_BUFFER_SIZE(sizeof(u2));
	cfile_p->methods_count = load_u2(buff);
	buff += sizeof(u2);

	// methods
	// 固定長なので、1回のmalloc()で確保する
	// cfile_p->methods = (method_info*) malloc(sizeof(method_info) * cfile_p->methods_count);
	cfile_p->methods = (method_info*) heap->allocate(sizeof(method_info) * cfile_p->methods_count);
	if (! cfile_p->methods) {
		fatal_error(FATAL_ERROR_NO_MEMORY);
	} else {
		for (int j = 0; j < cfile_p->methods_count; ++j) {
			CHECK_BUFFER_SIZE(sizeof(u2) * 4);
			method_info* info = &cfile_p->methods[j];
			info->access_flags = load_u2(buff);
			buff += sizeof(u2);
			info->name = (java_utf8*) load_u2(buff);	// とりあえずインデックス値を入れておく
			buff += sizeof(u2);
			info->descriptor = (java_utf8*) load_u2(buff);	// とりあえずインデックス値を入れておく
			buff += sizeof(u2);
			u2 attributes_count = load_u2(buff);
			buff += sizeof(u2);
			
			info->code_attribute = NULL;
			info->exceptions_attribute = NULL;
			if (attributes_count) {
				size_t length = load_attributes(buff,
												buffleft,
												attributes_count,
												cfile_p->constant_pool,
												info,
												heap);
				CHECK_BUFFER_SIZE(length);
				buff += length;
			}

			// パラメータ数を-1に初期化する
			info->parameters_count = -1;
			
			// 戻り値のタイプをNULLに初期化する
			info->return_type = NULL;

			info->declaring_ClassFile = cfile_p;
		}
	}
	
	// attribute_count
	CHECK_BUFFER_SIZE(sizeof(u2));
	u2 attributes_count = load_u2(buff);
	buff += sizeof(u2);
	
	// アトリビュートを読み込む
	if (attributes_count) {
		size_t length = load_attributes(buff, buffleft, attributes_count, cfile_p, heap);
		CHECK_BUFFER_SIZE(length);
		buff += length;
	}

	// バッファ内の全データを読み込んだかチェックする
	if (verify && buffleft) {
		// 余計なバイトが後ろにくっついている
		free_ClassFile(cfile_p);
		return NULL;
	}

	// ここまででクラスファイルからのロードは完了

	// constant_pool の一貫性をチェックする
	if (verify) {
		if (! check_constant_pool_consistency(cfile_p)) {
			assert(false);
			free_ClassFile(cfile_p);
			return NULL;
		}
	}

	// java_utf8への参照を解決する
	init_utf8_references(cfile_p);

	cfile_p->static_data_stat = NULL;
	
	// Update status
	cfile_p->status = CLASS_FILE_LOADED;

	DBG(_T("JVM parsed class:"));
	DBG_UTF8(cfile_p->this_class_name);
	DBG(_T("\n"));

#ifdef DEBUG
	for (int i = 0; i < cfile_p->methods_count; ++i) {
		method_info* minfo = &cfile_p->methods[i];
		Code_attribute* code = minfo->code_attribute;
		if (code && code->code[0] == 177 && code->code_length == 1) {
			// RETURN命令のみのJavaメソッド
			DBG(_T("Empty Java method."));
			DBG_UTF8(minfo->name);
			DBG_UTF8(minfo->descriptor);
			DBG(_T("\n"));
		}
	}
#endif

	return cfile_p;	

#undef CHECK_BUFFER_SIZE
}

/**
 * constant_poolの一貫性をチェックする
 * この関数は、CONSTANT_UTF8_info への解決が行われる＊前に＊呼び出す必要がある
 */
static bool check_constant_pool_consistency(ClassFile* cfile) {
#define CHECK_RANGE(index) { \
		if ((index) < 1 || (index) >= cfile->constant_pool_count) { \
			return false; \
		} \
	}

	// this_class が CONSTANT_Classかを調べる
	if (cfile->constant_pool_tags[(u2) cfile->this_class_name] != CONSTANT_Class) {
		return false;
	}

	// super_class が CONSTANT_Classかを調べる
	if (cfile->super_class_name
			&& cfile->constant_pool_tags[(u2) cfile->super_class_name] != CONSTANT_Class) {
		return false;
	}

	// すべてのタグをチェックする
	for (int i = 1; i < cfile->constant_pool_count; ++i) {
		switch (cfile->constant_pool_tags[i]) {
		case CONSTANT_Long:
		case CONSTANT_Double:
			i++;
			break;
	
		case CONSTANT_Integer:
		case CONSTANT_Float:
		case CONSTANT_Utf8:
			break;

		case CONSTANT_Class:
			{
				u2 index = (u2) cfile->constant_pool[i];
				CHECK_RANGE(index);
				if (cfile->constant_pool_tags[index] != CONSTANT_Utf8) {
					return false;
				}
			}
			break;

		case CONSTANT_Fieldref:
			{
				CONSTANT_Fieldref_info* fieldref
					= (CONSTANT_Fieldref_info*) cfile->constant_pool[i];
				u2 index = (u2) fieldref->class_name;
				CHECK_RANGE(index);
				if (cfile->constant_pool_tags[index] != CONSTANT_Class) {
					return false;
				}
				index = (u2) fieldref->field_name;
				CHECK_RANGE(index);
				if (cfile->constant_pool_tags[index] != CONSTANT_NameAndType) {
					return false;
				}
			}
			break;

		case CONSTANT_Methodref:
			{
				CONSTANT_Methodref_info* ref
					= (CONSTANT_Methodref_info*) cfile->constant_pool[i];
				u2 index = (u2) ref->class_name;
				CHECK_RANGE(index);
				if (cfile->constant_pool_tags[index] != CONSTANT_Class) {
					return false;
				}
				index = (u2) ref->method_name;
				CHECK_RANGE(index);
				if (cfile->constant_pool_tags[index] != CONSTANT_NameAndType) {
					return false;
				}
			}
			break;
		
		case CONSTANT_InterfaceMethodref:
			{
				u4 value = (u4) cfile->constant_pool[i];
				u2 index = (u2) value;
				CHECK_RANGE(index);
				if (cfile->constant_pool_tags[index] != CONSTANT_Class) {
					return false;
				}
				index = (u2) (value >> 16);
				CHECK_RANGE(index);
				if (cfile->constant_pool_tags[index] != CONSTANT_NameAndType) {
					return false;
				}
			}
			break;

		case CONSTANT_String:
			{
				u2 index = (u2) cfile->constant_pool[i];
				CHECK_RANGE(index);
				if (cfile->constant_pool_tags[index] != CONSTANT_Utf8) {
					return false;
				}
			}
			break;
		
		case CONSTANT_NameAndType:
			{
				u4 value = (u4) cfile->constant_pool[i];
				u2 index = (u2) value;
				CHECK_RANGE(index);
				if (cfile->constant_pool_tags[index] != CONSTANT_Utf8) {
					return false;
				}
				index = (u2) (value >> 16);
				CHECK_RANGE(index);
				if (cfile->constant_pool_tags[index] != CONSTANT_Utf8) {
					return false;
				}
			}
			break;
		
		default:
			return false;
		}
	}
	return true;
}

/**
 * java_utf8への参照を解決する
 * クラスファイルを読み込んだ時点で、java_utf8のインデックス値となっているフィールドについて、
 * java_utf8* への解決を行う。
 */
static void init_utf8_references(ClassFile* cfile_p) {
	// this_class_name
	u2 this_class = (u2) cfile_p->this_class_name;
	int cidx = (u2) cfile_p->constant_pool[this_class];
	cfile_p->this_class_name = (java_utf8*) cfile_p->constant_pool[cidx];

	// super_class_name
	u2 super_class = (u2) cfile_p->super_class_name;
	if (super_class != 0) {
		cfile_p->super_class_name = (java_utf8*) cfile_p->constant_pool[(u2) cfile_p->constant_pool[super_class]];
	} else {
		cfile_p->super_class_name = NULL;
	}
	// コンスタントプール内の情報を処理する
	for (int i = 1; i < cfile_p->constant_pool_count; ++i) {
		cp_info* cp = cfile_p->constant_pool[i];
		if (cp != NULL) {
			switch (cfile_p->constant_pool_tags[i]) {
			case CONSTANT_Fieldref:
				{
					CONSTANT_Fieldref_info* fieldref
							= (CONSTANT_Fieldref_info*) cp;
					u2 class_index = (u2) fieldref->class_name;
					const u2 class_name_index = (u2) cfile_p->constant_pool[class_index];
					// クラス名を設定する
					fieldref->class_name
						= (java_utf8*) cfile_p->constant_pool[class_name_index];

					//フィールド名とディスクリプタを取得する
					u2 name_and_type_index = (u2) fieldref->field_name;

					u4 name_and_type = (u4) cfile_p->constant_pool[name_and_type_index];
					// 下位16ビットに name_index が、上位16ビットに type_index がそれぞれ格納されている
					fieldref->field_name = (java_utf8*) cfile_p->constant_pool[(u2) name_and_type];
					fieldref->field_descriptor = (java_utf8*) cfile_p->constant_pool[(u2) (name_and_type >> 16)];
					
					break;
				}

			case CONSTANT_Methodref:
				{
					CONSTANT_Methodref_info* methodref = (CONSTANT_Methodref_info*) cp;
					u2 class_index = (u2) methodref->class_name;

					// クラス名を設定する
					const u2 class_name_index = (u2) cfile_p->constant_pool[class_index];
					methodref->class_name = (java_utf8*) cfile_p->constant_pool[class_name_index];

					// メソッド名とディスクリプタを取得する
					u2 name_and_type_index = (u2) methodref->method_name;
					u4 value = (u4) cfile_p->constant_pool[name_and_type_index];
					methodref->method_name = (java_utf8*) cfile_p->constant_pool[(u2) value];
					methodref->method_descriptor = (java_utf8*) cfile_p->constant_pool[value >> 16];
				
					break;
				}
			case CONSTANT_String:
				{
					const u2 string_index = (u2) cp;
					cfile_p->constant_pool[i]
							= (cp_info*) get_java_utf8(cfile_p, string_index);

				}
			}
		}
	}
	
	// field_info構造体内の情報を処理する
	for (int i = 0; i < cfile_p->fields_count; ++i) {
		field_info* finfo = &cfile_p->fields[i];
		u2 name_index = (u2) finfo->name;
		u2 descriptor_index = (u2) finfo->descriptor;
		finfo->name = (java_utf8*) cfile_p->constant_pool[name_index];
		finfo->descriptor = (java_utf8*) cfile_p->constant_pool[descriptor_index];
	}

	// method_info 構造体内の情報を処理する
	for (int i = 0; i < cfile_p->methods_count; ++i) {
		method_info* minfo = &cfile_p->methods[i];
		u2 name_index = (u2) minfo->name;
		u2 descriptor_index = (u2) minfo->descriptor;
		minfo->name = (java_utf8*) cfile_p->constant_pool[name_index];
		minfo->descriptor = (java_utf8*) cfile_p->constant_pool[descriptor_index];
	}
	return;
}

/**
 * アトリビュート名を取得する
 */
static inline java_utf8* get_attribute_name(ClassFile* cfile, u2 attribute_name_index) {
	return (java_utf8*) get_cp_info(cfile, attribute_name_index, CONSTANT_Utf8);
}

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

	assert(*mdesc == '(');
	mdesc++;

	while (*mdesc != '\0' && *mdesc != ')') {
		switch (*mdesc++) {
		case '[':
			// 配列
			{
				count++;
				bool in_obj = false;
				while (*mdesc && *mdesc != ')') {
					char c = *mdesc++;
					if (c == 'L' && !in_obj) {
						in_obj = true;
						continue;
					}
					if (in_obj) {
						if (c == ';') {
							break;
						}
					} else if (c == 'Z'
							|| c == 'B'
							|| c == 'C'
							|| c == 'S'
							|| c == 'I'
							|| c == 'J'
							|| c == 'F'
							|| c == 'D') {
						break;
					}
				}
			}
			break;

		case 'L':
			// オブジェクト
			count++;
			while (*mdesc && *mdesc != ')') {
				char c = *mdesc++;
				if (c == ';') {
					break;
				}
			}
			break;

		case 'B':
		case 'C':
		case 'F':
		case 'I':
		case 'S':
		case 'Z':
			count++;
			break;

		case 'D':
		case 'J':
			// doubleとlongは２スロット使用する
			count += 2;
			break;
			
		default:
			assert(false);
		}
	}
	return count;
}

/**
 * 指定されたメソッドの戻り値タイプを返す。
 */
const char* get_return_type(method_info* minfo) {
	if (minfo->return_type == NULL) {
		minfo->return_type = strrchr(minfo->descriptor, ')') + 1;
	}
	return minfo->return_type;
}

/**
 * 指定されたインデックスに対応する method_info 構造体へのポインタを返す。
 *
 * @param	cfile	取得対象となるClassFile構造体へのポインタ
 * @param	index	取得対象となるmethod_info構造体のインデックス
 * @return	対応する method_info 構造体へのポインタ。取得できなかった場合はNULL。
 */
static inline method_info* get_declared_method_info_by_index(ClassFile* cfile, u2 index) {
	assert(index < cfile->methods_count);
	return &cfile->methods[index];
}

/**
 * 指定されたクラスファイル内に、指定された名前およびディスクリプタを持つメソッドがあるか
 * 検索する
 *
 * @param	cfile	検索対象となるクラス。
 * @param	name	検索対象となるメソッドの名前。
 * @param	desc	検索対象となるメソッドのディスクリプタ。
 * @return	検索結果。一致するメソッドが存在しなかった場合はNULL。
 */
method_info* find_declaring_method_info(ClassFile* cfile, const java_utf8* name, const java_utf8* desc) {
	method_info* result = NULL;
	// intern_utf8()されていることを前提にする
	// name = intern_utf8(name);
	// desc = intern_utf8(desc);
	for (u2 i = 0; i < cfile->methods_count; ++i) {
		method_info* minfo = get_declared_method_info_by_index(cfile, i);
		// 名前と定義を比較する
		const java_utf8* mname = minfo->name;
		const java_utf8* mdesc = minfo->descriptor;
		if (name == mname && desc == mdesc) {
			result = minfo;
			break;
		}
	}
	return result;
}

/**
 * 配列のClassFileを作成する
 * 配列のClassFileは、以下のとおりとする
 *
 * constant_pool_count = 9
 * constant_pool[] = { NULL, <- 内部的に使用
 *                     java_utf8(この配列のクラス名),					:1
 *                     java_utf8("java/lang/Object"),					:2
 *                     java_utf8("java/lang/Cloneable"),				:3
 *                     java_utf8("java/io/Serializable"),				:4
 *                     CONSTANT_Class_info(2), <- java.lang.Object		:5
 *                     CONSTANT_Class_info(3), <- java.lang.Cloneable	:6
 *                     CONSTANT_Class_info(4), <- java.io.Serializable	:7
 *                     CONSTANT_Class_info(1), <- この配列のクラス		:8
 *                     }
 * access_flags  = ACC_SUPER | ACC_FINAL | ACC_PUBLIC
 * this_class_name  = この配列のクラス名(constant_pool[1])
 * super_class_name = java/lang/Object(constant_pool[2])
 * interfaces_count = 2
 * interfaces[]  = {
 *                  6, <- Cloneable
 *                  7  <- Serializable
 *                 }
 * fields_count  = 0
 * fields[]      = {}
 * methods_count = 0 <- 空
 * methods[]     = {} <- 空
 * attributes_count = 0
 * attributes[] = {} <- 空
 */
ClassFile* create_array_ClassFile(class_loader* l, const java_utf8* class_name, u2 access_flags) {
	PermanentHeap* heap = get_heap_of_class_loader(l);
//	ClassFile* class_file = (ClassFile*) calloc(sizeof(ClassFile), 1);
	ClassFile* class_file = (ClassFile*) heap->allocate(sizeof(ClassFile));
	if (class_file == NULL) {
		fatal_error(FATAL_ERROR_NO_MEMORY);
	}
	static u1* constant_pool_tags;

	// コンスタントプール数
	class_file->constant_pool_count = 9;
	// class_file->constant_pool = (cp_info**) malloc(sizeof(cp_info*) * class_file->constant_pool_count);
	class_file->constant_pool = (cp_info**) heap->allocate(sizeof(cp_info*) * class_file->constant_pool_count);
	if (class_file->constant_pool == NULL) {
		fatal_error(FATAL_ERROR_NO_MEMORY);
	}

	if (! constant_pool_tags) {
		// constant_pool_tags = (u1*) malloc(sizeof(u1) * class_file->constant_pool_count);
		constant_pool_tags = (u1*) heap->allocate(sizeof(u1) * class_file->constant_pool_count);
		constant_pool_tags[0] = 0;
		constant_pool_tags[1] = CONSTANT_Utf8;
		constant_pool_tags[2] = CONSTANT_Utf8;
		constant_pool_tags[3] = CONSTANT_Utf8;
		constant_pool_tags[4] = CONSTANT_Utf8;
		constant_pool_tags[5] = CONSTANT_Class;
		constant_pool_tags[6] = CONSTANT_Class;
		constant_pool_tags[7] = CONSTANT_Class;
		constant_pool_tags[8] = CONSTANT_Class;
	}
	class_file->constant_pool_tags = constant_pool_tags;

	// constant_pool[0];
	class_file->constant_pool[0] = NULL;

	// constant_pool[1]
//	class_file->constant_pool[1] = (cp_info*) intern_utf8(class_name);
	assert(intern_utf8(class_name) == class_name);
	class_file->constant_pool[1] = (cp_info*) class_name;

	// constant_pool[2]
	class_file->constant_pool[2] = (cp_info*) JAVA_LANG_OBJECT_CLASS_NAME;

	// constant_pool[3]
	class_file->constant_pool[3] = (cp_info*) JAVA_LANG_CLONEABLE_CLASS_NAME;

	// constant_pool[4]
	class_file->constant_pool[4] = (cp_info*) JAVA_IO_SERIALIZABLE_CLASS_NAME;

	// constant_pool[5]
	class_file->constant_pool[5] = (cp_info*) 2;

	// constant_pool[6]
	class_file->constant_pool[6] = (cp_info*) 3;

	// constant_pool[7]
	class_file->constant_pool[7] = (cp_info*) 4;

	// constant_pool[8]
	class_file->constant_pool[8] = (cp_info*) 1;

	// class_file->access_flags = ACC_SUPER | ACC_FINAL | ACC_PUBLIC;
	class_file->access_flags = ACC_SUPER | ACC_FINAL | access_flags;
	class_file->this_class_name = (java_utf8*) class_file->constant_pool[1];
	class_file->super_class_name = (java_utf8*) class_file->constant_pool[2];
	class_file->interfaces_count = 2;
	
	// class_file->interfaces = (u2*) malloc(sizeof(u2) * class_file->interfaces_count);
	class_file->interfaces = (u2*) heap->allocate(sizeof(u2) * class_file->interfaces_count);
	if (class_file->interfaces == NULL) {
		fatal_error(FATAL_ERROR_NO_MEMORY);
	}
	class_file->interfaces[0] = 6;
	class_file->interfaces[1] = 7;

	class_file->fields_count = 0;
	// class_file->fields = (field_info*) malloc(0);
	class_file->fields = (field_info*) heap->allocate(0);

	class_file->methods_count = 0;
	// class_file->methods = (method_info*) malloc(0);
	class_file->methods = (method_info*) heap->allocate(0);

	class_file->defining_loader = l;
	class_file->static_data_stat = NULL;

	return class_file;
}

/**
 * プリミティブクラスファイルを作成する
 * 配列のClassFileは、以下のとおりとする
 *
 * constant_pool_count = 1
 * constant_pool[] = { NULL, <- 内部的に使用        : 0
 *                     java_utf8(クラス名),			: 1
 *                   }
 * access_flags     = ACC_SUPER | ACC_FINAL | ACC_PUBLIC
 * this_class_name  = クラス名(constant_pool[1])
 * super_class_name = NULL
 * interfaces_count = 0
 * interfaces[]  = {}
 * fields_count  = 0
 * fields[]      = {}
 * methods_count = 0
 * methods[]     = {}
 * attributes_count = 0
 * attributes[] = {} <- 空
 *
 * @param	class_name	プリミティブクラス名
 * @return	対応するClassFile構造体へのポインタ
 */
ClassFile* create_primitive_ClassFile(const java_utf8* class_name) {
	PermanentHeap* heap = get_heap_of_class_loader(get_bootstrap_class_loader());

	// ClassFile* class_file = (ClassFile*) calloc(sizeof(ClassFile), 1);
	ClassFile* class_file = (ClassFile*) heap->allocate(sizeof(ClassFile));
	if (class_file == NULL) {
		fatal_error(FATAL_ERROR_NO_MEMORY);
	}
	
	// コンスタントプール数
	class_file->constant_pool_count = 2;
	// class_file->constant_pool = (cp_info**) malloc(sizeof(cp_info*) * class_file->constant_pool_count);
	class_file->constant_pool = (cp_info**) heap->allocate(sizeof(cp_info*) * class_file->constant_pool_count);
	// class_file->constant_pool_tags = (u1*) malloc(sizeof(u1) * class_file->constant_pool_count);
	class_file->constant_pool_tags = (u1*) heap->allocate(sizeof(u1) * class_file->constant_pool_count);
	if (class_file->constant_pool == NULL || class_file->constant_pool_tags == NULL) {
		fatal_error(FATAL_ERROR_NO_MEMORY);
	}
	
	// constant_pool[0];
	class_file->constant_pool[0] = NULL;

	// constant_pool[1]
	class_file->constant_pool[1] = (cp_info*) intern_utf8(class_name);
	class_file->constant_pool_tags[1] = CONSTANT_Utf8;

	class_file->access_flags = ACC_SUPER | ACC_FINAL | ACC_PUBLIC;
	class_file->this_class_name = (java_utf8*) class_file->constant_pool[1];
	class_file->super_class_name = NULL;
	class_file->interfaces_count = 0;
	
	class_file->interfaces = NULL;

	class_file->fields_count = 0;
	class_file->fields = NULL;

	class_file->methods_count = 0;
	class_file->methods = NULL;

	class_file->defining_loader = get_bootstrap_class_loader();
	class_file->static_data_stat = NULL;

	return class_file;
}


/**
 * フィールドの配置を調整する
 */
static void adjust_field_position(field_info* finfo, u1 size, u2* position) {
	// 各フィールドは、自分自身のサイズ境界上に配置される
	u2 padding = *position % size;
	
	if (padding != 0) {
		// 境界上に配置されるように調整する
		padding = size - padding;
		*position += padding;
	}
}

/**
 * 指定されたフィールドのサイズをバイト単位で返す。
 */
inline static u1 get_field_size(java_utf8* field_descriptor) {
	u1 type = field_descriptor[0];
	switch (type) {
	case 'B':
	case 'Z':
		return 1;

	case 'C':
	case 'S':
		return 2;

	case 'J':
	case 'D':
		return 8;

	default:
		return 4;
	}
}

/**
 * 指定されたフィールドが参照値を保持しているかを返す
 */
static bool is_reference_field(field_info* finfo) {
	u1 type = finfo->descriptor[0];
	switch (type) {
	case 'L':
	case '[':
		return true;
	default:
		return false;
	}
}

/**
 * フィールドテーブルに値を設定する
 */
static void set_field_table_element(field_info* e, u2* position) {
	// フィールドサイズを判定する
	u1 size = get_field_size(e->descriptor);
	e->size = size;

	// フィールドの位置を調整する
	adjust_field_position(e, size, position);
	e->position = *position;
	// 次の配置予定位置を更新する
	*position += size;
}

/**
 * フィールドテーブルの内容をコピーする
 */
static inline void copy_field_table_elements(field_info** dst, field_info** src, int count) {
	memcpy(dst, src, sizeof(field_info*) * count);
}

/**
 * 指定されたフィールドテーブル内の「参照フラグ」を更新する
 */
static void update_field_reference_flags(field_table* tbl, int startpos) {
	for (int i = startpos; i < tbl->fields_count; ++i) {
		field_info* e = tbl->elements[i];
		if (e->size == 4 && is_reference_field(e)) {
			tbl->reference_flags[e->position / 4] = true;
		}
	}
}

/**
 * フィールドテーブルを初期化する
 *
 * @param	cfile	クラスファイル構造体へのポインタ
 * @param	super_class_table	スーパークラスのClassFile。スーパークラスが存在しない場合NULL。
 */
static void init_field_table(ClassFile* cfile,
					  ClassFile* super_class_file,
					  ClassFile** interfaces,
					  u2 interfaces_count) {

	// ヒープ
	assert(cfile->defining_loader);
	PermanentHeap* heap = get_heap_of_class_loader(cfile->defining_loader);
	
	// バッファサイズの計算
	u2 count = cfile->fields_count;
	u2 super_class_fields_count = 0;
	if (super_class_file != NULL) {
		// スーパークラスが存在する場合、そのフィールド数も加算する
		field_table* tab = get_field_table(super_class_file);
		super_class_fields_count = tab->fields_count;
		count += super_class_fields_count;
	}

	// インスタンスフィールド用
	field_table* table = &cfile->instance_field_table;
	// table->elements = (field_info**) malloc(sizeof(field_info*) * count);
	table->elements = (field_info**) heap->allocate(sizeof(field_info*) * count);
	if (! table->elements) {
		fatal_error(FATAL_ERROR_NO_MEMORY);
	}

	// staticフィールド用
	// staticフィールドのテーブルには、インタフェースのフィールドも含める
	if (super_class_file) {
		// スーパークラスが存在する場合、そのフィールド数も加算する
		field_table* tab = get_static_field_table(super_class_file);
		super_class_fields_count = tab->fields_count;
		count += super_class_fields_count;
	}
	for (u2 i = 0; i < interfaces_count; ++i) {
		// インタフェース数分、バッファサイズを加算する
		ClassFile* interface_class_file = interfaces[i];
		field_table* tab = get_static_field_table(interface_class_file);
		count += tab->fields_count;
	}
	field_table* static_table = &cfile->static_field_table;
	// static_table->elements = (field_info**) malloc(sizeof(field_info*) * count);
	static_table->elements = (field_info**) heap->allocate(sizeof(field_info*) * count);
	if (static_table->elements == NULL) {
		fatal_error(FATAL_ERROR_NO_MEMORY);
	}
	
	// 指定されたClassFile内で定義されたフィールドの情報を
	// テンポラリ領域に格納する
	u2 instance_count = 0;
	u2 static_count = 0;
	
	// スーパークラスのstatic/インスタンスフィールド情報をコピーする
	if (super_class_file) {
		// staticフィールド
		field_table* tab = get_static_field_table(super_class_file);
		copy_field_table_elements(static_table->elements, tab->elements, tab->fields_count);
		static_count += tab->fields_count;

		// インスタンスフィールド
		tab = get_field_table(super_class_file);
		copy_field_table_elements(table->elements, tab->elements, tab->fields_count);
		instance_count += tab->fields_count;
	}
	
	// staticフィールドの場合、インタフェースのフィールド情報も入れる
	for (u2 i = 0; i < interfaces_count; ++i) {
		ClassFile* interface_class_file = interfaces[i];
		field_table* tab = get_static_field_table(interface_class_file);
		copy_field_table_elements(&static_table->elements[static_count], tab->elements, tab->fields_count);
		static_count += tab->fields_count;
	}

	// 自分自身の情報を入れる
	// 配置位置を初期化する
	u2 static_pos = 0;
	u2 this_static_fields_start_pos = static_count;
	u2 instance_pos;
	if (super_class_file != NULL) {
		field_table* tab = get_field_table(super_class_file);
		instance_pos = tab->total_size;
	} else {
		instance_pos = 0;
	}

	for (int i = 0; i < cfile->fields_count; ++i) {
		field_info* finfo = &cfile->fields[i];
		if (is_static(finfo->access_flags)) {
			// staticフィールド
			set_field_table_element(finfo, &static_pos);
			static_table->elements[static_count] = finfo;
			static_count++;
		} else {
			// 非staticフィールド
			set_field_table_element(finfo, &instance_pos);
			table->elements[instance_count] = finfo;
			instance_count++;
		}
	}

	static_table->fields_count = static_count;
	static_table->total_size = static_pos;

	table->fields_count = instance_count;
	table->total_size = instance_pos;

	// 参照フラグを初期化する
	unsigned int static_flags_size = sizeof(bool) * (static_table->total_size / 4);
	unsigned int flags_size = sizeof(bool) * (table->total_size / 4);
	// static_table->reference_flags = (bool*) calloc(static_flags_size, 1);
	static_table->reference_flags = (bool*) heap->allocate(static_flags_size);
	// table->reference_flags = (bool*) calloc(flags_size, 1);
	table->reference_flags = (bool*) heap->allocate(flags_size);
	if (! (static_table->reference_flags && table->reference_flags)) {
		fatal_error(FATAL_ERROR_NO_MEMORY);
	}

	update_field_reference_flags(static_table, this_static_fields_start_pos);
	update_field_reference_flags(table, 0);

	// static_table->elements, table->elements は余分にメモリを確保しているため、
	// メモリブロックの縮小処理を行う
#if 0
	// 現在のPermanentHeapはこの処理に対応していないため、コメントアウトしている
	static_table->elements = (field_info**) realloc(static_table->elements,
													sizeof(field_info*) * static_table->fields_count);
	if (! static_table->elements) {
		fatal_error(FATAL_ERROR_NO_MEMORY);
	}

	table->elements = (field_info**) realloc(table->elements,
											  sizeof(field_info*) * table->fields_count);
	if (! table->elements) {
		fatal_error(FATAL_ERROR_NO_MEMORY);
	}
#endif
}

/**
 * staticフィールドのフィールドIDを返す
 */
jfieldID get_static_field_id(ClassFile* cfile,
							 java_utf8* field_name,
							 java_utf8* field_descriptor) {
	field_table* tab = get_static_field_table(cfile);
	// intern_utf8()されていることを前提にする
	// field_name = intern_utf8(field_name);
	// field_descriptor = intern_utf8(field_descriptor);
	for (int i = tab->fields_count - 1; i >= 0; --i) {
		field_info* e = tab->elements[i];
		field_info* finfo = e;
		const java_utf8* name = finfo->name;
		const java_utf8* desc = finfo->descriptor;
		if (field_name == name && field_descriptor == desc) {
			return INDEX_TO_FIELD_ID(i);
		}
	}
	return NULL;
}

/**
 * 非staticフィールドのフィールドIDを返す
 */
jfieldID get_field_id(ClassFile* cfile,
					  java_utf8* field_name,
					  java_utf8* field_descriptor) {
	field_table* tab = get_field_table(cfile);
	// intern_utf8()されていることを前提にする
	// field_name = intern_utf8(field_name);
	// field_descriptor = intern_utf8(field_descriptor);
	for (int i = tab->fields_count - 1; i >= 0; --i) {
		field_info* e = tab->elements[i];
		field_info* finfo = e;
		const java_utf8* name = finfo->name;
		const java_utf8* desc = finfo->descriptor;
		if (field_name == name && field_descriptor == desc) {
			return INDEX_TO_FIELD_ID(i);
		}
	}
	return NULL;
}

/**
 * メソッド・テーブルを初期化する
 */
static bool init_method_table(frame* frm,
							  ClassFile* cfile,
							  ClassFile* superclass,
							  ClassFile** interfaces,
							  u2 interfaces_count) {
	// ヒープ
	assert(cfile->defining_loader);
	PermanentHeap* heap = get_heap_of_class_loader(cfile->defining_loader);

	// テーブルを確保する
	u2 methods_count = cfile->methods_count;
	method_table* mtable = &cfile->mtable;
	method_table* super_class_table;
	if (superclass != NULL) {
		// スーパークラスが存在する場合
		super_class_table = get_method_table(superclass);
		methods_count += super_class_table->methods_count;
	} else {
		super_class_table = NULL;
	}
	
	// 直接実装しているインタフェースのメソッド数を加算する
	for (u2 i = 0; i < interfaces_count; ++i) {
		ClassFile* ifile = interfaces[i];
		method_table* tab = &ifile->mtable;
		methods_count += tab->methods_count;
	}

	mtable->methods_count = methods_count;	// この値は仮の値
	// mtable->elements = (method_info**) calloc(sizeof(method_info*) * methods_count, 1);
	mtable->elements = (method_info**) heap->allocate(sizeof(method_info*) * methods_count);
	if (mtable->elements == NULL) {
		fatal_error(FATAL_ERROR_NO_MEMORY);
	}

	// スーパークラスが存在する場合、そのメソッド・テーブルをコピーする
	u2 element_index;
	if (super_class_table != NULL) {
		memcpy(mtable->elements,
				super_class_table->elements,
				sizeof(method_info*) * super_class_table->methods_count);
		element_index = super_class_table->methods_count;
	} else {
		element_index = 0;
	}
	
	// 自分自身のメソッドのうち、メソッド・テーブルに入れるべきメソッドを順番に入れていく
	for (u2 i = 0; i < cfile->methods_count; ++i) {
		method_info* minfo = get_declared_method_info_by_index(cfile, i);
		if (! is_private(minfo->access_flags)) {
			// private以外
			java_utf8* mname = minfo->name;
			java_utf8* mdesc = minfo->descriptor;
			if (INIT_METHOD_NAME != mname && CLINIT_METHOD_NAME != mname) {
				// <init>と<clinit>以外のメソッド
				bool override = false;
				// スーパークラスのメソッドをオーバーライドしているか調べる
				if (super_class_table != NULL) {
					for (u2 index = 0; index < super_class_table->methods_count; ++index) {
						method_info* super_minfo = mtable->elements[index];
						if (mname == super_minfo->name && mdesc == super_minfo->descriptor) {
							if (is_final(super_minfo->access_flags) && ! is_private(super_minfo->access_flags) && strncmp(cfile->this_class_name, "$Proxy", 6)) {
								// final と宣言されている場合はオーバーライドできない
								char* msg = (char*) malloc(64);
								if (! msg) {
									fatal_error(FATAL_ERROR_NO_MEMORY);
								}
								_snprintf(msg,
										  64 - 1,
										  "Method %s is a final method",
										  mname);
								msg[63] = '\0';
								throw_exception(frm,
												"java/lang/VerifyError",
												msg);
								free(msg);

								// ToDo:作業メモリを開放する
								return false;
							}
							// オーバーライドしている場合、メソッドテーブルを上書きする
							if (! add_loading_constraints_of_method(frm,
																	get_defining_loader(minfo->declaring_ClassFile),
																	get_defining_loader(cfile),
																	minfo->descriptor)) {
								// ロード制約追加失敗
								// （なお、インタフェースに関するロード制約は、
								// 　メソッドテーブルが完成した後に実施する）
								// ToDo:作業メモリを開放する
								return false;
							}
							mtable->elements[index] = minfo;
							override = true;
							break;
						}
					}
				}
				if (! override) {
					// オーバーライドしていない場合、テーブル末尾に追加する
					mtable->elements[element_index++] = minfo;
					// e->declaring_class_file = cfile;
				}

				// finalize() メソッドの有無を調べる
				if (superclass &&
						(FINALIZE_METHOD_NAME == minfo->name
							&& VOID_NOARG_METHOD_DESCRIPTOR == minfo->descriptor)) {
					// ファイナライザの有無を設定する
					cfile->has_finalizer = true;
				}
			}
		}
	}
	
	// スーパークラスがfainalize()を持っている場合、フラグを立てておく
	if (superclass && ! cfile->has_finalizer && superclass->has_finalizer) {
		cfile->has_finalizer = superclass->has_finalizer;
	}

	// インタフェースでは定義されているが、実装はされていないメソッドを
	// メソッドテーブル末尾に追加する
	for (u2 i = 0; i < interfaces_count; ++i) {
		ClassFile* ifile = interfaces[i];
		method_table* imtab = &ifile->mtable;
		for (u2 j = 0; j < imtab->methods_count; ++j) {
			method_info* iminfo = imtab->elements[j];
			bool found = false;
			for (u2 k = 0; k < mtable->methods_count; ++k) {
				method_info* minfo = mtable->elements[k];
				if (minfo && (minfo->name == iminfo->name)
						&& (minfo->descriptor == iminfo->descriptor)) {
					// メソッドは実装されている
					found = true;
					break;
				}
			}
			if (! found) {
				// メソッドが実装されていない場合、テーブル末尾に追加する
				mtable->elements[element_index++] = iminfo;

//				DBG(_T("Method:"));
//				DBG_UTF8(cfile->this_class_name);
//				DBG(_T("."));
//				DBG_UTF8(iminfo->name);
//				DBG_UTF8(iminfo->descriptor);
//				DBG(_T(" is not implemented.\r\n"));
			}
		}
	}

	// メソッド・テーブル上に記録されたメソッド数を修正する
	// （オーバーライドしたメソッドを含まないようにする）
	assert(mtable->methods_count >= element_index);
	mtable->methods_count = element_index;

	// オーバーライドしたメソッドが存在した場合、バッファの後ろに空き領域ができてしまうため
	// サイズを縮小する
#if 0
	現在のPermanentHeapはrealloc()に対応していないため、コメントアウトしている
	mtable->elements = (method_info**) realloc(mtable->elements,
											   sizeof(method_info*) * mtable->methods_count);
	if (! mtable->elements) {
		fatal_error(FATAL_ERROR_NO_MEMORY);
	}
#endif

	// ここまででメソッドテーブルが完成
	
	// 最後に、インタフェースに関するロード制約をチェックする
	for (int i = 0; i < cfile->interfaces_count; ++i) {
		ClassFile* ifile = get_interface_ClassFile(cfile, i);
		if (! process_loading_constraints(frm, ifile, mtable)) {
			// ロード制約追加失敗
			return false;
		}
	}

	return true;
}

/**
 * 指定されたインタフェースとメソッドテーブル間にロード制約を設定する
 */
static bool process_loading_constraints(frame* frm,
												  ClassFile* interface_cfile,
												  method_table* mtable) {
	
	class_loader* loader = get_defining_loader(interface_cfile);
	for (u2 i = 0; i < interface_cfile->methods_count; ++i) {
		method_info* interface_minfo = &interface_cfile->methods[i];
		for (int j = mtable->methods_count - 1; j >= 0; --j) {
			// メソッドテーブルの＊末尾から＊順番に検索してゆき、
			// 一致するメソッドについてロード制約を追加する
			method_info* minfo = mtable->elements[j];
			if (minfo->name == interface_minfo->name
					&& minfo->descriptor == interface_minfo->descriptor) {
				if (! add_loading_constraints_of_method(frm,
														loader,
														get_defining_loader(minfo->declaring_ClassFile),
														minfo->descriptor)) {
					// ロード制約設定失敗
					return false;
				}
				break;
			}
		}
	}

	// 再帰的にロード制約を設定する
	for (int i = 0; i < interface_cfile->interfaces_count; ++i) {
		ClassFile* superinterface_cfile = get_interface_ClassFile(interface_cfile, i);
		if (! process_loading_constraints(frm,
										  superinterface_cfile,
										  mtable)) {
			return false;
		}
	}

	return true;
}

/**
 * メソッドIDを取得する
 */
jmethodID get_method_id(const ClassFile* cfile, const java_utf8* name, const java_utf8* desc) {
	// ------------------------------------------------------------------------------------------------
	// メソッドIDは以下のようにエンコードされる
	// ビット31 - インデックスフラグ：このビットが1である場合は下位16ビットにインデックス値が入る
	//								  0である場合は、下位31ビットが method_info へのポインタである
	// ビット30〜16 - 予約
	// ビット15〜0  - インデックス値：
	// ------------------------------------------------------------------------------------------------

	jmethodID mid = NULL;
	u2 index = 0;
	bool found = false;
	bool is_int = is_interface(cfile->access_flags);
	// メソッド・テーブル内に一致するメソッドがないか調べる
	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) {
			found = true;
			index = i;
			if (is_int) {
				// インタフェースの場合、jmethodIDはmethod_infoそのものになる
				mid = (jmethodID) minfo;
				// デバッグ時にはMETHOD_ID_MASKビットが０であることを確認する
				// （Windows CEのメモリ管理方法が変更されると、これが成り立たなくなる可能性があるため）
				// http://www.microsoft.com/japan/msdn/library/default.asp?url=/japan/msdn/library/ja/jpdnce/htm/advmemmgmt.asp
				assert(! ((unsigned int) mid & METHOD_ID_MASK));
			} else {
				// インタフェース以外の場合下位16ビットにインデックスを入れる
				unsigned int tmp = (index & 0xffff);
				// METHOD_ID_MASKを立てる。2GB以上はシステム予約領域であることに依存している
				mid = (jmethodID) (tmp | METHOD_ID_MASK);
			}
			break;
		}
	}
	
	if (! found) {
		// ClassFile内の method_info 配列を検索する
		for (u2 i = 0; i < cfile->methods_count; ++i) {
			method_info* minfo = &cfile->methods[i];
			const java_utf8* mname = minfo->name;
			const java_utf8* mdesc = minfo->descriptor;
			if (name == mname && desc == mdesc) {
				// メソッドIDにはmethod_infoへのポインタを入れておく
				mid = (jmethodID) minfo;
				// デバッグ時にはMETHOD_ID_MASKビットが０であることを確認する
				// （Windows CEのメモリ管理方法が変更されると、これが成り立たなくなる可能性があるため）
				// http://www.microsoft.com/japan/msdn/library/default.asp?url=/japan/msdn/library/ja/jpdnce/htm/advmemmgmt.asp
				assert(! ((unsigned int) mid & METHOD_ID_MASK));
				break;
			}
		}
	}
	return mid;
}

/**
 * 指定されたjmethodIDに対応する method_info を返す
 */
method_info* get_method_info(ClassFile* cfile, jmethodID mid) {
	if ((unsigned int)mid & METHOD_ID_MASK) {
		// METHOD_ID_MASK が立っている場合、インデックス値として取り扱う
		unsigned int value = (unsigned int) mid & (~METHOD_ID_MASK);
		u2 flags = value >> 16;
		u2 index = (u2) value;
		
		method_info* minfo = NULL;
		method_table* mtab = get_method_table(cfile);
		minfo = mtab->elements[index];
		return minfo;

	} else {
		// METHOD_ID_MASKが立っていない場合、method_infoにキャストできる
		method_info* result = NULL;
		method_info* minfo = (method_info*) mid;
		method_table* mtab = get_method_table(cfile);
		
		if (minfo->declaring_ClassFile == cfile) {
			// そのまま返す
			result = minfo;
		} else if (is_private(minfo->access_flags)) {
			// そのまま返す
			result = minfo;
		} else {
			// メソッドテーブル内を再検索する
			for (u2 i = 0; i < mtab->methods_count; ++i) {
				method_info* minfo2 = mtab->elements[i];
				if (minfo->name == minfo2->name && minfo->descriptor == minfo2->descriptor) {
					result = minfo2;
				}
			}
		}
		assert(result);

		return result;
	}
}

const java_utf8* get_array_component_name(const char* class_name) {
	if (class_name[0] != '[') {
		// 配列ではない
		return NULL;	
	}
	
	int offset;
	int length;

	if (class_name[1] != '[' && class_name[1] != 'L') {
		// プリミティブ型配列の場合
		offset = 1;
		length = 1;

	} else {
		// 参照型配列の場合
		if (class_name[1] == 'L') {
			length = strlen(class_name) - 3;	// 先頭の [L と末尾の ; を取り除く
			offset = 2;
		} else {
			length = strlen(class_name) - 1;	// [ を取り除く
			offset = 1;
		}
	}
	return intern_utf8(class_name + offset, length);
}

const java_utf8* get_SourceFile(ClassFile* cfile) {
	if (cfile->sourcefile_index) {
		return (java_utf8*) cfile->constant_pool[cfile->sourcefile_index];
	} else {
		return NULL;
	}
}

/**
 * field_infoに必要となるアトリビュートをロードする
 */
static unsigned int load_attributes(const char* buff,
									size_t buffleft,
									u2 attributes_count,
									cp_info** constant_pool,
									field_info* finfo) {
	unsigned int count = 0;
	finfo->constantvalue_index = 0;
	for (u2 i = 0; i < attributes_count; ++i) {
		// バッファサイズをチェックする
		if (buffleft < sizeof(u2) + sizeof(u4)) {
			return (size_t) -1;
		}
		buffleft -= (sizeof(u2) + sizeof(u4));

		// アトリビュート名を取得する
		u2 attribute_name_index = load_u2(buff);
		buff += sizeof(u2);
		java_utf8* attr_name = (java_utf8*) constant_pool[attribute_name_index];

		// アトリビュート長
		u4 attribute_length = load_u4(buff);
		buff += sizeof(u4);
		if (buffleft < attribute_length) {
			return (size_t) -1;
		}

		if (g_ConstantValue_name == attr_name) {
			// ConstantValueアトリビュート
			if (attribute_length != sizeof(u2)) {
				return (size_t) -1;
			}
			finfo->constantvalue_index = load_u2(buff);

		} else if (g_Signature_name == attr_name) {
			// Signature
			finfo->signature_index = load_u2(buff);
		} else if (g_RuntimeVisibleAnnotations == attr_name) {
			// RuntimeVisibleAnnotations
			// ToDo: 保持しておく
		}

		buff += attribute_length;
		count += attribute_length + sizeof(u2) + sizeof(u4);
	}
	return count;
}

/**
 * method_infoに必要となるアトリビュートをロードする
 */
static unsigned int load_attributes(const char* buff, size_t buffleft, u2 attributes_count, cp_info** constant_pool, method_info* minfo, PermanentHeap* heap) {
// バッファサイズチェック用マクロ
#define CHECK_BUFFER_SIZE(size) { \
	if (buffleft < size) { \
	    return (size_t) -1; \
	} \
	buffleft -= (size); \
}
	
	unsigned int count = 0;
	for (u2 i = 0; i < attributes_count; ++i) {
		CHECK_BUFFER_SIZE(sizeof(u2) + sizeof(u4));
		
		// アトリビュート名を取得する
		u2 attribute_name_index = load_u2(buff);
		buff += sizeof(u2);
		java_utf8* attr_name = (java_utf8*) constant_pool[attribute_name_index];

		// アトリビュート長
		u4 attribute_length = load_u4(buff);
		buff += sizeof(u4);
		
		CHECK_BUFFER_SIZE(attribute_length);

		const char* org_buff = buff;
		if (g_Code_name == attr_name && minfo->code_attribute == NULL) {
			// Code_attribute
			u2 max_stack = load_u2(buff);
			buff += sizeof(u2);
			u2 max_locals = load_u2(buff);
			buff += sizeof(u2);
			u4 code_length = load_u4(buff);
			buff += sizeof(u4);
			
			// Code_attribute構造体とコード領域分を一度のmalloc()で確保する
			// char* tmp = (char*) malloc(sizeof(Code_attribute) + code_length);
			char* tmp = (char*) heap->allocate(sizeof(Code_attribute) + code_length);
			if (tmp == NULL) {
				fatal_error(FATAL_ERROR_NO_MEMORY);
			}

			Code_attribute* code = (Code_attribute*) tmp;
			code->max_stack = max_stack;
			code->max_locals = max_locals;
			code->code_length = code_length;
			code->code = (u1*) (tmp + sizeof(Code_attribute));

			memcpy(code->code, buff, code->code_length);
			buff += code->code_length;
			
			// "RETURN" 命令だけの場合、ACC_EMPTY フラグを立てておく
			if (code->code[0] == 177 && code_length == 1) {
				assert(! (minfo->access_flags & ACC_EMPTY));
				minfo->access_flags |= ACC_EMPTY;
			}

			// 例外テーブル長
			code->exception_table_length = load_u2(buff);
			buff += sizeof(u2);
			
			//code->exception_table
			//	= (exception_handler_info*) malloc(sizeof(exception_handler_info)
			//											* code->exception_table_length);
			code->exception_table
				= (exception_handler_info*) heap->allocate(sizeof(exception_handler_info)
														* code->exception_table_length);
			if (code->exception_table == NULL) {
				fatal_error(FATAL_ERROR_NO_MEMORY);
			}

			for (int j = 0; j < code->exception_table_length; ++j) {
				code->exception_table[j].start_pc = load_u2(buff);
				buff += sizeof(u2);
				code->exception_table[j].end_pc = load_u2(buff);
				buff += sizeof(u2);
				code->exception_table[j].handler_pc = load_u2(buff);
				buff += sizeof(u2);
				code->exception_table[j].catch_type = load_u2(buff);
				buff += sizeof(u2);
			}
			
			u2 attributes_count = load_u2(buff);
			buff += sizeof(u2);

			const size_t length = load_attributes(buff, buffleft, attributes_count, constant_pool, code, heap);
			buff += length;

			minfo->code_attribute = code; 
		} else if (attr_name == g_Exceptions_name && minfo->exceptions_attribute == NULL) {
			// Exceptions_attribute
			u2 number_of_exceptions = load_u2(buff);
			buff += sizeof(u2);
			
			// Exceptions_attribute* attr = (Exceptions_attribute*) malloc(sizeof(Exceptions_attribute) + sizeof(u2) * number_of_exceptions);
			Exceptions_attribute* attr
				= (Exceptions_attribute*) heap->allocate(sizeof(Exceptions_attribute) + sizeof(u2) * number_of_exceptions);
			if (attr == NULL) {
				fatal_error(FATAL_ERROR_NO_MEMORY);
			}
			u2* exception_index_table = (u2*) (attr + 1);
			for (int i = 0; i < number_of_exceptions; ++i) {
				exception_index_table[i] = load_u2(buff);
				buff += sizeof(u2);
			}
			attr->number_of_exceptions = number_of_exceptions;
			attr->exception_index_table = exception_index_table;
			minfo->exceptions_attribute = attr;			
		
		} else if (attr_name == g_Signature_name) {
			minfo->signature_index = load_u2(buff);
		} else if (g_RuntimeVisibleAnnotations == attr_name) {
			// RuntimeVisibleAnnotations
			// ToDo: 保持しておく
#ifdef DEBUG
			u2 num_annotations = load_u2(buff);
			buff += sizeof(u2);
			
			u2 type_index = load_u2(buff);
			buff += sizeof(u2);

			u2 num_element_value_pairs = load_u2(buff);
			
			const java_utf8* type_name = (const java_utf8*) constant_pool[type_index];
			type_name = type_name;
#endif
		} else if (g_RuntimeVisibleParameterAnnotations == attr_name) {
			// RuntimeVisibleParameterAnnotations
			// ToDo: 保持しておく
		}

		buff = org_buff + attribute_length;
		count += attribute_length + sizeof(u2) + sizeof(u4);
	}
	return count;

#undef CHECK_BUFFER_SIZE
}

/**
 * Code_attributeに必要となるアトリビュートをロードする
 */
static unsigned int load_attributes(const char* buff, size_t buffleft, u2 attributes_count, cp_info** constant_pool, Code_attribute* code, PermanentHeap* heap) {
// バッファサイズチェック用マクロ
#define CHECK_BUFFER_SIZE(size) { \
	if (buffleft < size) { \
	    return (size_t) -1; \
	} \
	buffleft -= (size); \
}
	unsigned int count = 0;
	code->linenumbertable_attribute = NULL;
	for (u2 i = 0; i < attributes_count; ++i) {
		CHECK_BUFFER_SIZE(sizeof(u2) + sizeof(u4));

		// アトリビュート名を取得する
		u2 attribute_name_index = load_u2(buff);
		buff += sizeof(u2);
		java_utf8* attr_name = (java_utf8*) constant_pool[attribute_name_index];

		// アトリビュート長
		u4 attribute_length = load_u4(buff);
		buff += sizeof(u4);

		CHECK_BUFFER_SIZE(attribute_length);

		const char* org_buff = buff;
		if (g_LineNumberTable_name == attr_name && code->linenumbertable_attribute == NULL) {
			// LineNumberTable
			u2 line_number_table_length = load_u2(buff);
			buff += sizeof(u2);
			
			//char* tmp = (char*) malloc(sizeof(LineNumberTable_attribute)
			// 							+ sizeof(line_number_table) * line_number_table_length);
			char* tmp = (char*) heap->allocate(sizeof(LineNumberTable_attribute)
										+ sizeof(line_number_table) * line_number_table_length);
			if (tmp == NULL) {
				fatal_error(FATAL_ERROR_NO_MEMORY);
			}
			LineNumberTable_attribute* line = (LineNumberTable_attribute*) tmp;
			line->line_number_table_length = line_number_table_length;
			
			line->table = (line_number_table*) (tmp + sizeof(LineNumberTable_attribute));
			if (line->table == NULL) {
				fatal_error(FATAL_ERROR_NO_MEMORY);
			}
			line_number_table* tbl = line->table;
			if (tbl != NULL) {
				for (u2 i = 0; i < line->line_number_table_length; ++i) {
					tbl->start_pc = load_u2(buff);
					buff += sizeof(u2);
					tbl->line_number = load_u2(buff);
					buff += sizeof(u2);
					tbl++;
				}
			}
			code->linenumbertable_attribute = line;
		}
		buff = org_buff + attribute_length;
		count += attribute_length + sizeof(u2) + sizeof(u4);
	}
	return count;

#undef CHECK_BUFFER_SIZE
}

/**
 * ClassFile構造体に必要となるアトリビュートをロードする
 */
static unsigned int load_attributes(const char* buff, size_t buffleft, u2 attributes_count, ClassFile* cfile, PermanentHeap* heap) {
// バッファサイズチェック用マクロ
#define CHECK_BUFFER_SIZE(size) { \
	if (buffleft < size) { \
	    return (size_t) -1; \
	} \
	buffleft -= (size); \
}
	unsigned int count = 0;
	cfile->sourcefile_index = 0;
	for (u2 i = 0; i < attributes_count; ++i) {
		CHECK_BUFFER_SIZE(sizeof(u2) + sizeof(u4));

		// アトリビュート名を取得する
		u2 attribute_name_index = load_u2(buff);
		buff += sizeof(u2);
		java_utf8* attr_name = (java_utf8*) cfile->constant_pool[attribute_name_index];

		// アトリビュート長
		u4 attribute_length = load_u4(buff);
		buff += sizeof(u4);
		CHECK_BUFFER_SIZE(attribute_length);

		const char* org_buff = buff;
		if (g_SourceFile_name == attr_name) {
			// SourceFile
			cfile->sourcefile_index = load_u2(buff);
			buff += sizeof(u2);

		} else if (g_InnerClasses_name == attr_name && cfile->innerclasses_attribute == NULL) {
			// InnerClassesアトリビュート
			u2 number_of_classes = load_u2(buff);
			buff += sizeof(u2);
			
			// char* tmp = (char*) malloc(sizeof(InnerClasses_attribute) + sizeof(classes_info) * number_of_classes);
			char* tmp = (char*) heap->allocate(sizeof(InnerClasses_attribute) + sizeof(classes_info) * number_of_classes);
			InnerClasses_attribute* ic = (InnerClasses_attribute*) tmp;
			ic->number_of_classes = number_of_classes;
			ic->classes = (classes_info*) (tmp + sizeof(InnerClasses_attribute));
			for (int j = 0; j < number_of_classes; ++j) {
				classes_info* info = &ic->classes[j];
				info->inner_class_info_index = load_u2(buff);
				buff += sizeof(u2);
				info->outer_class_info_index = load_u2(buff);
				buff += sizeof(u2);
				info->inner_name_index = load_u2(buff);
				buff += sizeof(u2);
				info->inner_class_access_flags = load_u2(buff);	     
				buff += sizeof(u2);
			}
			cfile->innerclasses_attribute = ic;
		
		} else if (g_Signature_name == attr_name) {
			// Signature
			cfile->signature_index = load_u2(buff);
		} else if (g_RuntimeVisibleAnnotations == attr_name) {
			// RuntimeVisibleAnnotations
			// ToDo: 保持しておく
		}

		buff = org_buff + attribute_length;
		count += attribute_length + sizeof(u2) + sizeof(u4);
	}
	return count;
}

/**
 * 指定されたCode_attribute構造体から、pcに対応する行数を得る。
 */
int get_LineNumber(Code_attribute* code, unsigned int pc) {
	LineNumberTable_attribute* line = code->linenumbertable_attribute;
	int linenumber = -1;
	if (line != NULL) {
		int prev_number = -1;
		for (u2 i = 0; i < line->line_number_table_length; ++i) {
			line_number_table* tab = &line->table[i];
			u4 start_pc = tab->start_pc;
			if (pc == start_pc) {
				linenumber = tab->line_number;
				break;
			} else if (pc < start_pc) {
				linenumber = prev_number;
				break;
			}
			prev_number = tab->line_number;
		}
		if (linenumber == -1) {
			linenumber = prev_number;
		}
	}
	return linenumber;
}

/**
 * 指定された名前がプリミティブクラスかどうかを返す
 */
bool is_primitive_class_name(java_utf8* class_name) {
	// class_name = intern_utf8(class_name);
	for (int i = 0; i < 9; ++i) {
		if (g_primitive_class_names[i] == class_name) {
			return true;
		}
	}
	return false;
}

/**
 * クラスファイルを初期化する
 */
bool prepare_ClassFile(frame* current_frame,
					   ClassFile* cfile,
					   ClassFile* super_class_file,
					   ClassFile** interfaces) {
    // ヒープ
	assert(cfile->defining_loader);
	PermanentHeap* heap = get_heap_of_class_loader(cfile->defining_loader);

	cfile->superclass_ClassFile = super_class_file;
//	cfile->interfaces_ClassFiles
//			= (ClassFile**) malloc(sizeof(ClassFile*) * cfile->interfaces_count);
	cfile->interfaces_ClassFiles
			= (ClassFile**) heap->allocate(sizeof(ClassFile*) * cfile->interfaces_count);
	if (! cfile->interfaces_ClassFiles) {
		fatal_error(FATAL_ERROR_NO_MEMORY);
	}
	memcpy(cfile->interfaces_ClassFiles, interfaces, sizeof(ClassFile*) * cfile->interfaces_count);

	// フィールドテーブル／メソッドテーブルを構築する
	init_field_table(cfile, super_class_file, interfaces, cfile->interfaces_count);
	if (! init_method_table(current_frame,
							cfile,
							super_class_file,
							interfaces,
							cfile->interfaces_count)) {
		return false;
	}
	return true;
}

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

	const char* work = descriptor;
  
	// 最初に、配列かどうかを調べる
	while (*work && *work == '[') {
		work++;
		if (work - descriptor > 255) {
			// 次元数オーバー
			return -1;
		}
	}
	if (! *work || *work == ')' ) {
		// [ のあとに何もない
		return -1;
	}

	switch (*work) {
    case 'Z':
    case 'B':
    case 'C':
    case 'S':
    case 'I':
    case 'J':
    case 'F':
    case 'D':
		// プリミティブ型
		work++;
		break;

	case 'L':
		// オブジェクト型
		{
			while (*work
					&& *work != '['
					&& *work != ')'
					&& *work != ';') {
				work++;
			}
			if (*work == ';') {
				work++;
				break;
			} else {
				// 不正なフォーマット
				return -1;
			}
		}
		break;

	default:
		// 不正なフォーマット
		return -1;
  }
  
	// トークンの長さを返す
	int length = work - descriptor;
	if (! length) {
		// 念のため
		return -1;
	}
	return length;
}

/**
 * 指定されたトークンからクラス名を抽出し、intern された文字列に変換して
 * 返す
 */
const java_utf8* intern_class_name(const char* token, int length) {
	if (! *token || length < 2) {
		return NULL;
	}
	if (*token == 'L') {
		// オブジェクト型
		if (token[length - 1] != ';') {
			return NULL;
		}
		return intern_utf8(token + 1, length - 2);
	} else if (*token == '[') {
		// 配列型
		return intern_utf8(token, length);
	}
	return NULL;
}

/**
 * 指定されたクラス from から、クラス target の access_flags を持つ
 * クラス／メソッド／フィールドにアクセス可能かを判定する
 */
bool is_accessible(frame* current_frame, ClassFile* from, ClassFile* target, u2 access_flags) {
	if (from == target) {
		// 自分自身のフィールド／メソッドには必ずアクセス可能
		return true;
	}

	if (is_public(access_flags)) {
		// publicの場合は常にアクセス可能
		return true;
	}
	if (is_protected(access_flags)) {
		// protectedの場合には以下のいずれかの条件を満たしていなければならない
		// ・同一パッケージ
		// ・from が targetの派生クラスである必要がある
		class_loader* loader = get_defining_loader(from);
		if (is_same_package(loader, from, target)) {
			return true;
		}
	
		while ((from = get_superclass_ClassFile(from)) != NULL) {
			if (from == target) {
				return true;
			}
		} 
		return false;
	}
	if (is_private(access_flags)) {
		// privateの場合には自分自身でなければならない
		return from == target;
	}
	
	// パッケージプライベートの場合
	class_loader* loader = get_defining_loader(from);
	return is_same_package(loader, from, target);
}

/**
 * 指定されたconstant_pool_index が指しているClassFileをresolveする
 */
ClassFile* resolve_ClassFile(frame* current_frame,
							 ClassFile* cfile,
							 u2 constant_pool_index) {
	cp_info* cinfo = get_cp_info(cfile, constant_pool_index, CONSTANT_Class);
	if (IS_SPECIAL_POINTER(cinfo)) {
		// すでにresolveされている
		return (ClassFile*) MAKE_NORMAL_POINTER(cinfo);
	}
	// クラスをロードする
	class_loader* loader = get_defining_loader(cfile);
	const java_utf8* target_class_name = get_java_utf8(cfile, (u2) cinfo);
	ClassFile* target_class_file = find_ClassFile(current_frame,
												  loader,
												  target_class_name);
	if (target_class_file) {
		if (! is_accessible(current_frame,
							current_frame->current_class_file,
							target_class_file,
							target_class_file->access_flags)) {
			// ターゲットとなるクラスにアクセスできない場合
			throw_exception(current_frame, "java/lang/IllegalAccessException");
			return NULL;
		}

		// クラスをキャッシュする
		cp_info* cached = (cp_info*) MAKE_SPECIAL_POINTER(target_class_file);
		cfile->constant_pool[constant_pool_index] = cached;
	}
	return target_class_file;
}
