/* 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_AnnotationDefault;	// "AnnotationDefault"

/**
 * プリミティブクラス名
 */
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 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,
				     PermanentHeap * heap);
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 raw_annotations_data *alloc_raw_annotations_data (const char *buff,
							 u4 attribute_length,
							 PermanentHeap *
							 heap);

/**
 * インタフェースに関するロード制約を追加する
 */
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);

/**
 * 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");

  // Constant values of annotations.
  g_RuntimeVisibleAnnotations = intern_utf8 ("RuntimeVisibleAnnotations");
  g_RuntimeVisibleParameterAnnotations =
    intern_utf8 ("RuntimeVisibleParameterAnnotations");
  g_AnnotationDefault = intern_utf8 ("AnnotationDefault");

  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:実装する
}

/**
 * Read specified buffer and parse and creates a class.
 */
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);

// Buffer size checking macro.
#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));

  // Checks "magic"
  u4 magic = load_u4 (buff);
  buff += sizeof (u4);
  if (magic != MAGIC)
    {
      // Wrong magic.
      return NULL;
    }

  // ClassFile構造体を確保する
//      cfile_p = (ClassFile*) calloc(sizeof(ClassFile), 1);
  cfile_p = (ClassFile *) heap->allocate (sizeof (ClassFile));
  if (cfile_p == NULL)
    {
      // no memory.
      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,
					       heap);
	      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 () ・ﾉ対応していないため、 ・R ・＜塔g ・A ・
    E ・g ・ｵている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,
		 PermanentHeap * heap)
{
  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)
	{
	  finfo->annotations =
	    alloc_raw_annotations_data (buff, attribute_length, heap);
	}

      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; \
	} \
  }

  unsigned int count = 0;
  for (u2 i = 0; i < attributes_count; ++i)
    {
      // アトリビュート名/アトリビュート長を取得する
      CHECK_BUFFER_SIZE (sizeof (u2) + sizeof (u4));
      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);
      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);

          // Bug #19442
	  const size_t length =
	    load_attributes (buff, buffleft - (buff - org_buff), 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
	  if (!minfo->annotations)
	    {
	      minfo->annotations =
		(raw_annotations_data_of_method_info *) heap->
		allocate (sizeof (raw_annotations_data_of_method_info));
	      if (!minfo->annotations)
		{
		  fatal_error (FATAL_ERROR_NO_MEMORY);
		}
	    }
	  minfo->annotations->annotations =
	    alloc_raw_annotations_data (buff, attribute_length, heap);
	}
      else if (g_RuntimeVisibleParameterAnnotations == attr_name)
	{
	  // RuntimeVisibleParameterAnnotations
	  if (!minfo->annotations)
	    {
	      minfo->annotations =
		(raw_annotations_data_of_method_info *) heap->
		allocate (sizeof (raw_annotations_data_of_method_info));
	      if (!minfo->annotations)
		{
		  fatal_error (FATAL_ERROR_NO_MEMORY);
		}
	    }
	  minfo->annotations->parameter_annotations =
	    alloc_raw_annotations_data (buff, attribute_length, heap);
	}
      else if (g_AnnotationDefault == attr_name)
	{
	  // AnnotationDefault
	  if (!minfo->annotations)
	    {
	      minfo->annotations =
		(raw_annotations_data_of_method_info *) heap->
		allocate (sizeof (raw_annotations_data_of_method_info));
	      if (!minfo->annotations)
		{
		  fatal_error (FATAL_ERROR_NO_MEMORY);
		}
	    }
	  minfo->annotations->annotation_default =
	    alloc_raw_annotations_data (buff, attribute_length, heap);
	}
      buff = org_buff + attribute_length;
      buffleft -= 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));
	  line_number_table *tbl = line->table;
          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
	  cfile->annotations =
	    alloc_raw_annotations_data (buff, attribute_length, heap);
	}

      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)
	    {
              if (prev_number == -1)
              {
	        linenumber = tab->line_number;
              }
              else
              {
	        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;
}

raw_annotations_data *
alloc_raw_annotations_data (const char *buff, u4 attribute_length,
			    PermanentHeap * heap)
{
  raw_annotations_data *result =
    (raw_annotations_data *)::malloc (sizeof (raw_annotations_data));
  if (result)
    {
      result->length = attribute_length;
      result->data = (char *) heap->allocate (attribute_length);
      if (result->data)
	{
	  ::memcpy (result->data, buff, attribute_length);
	}
    }
  return result;
}
