/* instruction_inc.h
   Copyright (C) 2005 Free Software Foundation, Inc.

This file is part of GNU Classpath.

GNU Classpath 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.

GNU Classpath 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.

Linking this library statically or dynamically with other modules is
making a combined work based on this library.  Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.

As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module.  An independent module is a module which is not derived from
or based on this library.  If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so.  If you do not wish to do so, delete this
exception statement from your version. */

// 命令実行 switch 文にincludeするファイル

#define	EXECUTOR(inst)	break; \
						case inst:
#define EXECUTOR_ALIAS(inst)	case inst:

/**
 * baload, saload, iaload, faload, laload命令生成用マクロ
 */
#define EXECUTE_PRIMITIVE_ALOAD_BODY(name, type, PUSHTYPE) \
{ \
	jint index; \
	PEEK_STACK_DATA(current_frame, 0, jint, index); \
	jobject ref; \
	PEEK_STACK_DATA(current_frame, 1, jobject, ref); \
	if (ref == NULL) { \
		throw_exception(current_frame, "java/lang/NullPointerException"); \
		CHECK_EXCEPTION; \
	} \
	if (index < 0 || index >= get_array_length((jarray) ref)) { \
		throw_exception(current_frame, "java/lang/ArrayIndexOutOfBoundsException", index); \
		CHECK_EXCEPTION;	\
	} \
	type * aptr = (type *) get_object_body(ref); \
	type value = aptr[index]; \
	POP_DISCARD_N(current_frame, 2); \
	PUSH_##PUSHTYPE##(current_frame, value); \
}

/*
マクロ使用例)

EXECUTE_PRIMITIVE_ALOAD_BODY(baload, jbyte, INT);
EXECUTE_PRIMITIVE_ALOAD_BODY(saload, jshort, INT);
EXECUTE_PRIMITIVE_ALOAD_BODY(caload, jchar, INT);
EXECUTE_PRIMITIVE_ALOAD_BODY(iaload, jint, INT);
EXECUTE_PRIMITIVE_ALOAD_BODY(laload, jlong, LONG);

*/

/**
 * iastore, bastore, castore, sastore, fastore, lastore
 */
#define EXECUTE_PRIMITIVE_ASTORE_BODY(name, type, POPTYPE) \
{ \
	type value; \
	POP_##POPTYPE##(current_frame, value); \
	jint index; \
	PEEK_STACK_DATA(current_frame, 0, jint, index); \
	jobject ref; \
	PEEK_STACK_DATA(current_frame, 1, jobject, ref); \
	if (ref == NULL) { \
		throw_exception(current_frame, "java/lang/NullPointerException"); \
		CHECK_EXCEPTION; \
	} \
	if (index < 0 || index >= get_array_length((jarray) ref)) { \
		throw_exception(current_frame, "java/lang/ArrayIndexOutOfBoundsException", index); \
		CHECK_EXCEPTION;	\
	} \
	type * aptr = (type *) get_object_body(ref); \
	aptr[index] = value; \
	POP_DISCARD_N(current_frame, 2); \
}

/**
 * マクロ使用例
EXECUTE_PRIMITIVE_ASTORE_BODY(iastore, jint, INT);
EXECUTE_PRIMITIVE_ASTORE_BODY(bastore, jbyte, INT);
EXECUTE_PRIMITIVE_ASTORE_BODY(castore, jchar, INT);
EXECUTE_PRIMITIVE_ASTORE_BODY(sastore, jshort, INT);
EXECUTE_PRIMITIVE_ASTORE_BODY(fastore, jfloat, FLOAT);
EXECUTE_PRIMITIVE_ASTORE_BODY(lastore, jlong, LONG);
*/

/**
 * バイトコードを書き換えるマクロ
 */
#define REWRITE_BYTECODE(new_bytecode)	(*bytecode = new_bytecode)

#include "bytecode.h"

/**
 * run_code()のswitch文の中で #include されるファイル。
 * 以下の変数が利用可能。
 *
 * current_frame - カレントフレーム(frame*)
 * bytecode      - 現在のバイトコードを指すポインタ
 *
 */

/**
 * nopを実行する
 */
EXECUTOR ( NOP )
{
	// 何もしない
	bytecode++;
}

/**
 * aconst_nullを実行する
 */
EXECUTOR ( ACONST_NULL )
{
	PUSH_OBJECT(current_frame, NULL);
	bytecode++;
}

/**
 * iconst_m1命令を実行する
 */
EXECUTOR ( ICONST_M1 )
{
	FAST_PUSH_INT(stack_base, pposition, -1);
	bytecode++;
}

/**
 * iconst_0命令を実行する
 */
EXECUTOR ( ICONST_0 )
{
	FAST_PUSH_INT(stack_base, pposition, 0);
	bytecode++;
}

/**
 * iconst_1命令を実行する
 */
EXECUTOR ( ICONST_1 )
{
	FAST_PUSH_INT(stack_base, pposition, 1);
	bytecode++;
}

/**
 * iconst_2命令を実行する
 */
EXECUTOR ( ICONST_2 )
{
	FAST_PUSH_INT(stack_base, pposition, 2);
	bytecode++;
}

/**
 * iconst_3命令を実行する
 */
EXECUTOR ( ICONST_3 )
{
	FAST_PUSH_INT(stack_base, pposition, 3);
	bytecode++;
}

/**
 * iconst_4命令を実行する
 */
EXECUTOR ( ICONST_4 )
{
	FAST_PUSH_INT(stack_base, pposition, 4);
	bytecode++;
}

/**
 * iconst_5命令を実行する
 */
EXECUTOR ( ICONST_5 )
{
	FAST_PUSH_INT(stack_base, pposition, 5);
	bytecode++;
}

/**
 * lconst_0命令を実行する
 */
EXECUTOR ( LCONST_0 )
{
	PUSH_LONG(current_frame, 0);
	bytecode++;
}

/**
 * lconst_1命令を実行する
 */
EXECUTOR ( LCONST_1 )
{
	PUSH_LONG(current_frame, 1);
	bytecode++;
}

/**
 * fconst_0命令を実行する
 */
EXECUTOR ( FCONST_0 )
{
	FAST_PUSH_FLOAT(stack_base, pposition, 0.0f);
	bytecode++;
}

/**
 * fconst_1命令を実行する
 */
EXECUTOR ( FCONST_1 )
{
	FAST_PUSH_FLOAT(stack_base, pposition, 1.0f);
	bytecode++;
}

/**
 * fconst_2命令を実行する
 */
EXECUTOR ( FCONST_2 )
{
	FAST_PUSH_FLOAT(stack_base, pposition, 2.0f);
	bytecode++;
}

/**
 * dconst_0命令を実行する
 */
EXECUTOR ( DCONST_0 )
{
	PUSH_DOUBLE(current_frame, 0.0);
	bytecode++;
}

/**
 * dconst_1命令を実行する
 */
EXECUTOR ( DCONST_1 )
{
	PUSH_DOUBLE(current_frame, 1.0);
	bytecode++;
}

/**
 * bipush命令を実行する
 */
EXECUTOR ( BIPUSH )
{
	__int8 tmp = bytecode[1];
	__int32 v = tmp;	// 符号拡張
	FAST_PUSH_INT(stack_base, pposition, v);
	bytecode += 2;
}

/**
 * sipush命令を実行する
 */
EXECUTOR ( SIPUSH )
{
	__int16 s = MAKE_INT16(bytecode[1], bytecode[2]);
	FAST_PUSH_INT(stack_base, pposition, (__int32) s);
	bytecode += 3;
}

/**
 * ldc命令を実行する
 */
EXECUTOR ( LDC )
{
	execute_ldc_w(current_frame, 0, bytecode[1]);
	CHECK_EXCEPTION;
	bytecode += 2;
}

/**
 * ldc_w命令を実行する
 */
EXECUTOR ( LDC_W )
{
	execute_ldc_w(current_frame, bytecode[1], bytecode[2]);
	CHECK_EXCEPTION;
	bytecode += 3;
}

/**
 * ldc2_w命令を実行する
 */
EXECUTOR ( LDC2_W )
{
	u2 index = MAKE_U2(GET_PARAMETER(bytecode, 1),
					   GET_PARAMETER(bytecode, 2));
	ClassFile* cfile = current_frame->current_class_file;
	__int64 value = *(__int64*) &cfile->constant_pool[index];
	PUSH_LONG(current_frame, value);
	bytecode += 3;
}

/**
 * iload命令を実行する
 */
EXECUTOR       ( ILOAD )
EXECUTOR_ALIAS ( FLOAD )
{
	FAST_LOAD(stack_base, pposition, local_variables_base, bytecode[1]);
	bytecode += 2;
}

EXECUTOR       ( ALOAD )
{
	ALOAD_N(current_frame, bytecode[1]);
	bytecode += 2;
}

/**
 * lload命令を実行する
 */
EXECUTOR       ( LLOAD )
EXECUTOR_ALIAS ( DLOAD )
{
	LOAD2(current_frame, bytecode[1]);
	bytecode += 2;
}

/**
 * iload_0命令を実行する
 */
EXECUTOR       ( ILOAD_0 )
EXECUTOR_ALIAS ( FLOAD_0 )
{
	FAST_LOAD(stack_base, pposition, local_variables_base, 0);
	bytecode++;
}

EXECUTOR       ( ALOAD_0 )
{
	ALOAD_N(current_frame, 0);
	bytecode++;
}

/**
 * iload_1命令を実行する
 */
EXECUTOR       ( ILOAD_1 )
EXECUTOR_ALIAS ( FLOAD_1 )
{
	FAST_LOAD(stack_base, pposition, local_variables_base, 1);
	bytecode++;
}

EXECUTOR       ( ALOAD_1 )
{
	ALOAD_N(current_frame, 1);
	bytecode++;
}

/**
 * iload_2命令を実行する
 */
EXECUTOR       ( ILOAD_2 )
EXECUTOR_ALIAS ( FLOAD_2 )
{
	FAST_LOAD(stack_base, pposition, local_variables_base, 2);
	bytecode++;
}

EXECUTOR        ( ALOAD_2 )
{
	ALOAD_N(current_frame, 2);
	bytecode++;
}

/**
 * iload_3命令を実行する
 */
EXECUTOR       ( ILOAD_3 )
EXECUTOR_ALIAS ( FLOAD_3 )
{
	FAST_LOAD(stack_base, pposition, local_variables_base, 3);
	bytecode++;
}

EXECUTOR       ( ALOAD_3 )
{
	ALOAD_N(current_frame, 3);
	bytecode++;
}

/**
 * lload_0命令を実行する
 */
EXECUTOR       ( LLOAD_0 )
EXECUTOR_ALIAS ( DLOAD_0 )
{
	LOAD2(current_frame, 0);
	bytecode++;
}

/**
 * lload_1命令を実行する
 */
EXECUTOR       ( LLOAD_1 )
EXECUTOR_ALIAS ( DLOAD_1 )
{
	LOAD2(current_frame, 1);
	bytecode++;
}

/**
 * lload_2命令を実行する
 */
EXECUTOR       ( LLOAD_2 )
EXECUTOR_ALIAS ( DLOAD_2 )
{
	LOAD2(current_frame, 2);
	bytecode++;
}

/**
 * lload_3命令を実行する
 */
EXECUTOR       ( LLOAD_3 )
EXECUTOR_ALIAS ( DLOAD_3 )
{
	LOAD2(current_frame, 3);
	bytecode++;
}

/**
 * iaload, faload, baload, saload命令を実行する
 */
EXECUTOR       ( IALOAD )
EXECUTOR_ALIAS ( FALOAD )
{
	EXECUTE_PRIMITIVE_ALOAD_BODY(iaload, jint, INT);
	bytecode++;
}

EXECUTOR       ( BALOAD )
{
	EXECUTE_PRIMITIVE_ALOAD_BODY(baload, jbyte, INT);
	bytecode++;
}

EXECUTOR       ( SALOAD )
{
	EXECUTE_PRIMITIVE_ALOAD_BODY(saload, jshort, INT);
	bytecode++;
}

/**
 * laload命令を実行する
 */
EXECUTOR       ( LALOAD )
EXECUTOR_ALIAS ( DALOAD )
{
	EXECUTE_PRIMITIVE_ALOAD_BODY(laload, jlong, LONG);
	bytecode++;
}

/**
 * aaload命令を実行する
 */
EXECUTOR ( AALOAD )
{
	// パラメータを取得
	jint idx;
	PEEK_STACK_DATA(current_frame, 0, jint, idx);
	jobject aref;
	PEEK_STACK_DATA(current_frame, 1, jobject, aref);

	// nullチェック
	if (aref == NULL) {
		throw_exception(current_frame, "java/lang/NullPointerException");
		CHECK_EXCEPTION;
	}

	// 配列境界チェック
	if (idx < 0 || idx >= get_array_length((jarray) aref)) {
		throw_exception(current_frame, "java/lang/ArrayIndexOutOfBoundsException", idx);
		CHECK_EXCEPTION;
	}

	// 配列要素を取得
	jobject* parray = (jobject*) get_object_body(aref);
	jobject ref = parray[idx];

	// パラメータをまとめて破棄
	POP_DISCARD_N(current_frame, 2);
	
	// 結果をPUSH
	PUSH_OBJECT(current_frame, ref);

	CHECK_EXCEPTION;
	bytecode++;
}

/**
 * caload命令を実行する
 */
EXECUTOR ( CALOAD )
{
	// execute_caload(current_frame, bytecode);
	EXECUTE_PRIMITIVE_ALOAD_BODY(caload, jchar, INT);
	CHECK_EXCEPTION;
	bytecode++;
}


/**
 * istore命令を実行する
 */
EXECUTOR       ( ISTORE )
EXECUTOR_ALIAS ( FSTORE )
{
	FAST_STORE(stack_base, pposition, local_variables_base, bytecode[1]);
	bytecode += 2;
}

EXECUTOR       ( ASTORE )
{
	ASTORE_N(current_frame, bytecode[1]);
	bytecode += 2;
}

/**
 * lstore命令を実行する
 */
EXECUTOR       ( LSTORE )
EXECUTOR_ALIAS ( DSTORE )
{
	STORE2(current_frame, bytecode[1]);
	bytecode += 2;
}

/**
 * istore_0命令を実行する
 */
EXECUTOR ( ISTORE_0 )
{
	FAST_STORE(stack_base, pposition, local_variables_base, 0);
	bytecode++;
}

/**
 * istore_1命令を実行する
 */
EXECUTOR ( ISTORE_1 )
{
	FAST_STORE(stack_base, pposition, local_variables_base, 1);
	bytecode++;
}

/**
 * istore_2命令を実行する
 */
EXECUTOR ( ISTORE_2 )
{
	FAST_STORE(stack_base, pposition, local_variables_base, 2);
	bytecode++;
}

/**
 * istore_3命令を実行する
 */
EXECUTOR ( ISTORE_3 )
{
	FAST_STORE(stack_base, pposition, local_variables_base, 3);
	bytecode++;
}

/**
 * lstore_0命令を実行する
 */
EXECUTOR ( LSTORE_0 )
{
	STORE2(current_frame, 0);
	bytecode++;
}

/**
 * lstore_1命令を実行する
 */
EXECUTOR ( LSTORE_1 )
{
	STORE2(current_frame, 1);
	bytecode++;
}

/**
 * lstore_2命令を実行する
 */
EXECUTOR ( LSTORE_2 )
{
	STORE2(current_frame, 2);
	bytecode++;
}

/**
 * lstore_3命令を実行する
 */
EXECUTOR ( LSTORE_3 )
{
	STORE2(current_frame, 3);
	bytecode++;
}

/**
 * fstore_0命令を実行する
 */
EXECUTOR ( FSTORE_0 )
{
	FAST_STORE(stack_base, pposition, local_variables_base, 0);
	bytecode++;
}

/**
 * fstore_1命令を実行する
 */
EXECUTOR ( FSTORE_1 )
{
	FAST_STORE(stack_base, pposition, local_variables_base, 1);
	bytecode++;
}

/**
 * fstore_2命令を実行する
 */
EXECUTOR ( FSTORE_2 )
{
	FAST_STORE(stack_base, pposition, local_variables_base, 2);
	bytecode++;
}

/**
 * fstore_3命令を実行する
 */
EXECUTOR ( FSTORE_3 )
{
	FAST_STORE(stack_base, pposition, local_variables_base, 3);
	bytecode++;
}

/**
 * dstore_0命令を実行する
 */
EXECUTOR ( DSTORE_0 )
{
	STORE2(current_frame, 0);
	bytecode++;
}

/**
 * dstore_1命令を実行する
 */
EXECUTOR ( DSTORE_1 )
{
	STORE2(current_frame, 1);
	bytecode++;
}

/**
 * dstore_2命令を実行する
 */
EXECUTOR ( DSTORE_2 )
{
	STORE2(current_frame, 2);
	bytecode++;
}

/**
 * dstore_3命令を実行する
 */
EXECUTOR ( DSTORE_3 )
{
	STORE2(current_frame, 3);
	bytecode++;
}

/**
 * astore_0命令を実行する
 */
EXECUTOR ( ASTORE_0 )
{
	ASTORE_N(current_frame, 0);
	bytecode++;
}

/**
 * astore_1命令を実行する
 */
EXECUTOR ( ASTORE_1 )
{
	ASTORE_N(current_frame, 1);
	bytecode++;
}

/**
 * astore_2命令を実行する
 */
EXECUTOR ( ASTORE_2 )
{
	ASTORE_N(current_frame, 2);
	bytecode++;
}

/**
 * astore_3命令を実行する
 */
EXECUTOR ( ASTORE_3 )
{
	ASTORE_N(current_frame, 3);
	bytecode++;
}

/**
 * iastore, fastore, bastore, castore, sastore命令を実行する
 */
EXECUTOR ( IASTORE )
{
	EXECUTE_PRIMITIVE_ASTORE_BODY(iastore, jint, INT);
	bytecode++;
}

EXECUTOR ( FASTORE )
{
	EXECUTE_PRIMITIVE_ASTORE_BODY(fastore, jfloat, FLOAT);
	bytecode++;
}

EXECUTOR ( BASTORE )
{
	EXECUTE_PRIMITIVE_ASTORE_BODY(bastore, jbyte, INT);
	bytecode++;
}

EXECUTOR ( CASTORE )
{
	EXECUTE_PRIMITIVE_ASTORE_BODY(castore, jchar, INT);
	bytecode++;
}

EXECUTOR ( SASTORE )
{
	EXECUTE_PRIMITIVE_ASTORE_BODY(sastore, jshort, INT);
	bytecode++;
}

/**
 * lastore, dastore命令を実行する
 */
EXECUTOR       ( LASTORE )
EXECUTOR_ALIAS ( DASTORE )
{
	EXECUTE_PRIMITIVE_ASTORE_BODY(lastore, jlong, LONG);
	bytecode++;
}

/**
 * aastore命令を実行する
 */
EXECUTOR ( AASTORE )
{
	// 代入する値
	jobject value;
	PEEK_STACK_DATA(current_frame, 0, jobject, value);

	// インデックス
	jint index;
	PEEK_STACK_DATA(current_frame, 1, jint, index);
	
	// 代入先の配列
	jobject ref;
	PEEK_STACK_DATA(current_frame, 2, jobject, ref);
	
	if (ref == NULL) {
		// 配列の参照がnullの場合、NullPointerExceptionを発生させる
		throw_exception(current_frame, "java/lang/NullPointerException");
		CHECK_EXCEPTION;
	}
	
	// value が refに代入可能かを調べる
	ClassFile* array_class_file = get_ClassFile(ref);
	const java_utf8* component_name = get_array_component_name(array_class_file);
	ClassFile* component_cfile = find_ClassFile(current_frame,
												get_defining_loader(array_class_file),
												component_name);
	if (! component_cfile) {
		// 例外が設定されているはず
		CHECK_EXCEPTION;
	}
	ClassFile* value_cfile = value ? get_ClassFile(value) : NULL;
	if (value != NULL
			&& (value_cfile != component_cfile) 
			&& (! is_assignable_from(current_frame, value_cfile, component_cfile))) {
		// 代入する値がnull以外で、かつ配列要素の代入互換性がない場合は
		// ArrayStoreExceptionをthrowする
		throw_exception(current_frame, "java/lang/ArrayStoreException");
		CHECK_EXCEPTION;
	}

	// 配列境界チェック
	if (index < 0 || index >= get_array_length((jarray) ref)) {
		throw_exception(current_frame, "java/lang/ArrayIndexOutOfBoundsException", index);
		CHECK_EXCEPTION;
	}
	jobject* parray = (jobject*) get_object_body(ref);
	parray[index] = value;

	// パラメータをまとめて破棄
	POP_DISCARD_N(current_frame, 3);

	bytecode++;
}

/**
 * pop命令を実行する
 */
EXECUTOR ( POP )
{
	POP_DISCARD(current_frame);
	bytecode++;
}

/**
 * pop2命令を実行する
 */
EXECUTOR ( POP2 )
{
	POP2_DISCARD(current_frame);
	bytecode++;
}

/**
 * dup命令を実行する
 */
EXECUTOR ( DUP )
{
	DUP_STACK(current_frame);
	bytecode++;
}

/**
 * dup_x1命令を実行する
 */
EXECUTOR ( DUP_X1 )
{
	dup_x1(current_frame);
	bytecode++;
}

/**
 * dup_x2命令を実行する
 */
EXECUTOR ( DUP_X2 )
{
	dup_x2(current_frame);
	bytecode++;
}

/**
 * dup2命令を実行する
 */
EXECUTOR ( DUP2 )
{
	dup2(current_frame);
	bytecode++;
}

/**
 * dup2_x1命令を実行する
 */
EXECUTOR ( DUP2_X1 )
{
	dup2_x1(current_frame);
	bytecode++;
}

/**
 * dup2_x2命令を実行する
 */
EXECUTOR ( DUP2_X2 )
{
	dup2_x2(current_frame);
	bytecode++;
}

/**
 * swap命令を実行する
 */
EXECUTOR ( SWAP )
{
	swap(current_frame);
	bytecode++;
}


/**
 * iadd命令を実行する
 */
EXECUTOR ( IADD )
{
	ADD_STACK(current_frame, jint);
	bytecode++;
}

/**
 * ladd命令を実行する
 */
EXECUTOR ( LADD )
{
	ADD2_STACK(current_frame, jlong);
	bytecode++;
}

/**
 * fadd命令を実行する
 */
EXECUTOR ( FADD )
{
	ADD_STACK(current_frame, jfloat);
	bytecode++;
}

/**
 * dadd命令を実行する
 */
EXECUTOR ( DADD )
{
	ADD2_STACK(current_frame, jdouble);
	bytecode++;
}

/**
 * isub命令を実行する
 */
EXECUTOR ( ISUB )
{
	SUB_STACK(current_frame, jint);
	bytecode++;
}

/**
 * lsub命令を実行する
 */
EXECUTOR ( LSUB )
{
	SUB2_STACK(current_frame, jlong);
	bytecode++;
}

/**
 * fsub命令を実行する
 */
EXECUTOR ( FSUB )
{
	SUB_STACK(current_frame, jfloat);
	bytecode++;
}

/**
 * dsub命令を実行する
 */
EXECUTOR ( DSUB )
{
	SUB2_STACK(current_frame, jdouble);
	bytecode++;
}

/**
 * imul命令を実行する
 */
EXECUTOR ( IMUL )
{
	MUL_STACK(current_frame, jint);
	bytecode++;
}

/**
 * lmul命令を実行する
 */
EXECUTOR ( LMUL )
{
	MUL2_STACK(current_frame, jlong);
	bytecode++;
}

/**
 * fmul命令を実行する
 */
EXECUTOR ( FMUL )
{
	MUL_STACK(current_frame, jfloat);
	bytecode++;
}

/**
 * dmul命令を実行する
 */
EXECUTOR ( DMUL )
{
	MUL2_STACK(current_frame, jdouble);
	bytecode++;
}

/**
 * idiv命令を実行する
 */
EXECUTOR ( IDIV )
{
	jint value2;
	FAST_PEEK_STACK_DATA(stack_base, pposition, 0, jint, value2);
	if (value2 == 0) {
		throw_exception(current_frame, "java/lang/ArithmeticException", "/ by zero");
		CHECK_EXCEPTION;
	}

	jint value1;
	FAST_PEEK_STACK_DATA(stack_base, pposition, 1, jint, value1);

	// パラメータ2個をまとめてPOPして破棄する
	FAST_POP_DISCARD_N(pposition, 2);
	
	// 計算結果をPUSHする
	FAST_PUSH_INT(stack_base, pposition, value1 / value2);
	bytecode++;
}

/**
 * ldiv命令を実行する
 */
EXECUTOR ( LDIV )
{
	__int64 value2;
	POP_LONG(current_frame, value2);
	if (value2 == 0) {
		throw_exception(current_frame, "java/lang/ArithmeticException", "/ by zero");
		CHECK_EXCEPTION;
	}
	__int64 value1;
	POP_LONG(current_frame, value1);
	__int64 result = value1 / value2;
	PUSH_LONG(current_frame, value1 / value2);
	bytecode++;
}

/**
 * fdiv命令を実行する
 */
EXECUTOR ( FDIV )
{
	jfloat value2;
	// FAST_POP_FLOAT(stack_base, pposition, value2);
	FAST_PEEK_STACK_DATA(stack_base, pposition, 0, jfloat, value2);
	jfloat value1;
	// FAST_POP_FLOAT(stack_base, pposition, value1);
	FAST_PEEK_STACK_DATA(stack_base, pposition, 1, jfloat, value1);

	// パラメータをまとめて破棄する
	FAST_POP_DISCARD_N(pposition, 2);

	// 結果をPUSHする
	FAST_PUSH_FLOAT(stack_base, pposition, value1 / value2);
	bytecode++;
}

/**
 * ddiv命令を実行する
 */
EXECUTOR ( DDIV )
{
	double value2;
	POP_DOUBLE(current_frame, value2);
	double value1;
	POP_DOUBLE(current_frame, value1);
	PUSH_DOUBLE(current_frame, value1 / value2);
	bytecode++;
}

/**
 * irem命令を実行する
 */
EXECUTOR ( IREM )
{
	__int32 value2;
	FAST_POP_INT(stack_base, pposition, value2);
	if (value2 == 0) {
		throw_exception(current_frame, "java/lang/ArithmeticException", "% by zero");
		CHECK_EXCEPTION;
	}

	__int32 value1;
	FAST_POP_INT(stack_base, pposition, value1);
	FAST_PUSH_INT(stack_base, pposition, value1 % value2);
	bytecode++;
}

/**
 * lrem命令を実行する
 */
EXECUTOR ( LREM )
{
	__int64 value2;
	POP_LONG(current_frame, value2);
	if (value2 == 0) {
		throw_exception(current_frame, "java/lang/ArithmeticException", "% by zero");
		CHECK_EXCEPTION;
	}

	__int64 value1;
	POP_LONG(current_frame, value1);
	PUSH_LONG(current_frame, value1 % value2);
	bytecode++;
}

/**
 * frem命令を実行する
 */
EXECUTOR ( FREM )
{
	float value2;
	FAST_POP_FLOAT(stack_base, pposition, value2);
	float value1;
	FAST_POP_FLOAT(stack_base, pposition, value1);
	float result = (float) fmod(value1, value2);
	// PUSH_FLOAT(current_frame, result);
	FAST_PUSH_FLOAT(stack_base, pposition, result);
	bytecode++;
}

/**
 * drem命令を実行する
 */
EXECUTOR ( DREM )
{
	double value2;
	POP_DOUBLE(current_frame, value2);
	double value1;
	POP_DOUBLE(current_frame, value1);
	double result = fmod(value1, value2);
	PUSH_DOUBLE(current_frame, result);
	bytecode++;
}

/**
 * ineg命令を実行する
 */
EXECUTOR ( INEG )
{
	__int32 value;
	FAST_POP_INT(stack_base, pposition, value);
	FAST_PUSH_INT(stack_base, pposition, -value);
	bytecode++;
}

/**
 * lneg命令を実行する
 */
EXECUTOR ( LNEG )
{
	__int64 value;
	POP_LONG(current_frame, value);
	PUSH_LONG(current_frame, -value);
	bytecode++;
}

/**
 * fneg命令を実行する
 */
EXECUTOR ( FNEG )
{
	float value;
	FAST_POP_FLOAT(stack_base, pposition, value);
	FAST_PUSH_FLOAT(stack_base, pposition, -value);
	bytecode++;
}

/**
 * dneg命令を実行する
 */
EXECUTOR ( DNEG )
{
	double value;
	POP_DOUBLE(current_frame, value);
	PUSH_DOUBLE(current_frame, -value);
	bytecode++;
}


/**
 * ishl命令を実行する
 */
EXECUTOR ( ISHL )
{
	ISHL_STACK(current_frame);
	bytecode++;
}

/**
 * lshl命令を実行する
 */
EXECUTOR ( LSHL )
{
	__int32 value2;
	FAST_POP_INT(stack_base, pposition, value2);
	value2 &= 0x3f;	// シフト回数をマスクする
	__int64 value1;
	POP_LONG(current_frame, value1);
	PUSH_LONG(current_frame, value1 <<= value2);
	bytecode++;
}

/**
 * ishr命令を実行する
 */
EXECUTOR ( ISHR )
{
	ISHR_STACK(current_frame);
	bytecode++;
}

/**
 * lshr命令を実行する
 */
EXECUTOR ( LSHR )
{
	__int32 value2;
	FAST_POP_INT(stack_base, pposition, value2);
	value2 &= 0x3f;	// シフト回数をマスクする

	__int64 value1;
	POP_LONG(current_frame, value1);
	
	PUSH_LONG(current_frame, value1 >> value2);
	bytecode++;
}

/**
 * iushr命令を実行する
 */
EXECUTOR ( IUSHR )
{
	IUSHR_STACK(current_frame);
	bytecode++;
}

/**
 * lushr命令を実行する
 */
EXECUTOR ( LUSHR )
{
	__int32 value2;
	FAST_POP_INT(stack_base, pposition, value2);
	__int32 s = value2 & 0x3f;	// シフト回数をマスクする

	__int64 value1;
	POP_LONG(current_frame, value1);
	
	unsigned __int64 result = value1;
	result >>= s;
	PUSH_LONG(current_frame, result);
	bytecode++;
}

/**
 * iand命令を実行する
 */
EXECUTOR ( IAND )
{
	IAND_STACK(current_frame);
	bytecode++;
}

/**
 * land命令を実行する
 */
EXECUTOR ( LAND )
{
	LAND_STACK(current_frame);
	bytecode++;
}

/**
 * ior命令を実行する
 */
EXECUTOR ( IOR )
{
	IOR_STACK(current_frame);
	bytecode++;
}

/**
 * lor命令を実行する
 */
EXECUTOR ( LOR )
{
	LOR_STACK(current_frame);
	bytecode++;
}


/**
 * ixor命令を実行する
 */
EXECUTOR ( IXOR )
{
	IXOR_STACK(current_frame);
	bytecode++;
}

/**
 * lxor命令を実行する
 */
EXECUTOR ( LXOR )
{
	LXOR_STACK(current_frame);
	bytecode++;
}

/**
 * iinc命令を実行する
 */
EXECUTOR ( IINC )
{
	__int8 count = bytecode[2];
	// IINC_LOCAL(current_frame, bytecode[1], (__int16) count);	// 符号拡張	
	FAST_IINC_LOCAL(local_variables_base, bytecode[1], (__int16) count);
	bytecode += 3;
}

/**
 * i2l命令を実行する
 */
EXECUTOR ( I2L )
{
	__int32 value;
	FAST_POP_INT(stack_base, pposition, value);
	__int64 result = value;
	PUSH_LONG(current_frame, result);
	bytecode++;
}

/**
 * i2f命令を実行する
 */
EXECUTOR ( I2F )
{
	I2F_STACK(current_frame);
	bytecode++;
}

/**
 * i2d命令を実行する
 */
EXECUTOR ( I2D )
{
	__int32 value;
	FAST_POP_INT(stack_base, pposition, value);
	double result = value;
	PUSH_DOUBLE(current_frame, result);
	bytecode++;
}

/**
 * l2i命令を実行する
 */
EXECUTOR ( L2I )
{
	L2I_STACK(current_frame);
	bytecode++;
}

/**
 * l2f命令を実行する
 */
EXECUTOR ( L2F )
{
	L2F_STACK(current_frame);
	bytecode++;
}

/**
 * l2d命令を実行する
 */
EXECUTOR ( L2D )
{
	L2D_STACK(current_frame);
	bytecode++;
}

/**
 * f2i命令を実行する
 */
EXECUTOR ( F2I )
{
	F2I_STACK(current_frame);
	bytecode++;
}

/**
 * f2l命令を実行する
 */
EXECUTOR ( F2L )
{
	float value;
	FAST_POP_FLOAT(stack_base, pposition, value);
	__int64 result = (__int64) value;
	PUSH_LONG(current_frame, result);
	bytecode++;
}

/**
 * f2d命令を実行する
 */
EXECUTOR ( F2D )
{
	float f;
	FAST_POP_FLOAT(stack_base, pposition, f);
	double d = f;
	PUSH_DOUBLE(current_frame, d);
	bytecode++;
}

/**
 * d2i命令を実行する
 */
EXECUTOR ( D2I )
{
	double value;
	POP_DOUBLE(current_frame, value);
	__int32 result = (__int32) value;
	FAST_PUSH_INT(stack_base, pposition, result);
	bytecode++;
}

/**
 * d2l命令を実行する
 */
EXECUTOR ( D2L )
{
	double value;
	POP_DOUBLE(current_frame, value);
	__int64 result = (__int64) value;
	PUSH_LONG(current_frame, result);
	bytecode++;
}

/**
 * d2f命令を実行する
 */
EXECUTOR ( D2F )
{
	D2F_STACK(current_frame);
	bytecode++;
}

/**
 * i2b命令を実行する
 */
EXECUTOR ( I2B )
{
	__int32 value;
	FAST_POP_INT(stack_base, pposition, value);
	__int8 result = (__int8) value;
	FAST_PUSH_INT(stack_base, pposition, result);
	bytecode++;
}

/**
 * i2c命令を実行する
 */
EXECUTOR ( I2C )
{
	__int32 value;
	FAST_POP_INT(stack_base, pposition, value);
	unsigned __int16 result = (unsigned __int16) value;
	FAST_PUSH_INT(stack_base, pposition, result);
	bytecode++;
}

/**
 * i2s命令を実行する
 */
EXECUTOR ( I2S )
{
	__int32 value;
	FAST_POP_INT(stack_base, pposition, value);
	__int16 result = (__int16) value;
	FAST_PUSH_INT(stack_base, pposition, result);
	bytecode++;
}

/**
 * lcmp命令を実行する
 */
EXECUTOR ( LCMP )
{
	__int64 value2;
	POP_LONG(current_frame, value2);
	
	__int64	value1;
	POP_LONG(current_frame, value1);

	if (value1 > value2) {
		FAST_PUSH_INT(stack_base, pposition, 1);
	} else if (value1 == value2) {
		FAST_PUSH_INT(stack_base, pposition, 0);
	} else {	// value1 > value2
		FAST_PUSH_INT(stack_base, pposition, -1);
	}
	bytecode++;
}

/**
 * fcmpl命令を実行する
 */
EXECUTOR ( FCMPL )
{
	jfloat value2;
	FAST_PEEK_STACK_DATA(stack_base, pposition, 0, jfloat, value2);
	jfloat value1;
	FAST_PEEK_STACK_DATA(stack_base, pposition, 1, jfloat, value1);

	// パラメータをまとめてPOPし、破棄する
	FAST_POP_DISCARD_N(pposition, 2);

	if (_isnan(value1) || _isnan(value2)) {
		// NaN
		FAST_PUSH_INT(stack_base, pposition, -1);
	} else {
		if (value1 > value2) {
			FAST_PUSH_INT(stack_base, pposition, 1);
		} else if (value1 == value2) {
			FAST_PUSH_INT(stack_base, pposition, 0);
		} else {
			FAST_PUSH_INT(stack_base, pposition, -1);
		}
	}
	bytecode++;
}

/**
 * fcmpg命令を実行する
 */
EXECUTOR ( FCMPG )
{
	jfloat value2;
	FAST_PEEK_STACK_DATA(stack_base, pposition, 0, jfloat, value2);
	jfloat value1;
	FAST_PEEK_STACK_DATA(stack_base, pposition, 1, jfloat, value1);

	// パラメータをまとめて破棄する
	FAST_POP_DISCARD_N(pposition, 2);

	if (_isnan(value1) || _isnan(value2)) {
		// NaN
		FAST_PUSH_INT(stack_base, pposition, 1);
	} else {
		if (value1 > value2) {
			FAST_PUSH_INT(stack_base, pposition, 1);
		} else if (value1 == value2) {
			FAST_PUSH_INT(stack_base, pposition, 0);
		} else {
			FAST_PUSH_INT(stack_base, pposition, -1);
		}
	}
	bytecode++;
}

/**
 * dcmpl命令を実行する
 */
EXECUTOR ( DCMPL )
{
	double value2;
	POP_DOUBLE(current_frame, value2);
	double value1;
	POP_DOUBLE(current_frame, value1);

	if (_isnan(value1) || _isnan(value2)) {
		// NaN
		FAST_PUSH_INT(stack_base, pposition, -1);
	} else {
		if (value1 > value2) {
			FAST_PUSH_INT(stack_base, pposition, 1);
		} else if (value1 == value2) {
			FAST_PUSH_INT(stack_base, pposition, 0);
		} else {
			FAST_PUSH_INT(stack_base, pposition, -1);
		}
	}
	bytecode++;
}

/**
 * dcmpg命令を実行する
 */
EXECUTOR ( DCMPG )
{
	double value2;
	POP_DOUBLE(current_frame, value2);
	double value1;
	POP_DOUBLE(current_frame, value1);

	if (_isnan(value1) || _isnan(value2)) {
		// NaN
		FAST_PUSH_INT(stack_base, pposition, 1);
	} else {
		if (value1 > value2) {
			FAST_PUSH_INT(stack_base, pposition, 1);
		} else if (value1 == value2) {
			FAST_PUSH_INT(stack_base, pposition, 0);
		} else {
			FAST_PUSH_INT(stack_base, pposition, -1);
		}
	}
	bytecode++;
}

/**
 * ifeq命令を実行する
 */
EXECUTOR ( IFEQ )
{
	__int32 value;
	FAST_POP_INT(stack_base, pposition, value);
	SET_JUMP_ADDRESS(current_frame, (value == 0), bytecode[1], bytecode[2], 3);
}

/**
 * ifne命令を実行する
 */
EXECUTOR ( IFNE )
{
	__int32 value;
	FAST_POP_INT(stack_base, pposition, value);
	SET_JUMP_ADDRESS(current_frame, (value != 0), bytecode[1], bytecode[2], 3);
}

/**
 * iflt命令を実行する
 */
EXECUTOR ( IFLT )
{
	__int32 value;
	FAST_POP_INT(stack_base, pposition, value);
	SET_JUMP_ADDRESS(current_frame, (value < 0), bytecode[1], bytecode[2], 3);
}

/**
 * ifle命令を実行する
 */
EXECUTOR ( IFLE )
{
	__int32 value;
	FAST_POP_INT(stack_base, pposition, value);
	SET_JUMP_ADDRESS(current_frame, (value <= 0), bytecode[1], bytecode[2], 3);
}

/**
 * ifgt命令を実行する
 */
EXECUTOR ( IFGT )
{
	__int32 value;
	FAST_POP_INT(stack_base, pposition, value);
	SET_JUMP_ADDRESS(current_frame, (value > 0), bytecode[1], bytecode[2], 3);
}

/**
 * ifge命令を実行する
 */
EXECUTOR ( IFGE )
{
	__int32 value;
	FAST_POP_INT(stack_base, pposition, value);
	SET_JUMP_ADDRESS(current_frame, (value >= 0), bytecode[1], bytecode[2], 3);
}

/**
 * if_icmpeq命令を実行する
 */
EXECUTOR ( IF_ICMPEQ )
{
	// スタックからパラメータを取り出す
	jint value2;
	FAST_PEEK_STACK_DATA(stack_base, pposition, 0, jint, value2);
	jint value1;
	FAST_PEEK_STACK_DATA(stack_base, pposition, 1, jint, value1);

	// パラメータをまとめて破棄する
	FAST_POP_DISCARD_N(pposition, 2);

	SET_JUMP_ADDRESS(current_frame, (value1 == value2), bytecode[1], bytecode[2], 3);
}

/**
 * if_icmpne命令を実行する
 */
EXECUTOR ( IF_ICMPNE )
{
	// スタックからパラメータを取り出す
	jint value2;
	FAST_PEEK_STACK_DATA(stack_base, pposition, 0, jint, value2);
	jint value1;
	FAST_PEEK_STACK_DATA(stack_base, pposition, 1, jint, value1);

	// パラメータをまとめて破棄する
	FAST_POP_DISCARD_N(pposition, 2);

	SET_JUMP_ADDRESS(current_frame, (value1 != value2), bytecode[1], bytecode[2], 3);
}

/**
 * if_icmplt命令を実行する
 */
EXECUTOR ( IF_ICMPLT )
{
	// スタックからパラメータを取り出す
	jint value2;
	FAST_PEEK_STACK_DATA(stack_base, pposition, 0, jint, value2);
	jint value1;
	FAST_PEEK_STACK_DATA(stack_base, pposition, 1, jint, value1);

	// パラメータをまとめて破棄する
	FAST_POP_DISCARD_N(pposition, 2);

	SET_JUMP_ADDRESS(current_frame, (value1 < value2), bytecode[1], bytecode[2], 3);
}

/**
 * if_icmpge命令を実行する
 */
EXECUTOR ( IF_ICMPGE )
{
	// スタックからパラメータを取り出す
	jint value2;
	FAST_PEEK_STACK_DATA(stack_base, pposition, 0, jint, value2);
	jint value1;
	FAST_PEEK_STACK_DATA(stack_base, pposition, 1, jint, value1);

	// パラメータをまとめて破棄する
	FAST_POP_DISCARD_N(pposition, 2);

	SET_JUMP_ADDRESS(current_frame, (value1 >= value2), bytecode[1], bytecode[2], 3);
}

/**
 * if_icmpgt命令を実行する
 */
EXECUTOR ( IF_ICMPGT )
{
	// スタックからパラメータを取り出す
	jint value2;
	FAST_PEEK_STACK_DATA(stack_base, pposition, 0, jint, value2);
	jint value1;
	FAST_PEEK_STACK_DATA(stack_base, pposition, 1, jint, value1);

	// パラメータをまとめて破棄する
	FAST_POP_DISCARD_N(pposition, 2);

	SET_JUMP_ADDRESS(current_frame, (value1 > value2), bytecode[1], bytecode[2], 3);
}

/**
 * if_icmple命令を実行する
 */
EXECUTOR ( IF_ICMPLE )
{
	// スタックからパラメータを取り出す
	jint value2;
	FAST_PEEK_STACK_DATA(stack_base, pposition, 0, jint, value2);
	jint value1;
	FAST_PEEK_STACK_DATA(stack_base, pposition, 1, jint, value1);

	// パラメータをまとめて破棄する
	FAST_POP_DISCARD_N(pposition, 2);

	SET_JUMP_ADDRESS(current_frame, (value1 <= value2), bytecode[1], bytecode[2], 3);
}

/**
 * if_acmpeq命令を実行する
 */
EXECUTOR ( IF_ACMPEQ )
{
	jobject value2;
	FAST_PEEK_STACK_DATA(stack_base, pposition, 0, jobject, value2);
	jobject value1;
	FAST_PEEK_STACK_DATA(stack_base, pposition, 1, jobject, value1);
	
	// パラメータをまとめて破棄する
	FAST_POP_DISCARD_N(pposition, 2);
	
	SET_JUMP_ADDRESS(current_frame, (value1 == value2), bytecode[1], bytecode[2], 3);
}

/**
 * if_acmpne命令を実行する
 */
EXECUTOR ( IF_ACMPNE )
{
	jobject value2;
	FAST_PEEK_STACK_DATA(stack_base, pposition, 0, jobject, value2);
	jobject value1;
	FAST_PEEK_STACK_DATA(stack_base, pposition, 1, jobject, value1);
	
	// パラメータをまとめて破棄する
	FAST_POP_DISCARD_N(pposition, 2);

	SET_JUMP_ADDRESS(current_frame, (value1 != value2), bytecode[1], bytecode[2], 3);
}

/**
 * goto命令を実行する
 */
EXECUTOR ( GOTO )
{
	// Thread.interrupt()された場合に対応するために、例外をチェックする
	CHECK_EXCEPTION;
	short branchoffset = (bytecode[1] << 8) | (bytecode[2] & 0xff);
	bytecode += branchoffset;
}

/**
 * jsr命令を実行する
 */
EXECUTOR ( JSR )
{
	__int16 offset = MAKE_INT16(bytecode[1], bytecode[2]);
	execute_jsr(current_frame, (__int32) offset);
	
	CHECK_EXCEPTION;
}

/**
 * ret命令を実行する
 */
EXECUTOR ( RET )
{
	__int32 address = get_int(current_frame, bytecode[1]);
	// jsr命令で最上位ビットが立てられているため、最上位ビットをクリアする
	bytecode = (u1*) (address & ~0x80000000);
}

/**
 * tableswitch命令を実行する
 */
EXECUTOR ( TABLESWITCH )
{
	execute_tableswitch(current_frame, bytecode);
	CHECK_EXCEPTION;
}

/**
 * lookupswitch命令を実行する
 */
EXECUTOR ( LOOKUPSWITCH )
{
	execute_lookupswitch(current_frame, bytecode);
	CHECK_EXCEPTION;
}

/**
 * ireturn命令を実行する
 */
EXECUTOR       ( IRETURN )
EXECUTOR_ALIAS ( LRETURN )
EXECUTOR_ALIAS ( FRETURN )
EXECUTOR_ALIAS ( DRETURN )
EXECUTOR_ALIAS ( ARETURN )
EXECUTOR_ALIAS (  RETURN )
{
	goto END;	// リターンする
}

/**
 * getstatic命令を実行する
 */
EXECUTOR ( GETSTATIC )
{
	execute_getstatic(current_frame, bytecode);
	CHECK_EXCEPTION;
	bytecode += 3;
}

/**
 * putstatic命令を実行する
 */
EXECUTOR ( PUTSTATIC )
{ 
	execute_putstatic(current_frame, bytecode);
	CHECK_EXCEPTION;
	bytecode += 3;
}

/**
 * getfield命令を実行する
 */
EXECUTOR ( GETFIELD )
{
//	execute_getfield(current_frame, bytecode);
	u1 index1 = GET_PARAMETER(bytecode, 1);
	u1 index2 = GET_PARAMETER(bytecode, 2);
	u2 index = MAKE_U2(index1, index2);

	// インデックスで指定された CONSTANT_Fieldref_info 構造体へのポインタを取得する
	CONSTANT_Fieldref_info* fieldref = get_CONSTANT_Fieldref_info(current_frame->current_class_file, index);
	
	// Fieldrefで指定されたクラスを取得する
	ClassFile* target_class_file = fieldref->class_file;
	if (target_class_file == NULL) {
		class_loader* loader = get_defining_loader(current_frame->current_class_file);
		target_class_file = find_ClassFile(current_frame, loader, fieldref->class_name);
		if (! target_class_file) {
			// 初期化に失敗
			// 例外が設定されているはず
			CHECK_EXCEPTION;
		}
		fieldref->class_file = target_class_file;

	}
	
	// フィールドIDを取得する
	jfieldID fid = fieldref->field_id;
	if (fid == NULL) {
		fid = get_field_id(target_class_file,
						   fieldref->field_name,
						   fieldref->field_descriptor);
		if (fid == NULL) {
			// 例外を設定する
			throw_exception(current_frame, "java/lang/NoSuchFieldError");
			CHECK_EXCEPTION;
		}
		fieldref->field_id = fid;
	}

	// 設定対象となるクラスのClassFile構造体を取得する
	field_info* finfo = get_field_info(target_class_file, fid);
	ClassFile* declaring_class_file = finfo->declaring_ClassFile;
	assert(declaring_class_file);

	// ロード制約を追加する
	if (! add_loading_constraints_of_method(current_frame,
											declaring_class_file,
											finfo->descriptor)) {
		// ロード制約違反
		CHECK_EXCEPTION;
	}
	// アクセス権限をチェックする
	if (! is_accessible(current_frame, current_frame->current_class_file, declaring_class_file, finfo->access_flags)) {
		throw_exception(current_frame, "java/lang/IllegalAccessError", finfo->name);
		CHECK_EXCEPTION;
	}

	// フィールドのオフセットをキャッシュしておく
	// 無効な値と区別するために、最上位ビットを立てておく
	fieldref->field_position = finfo->position | 0x80000000;

	// quick命令に書き換える
	REWRITE_BYTECODE(GETFIELD_QUICK);
	continue;
}

/**
 * getfield_quick命令を実行する（内部命令）
 */
EXECUTOR ( GETFIELD_QUICK )
{
	u2 index = MAKE_U2(bytecode[1], bytecode[2]);

	// インデックスで指定された CONSTANT_Fieldref_info 構造体へのポインタを取得する
	CONSTANT_Fieldref_info* fieldref = get_CONSTANT_Fieldref_info(current_frame->current_class_file, index);

	// フィールドの最上位ビットをクリアした値が
	// 実際のポジション
	get_field_by_position(current_frame,
						  fieldref->field_descriptor,
						  (fieldref->field_position & ~0x80000000));
	CHECK_EXCEPTION;
	bytecode += 3;
}


/**
 * putfield命令を実行する
 */
EXECUTOR ( PUTFIELD )
{
//	execute_putfield(current_frame, bytecode);
	u2 index = MAKE_U2(bytecode[1], bytecode[2]);

	// インデックスで指定された CONSTANT_Fieldref_info 構造体へのポインタを取得する
	CONSTANT_Fieldref_info* fieldref = get_CONSTANT_Fieldref_info(current_frame->current_class_file, index);
	
	// Fieldrefで指定されたクラスを取得する
	ClassFile* target_class_file = fieldref->class_file;
	if (target_class_file == NULL) {
		class_loader* loader = get_defining_loader(current_frame->current_class_file);
		target_class_file = find_ClassFile(current_frame, loader, fieldref->class_name);
		if (! target_class_file) {
			// 初期化に失敗
			CHECK_EXCEPTION;
		}
		fieldref->class_file = target_class_file;
	}

	// フィールドIDを取得する
	jfieldID fid = fieldref->field_id;
	if (fid == NULL) {
		fid = get_field_id(target_class_file,
						   fieldref->field_name,
						   fieldref->field_descriptor);
		if (fid == NULL) {
			// 例外を設定する
			throw_exception(current_frame, "java/lang/NoSuchFieldError");
			CHECK_EXCEPTION;
		}
		fieldref->field_id = fid;
	}

	// 設定対象となるクラスのClassFile構造体を取得する
	field_info* finfo = get_field_info(target_class_file, fid);
	ClassFile* declaring_class_file = finfo->declaring_ClassFile;
	assert(declaring_class_file);

	// ロード制約を追加する
	if (! add_loading_constraints_of_method(current_frame,
											declaring_class_file,
											finfo->descriptor)) {
		CHECK_EXCEPTION;
	}

	// アクセス権限をチェックする
	if (! is_accessible(current_frame, current_frame->current_class_file, declaring_class_file, finfo->access_flags)) {
		throw_exception(current_frame, "java/lang/IllegalAccessError", finfo->name);
		CHECK_EXCEPTION;
	}
	// フィールドのポジションをキャッシュしておく
	// NULLと有効な値(=オフセット0）とを区別するため、最上位ビットを立てておく
	fieldref->field_position = finfo->position | 0x80000000;

	// 命令を書き換える
	REWRITE_BYTECODE(PUTFIELD_QUICK);
	continue;
}

/**
 * putfield_quick命令を実行する（内部命令）
 */
EXECUTOR ( PUTFIELD_QUICK )
{
	u2 index = MAKE_U2(bytecode[1], bytecode[2]);

	// インデックスで指定された CONSTANT_Fieldref_info 構造体へのポインタを取得する
	CONSTANT_Fieldref_info* fieldref = get_CONSTANT_Fieldref_info(current_frame->current_class_file, index);
	
	// フィールドの位置が判明している場合は、それを利用する
	// アドレスに戻すために、最上位ビットをクリアする
	put_field_by_position(current_frame,
						  fieldref->field_descriptor,
						  fieldref->field_position & ~0x80000000);
	CHECK_EXCEPTION;
	bytecode += 3;
}

/**
 * invokevirtual命令を実行する
 */
EXECUTOR ( INVOKEVIRTUAL )
{
	u2 index = MAKE_U2(bytecode[1], bytecode[2]);
	
	// 呼び出し対象となるメソッドの CONSTANT_Methodref_info を取得する
	CONSTANT_Methodref_info* methodref
		= get_CONSTANT_Methodref_info(current_frame->current_class_file, index);

	// 対象クラスを解決する
	ClassFile* target_class_file = methodref->class_file;
	if (target_class_file == NULL) {
		class_loader* loader = get_defining_loader(current_frame->current_class_file);
		target_class_file = find_ClassFile(current_frame, loader, methodref->class_name);
		methodref->class_file = target_class_file;

	}
	if (! target_class_file) {
		// クラスのロード失敗
		CHECK_EXCEPTION;
	}

	// 対象クラスにアクセス可能か？
	if (! is_accessible(current_frame,
						current_frame->current_class_file,
						target_class_file,
						target_class_file->access_flags)) {
		// 対象クラスにアクセス不可能な場合
		throw_exception(current_frame, "java/lang/IllegalAccessError");
		CHECK_EXCEPTION;
	}

	// 呼び出し対象となるメソッドを解決する
	jmethodID mid = methodref->mid;
	if (! mid) {
		// メソッドを検索する
		mid = get_method_id(target_class_file,
							methodref->method_name,
							methodref->method_descriptor);
		if (mid == NULL) {
			throw_exception(current_frame,
							"java/lang/NoSuchMethodError",
							methodref->method_name);
			CHECK_EXCEPTION;
		} else {
			methodref->mid = mid;
		}
	}
	
	method_info* target_method_info = get_method_info(target_class_file, mid);
	// メソッドにアクセスできるかを調べる
	if (! is_accessible(current_frame,
						current_frame->current_class_file,
						target_class_file,
						target_method_info->access_flags)) {
		if (! (target_class_file->this_class_name[0] == '['
				&& target_method_info->name == CLONE_METHOD_NAME)) {
			// 配列クラスの clone() メソッドのみ特別扱いする。(protectedだが無条件にアクセス可能とする）
			// ToDo: 本当にこの方法でよいか？
			throw_exception(current_frame, "java/lang/IllegalAccessError");
			CHECK_EXCEPTION;
		}
	}

	// ロード制約を追加する
	if (! add_loading_constraints_of_method(current_frame,
											target_method_info->declaring_ClassFile,
											target_method_info->descriptor)) {
		CHECK_EXCEPTION;
	}

	// 命令を書き換える
	REWRITE_BYTECODE( INVOKEVIRTUAL_QUICK );
	continue;
}

/**
 * invokevirtual_quick命令を実行する（内部命令）
 */
EXECUTOR ( INVOKEVIRTUAL_QUICK )
{
	u2 index = MAKE_U2(bytecode[1], bytecode[2]);
	
	// 呼び出し対象となるメソッドの CONSTANT_Methodref_info を取得する
	CONSTANT_Methodref_info* methodref
		= get_CONSTANT_Methodref_info(current_frame->current_class_file, index);

	// 呼び出し対象となるクラスとメソッドを解決する
	ClassFile* target_class_file = methodref->class_file;
	jmethodID mid = methodref->mid;

	// オペランドスタックから objectref (this) を取得する
	u2 param_count = get_parameters_count(methodref);
	jobject objectref;
	get_stack_data(current_frame, param_count, (__int32*) &objectref);

	if (! objectref) {
		throw_exception(current_frame, "java/lang/NullPointerException");
		CHECK_EXCEPTION;
	}
	ClassFile* object_class_file = get_ClassFile(objectref);

	// 呼び出し対象となるClassFileとmethod_infoを取得する
	method_info* target_method_info = get_method_info(object_class_file, mid);
	ClassFile* declaring_class_file = target_method_info->declaring_ClassFile;
	
	// メソッド本体を実行する
	invoke_method(current_frame, objectref, declaring_class_file, target_method_info);
	CHECK_EXCEPTION;
	bytecode += 3;
}

/**
 * invokespecial命令を実行する
 */
EXECUTOR ( INVOKESPECIAL )
{
	u2 index = MAKE_U2(bytecode[1], bytecode[2]);

	// 呼び出し対象となるメソッドの CONSTANT_Methodref_info を取得する
	CONSTANT_Methodref_info* methodref = get_CONSTANT_Methodref_info(current_frame->current_class_file, index);

	// 呼び出し対象となるクラスとメソッドを解決する
	ClassFile* target_class_file = methodref->class_file;
	if (target_class_file == NULL) {
		class_loader* loader = get_defining_loader(current_frame->current_class_file);
		target_class_file = find_ClassFile(current_frame, loader, methodref->class_name);
		if (! target_class_file) {
			// ロード失敗
			CHECK_EXCEPTION;
		}
		methodref->class_file = target_class_file;
	}

	jmethodID mid = methodref->mid;
	if (! mid) {
		mid = get_method_id(target_class_file, methodref->method_name, methodref->method_descriptor);
		if (mid == NULL) {
			throw_exception(current_frame, "java/lang/NoSuchMethodError", methodref->method_name);
			CHECK_EXCEPTION;
		}
		methodref->mid = mid;
	}
	
	// 呼び出し対象となるClassFileとmethod_infoを取得する
	// 検索の基準となるクラスはオペランドスタック上のオブジェクトではなく、
	// CONSTANT_Methodref_infoで指定されたクラスを使用する
	method_info* target_method_info   = get_method_info(target_class_file, mid);
	ClassFile*   declaring_class_file = target_method_info->declaring_ClassFile;

	const java_utf8* target_method_name = target_method_info->name;
	const java_utf8* target_method_desc = target_method_info->descriptor;

	// "super.method()" と"non-virtual呼び出し" のどちらであるかを調べる
	bool super_method;

	// 以下の特殊条件を満たしているかを調べる
	//		・カレントクラスのACC_SUPERフラグが立っている
	//		・ターゲットクラスはカレントクラスのスーパークラスである
	//		・"<init>"メソッドではない
	// 上記条件を満たしている場合 super.メソッド名() の処理を行う
	if (INIT_METHOD_NAME != target_method_name) {
		if ((current_frame->current_class_file->access_flags & ACC_SUPER) != 0
				&& ((current_frame->current_class_file != target_class_file)
						&& is_assignable_from(current_frame, current_frame->current_class_file, target_class_file))) {

			// 直接のスーパークラスを取得する
			ClassFile* super_class_file = get_superclass_ClassFile(current_frame->current_class_file);

			// 該当メソッドのメソッドIDを取得する
			jmethodID mid2 = get_method_id(super_class_file,
										  target_method_name,
										  target_method_desc);
			if (mid2 == NULL) {
				// 見つからなかった場合、AbstractMethodErrorを設定し、リターンする
				throw_exception(current_frame,
								"java/lang/AbstractMethodError",
								target_method_name);
				CHECK_EXCEPTION;
			}
			assert(mid == mid2);

			// スーパークラスのメソッド情報を得る
			target_method_info	 = get_method_info(super_class_file, mid2);
			declaring_class_file = target_method_info->declaring_ClassFile;
			super_method = true;
		} else {
			super_method = false;
		}
	} else {
		super_method = false;
	}

	// ロード制約を追加する
	if (! add_loading_constraints_of_method(current_frame,
											declaring_class_file,
											target_method_info->descriptor)) {
		CHECK_EXCEPTION;
	}

	// アクセス権限を調べる
	if (! is_accessible(current_frame,
						current_frame->current_class_file,
						target_class_file,
						target_method_info->access_flags)) {
		throw_exception(current_frame, "java/lang/IllegalAccessError");
		CHECK_EXCEPTION;
	}
	
	// 命令を書き換える
	if (super_method) {
		// super.method()
		REWRITE_BYTECODE( INVOKESUPER_QUICK );
	} else {
		// non-virtual呼び出し
		REWRITE_BYTECODE( INVOKENONVIRTUAL_QUICK );
	}
	continue;
}

/**
 * invokesuper_quick命令を実行する（内部命令）
 */
EXECUTOR ( INVOKESUPER_QUICK )
{
	u2 index = MAKE_U2(bytecode[1], bytecode[2]);

	// 呼び出し対象となるメソッドの CONSTANT_Methodref_info を取得する
	CONSTANT_Methodref_info* methodref = get_CONSTANT_Methodref_info(current_frame->current_class_file, index);

	// 呼び出し対象となるクラスとメソッドを解決する
	ClassFile* target_class_file = methodref->class_file;
	jmethodID mid = methodref->mid;
	
	// 直接のスーパークラスを取得する
	ClassFile* super_class_file = get_superclass_ClassFile(current_frame->current_class_file);

	// 呼び出し対象となるClassFileとmethod_infoを取得する
	method_info* target_method_info   = get_method_info(super_class_file, mid);
	ClassFile*   declaring_class_file = target_method_info->declaring_ClassFile;

	// オペランドスタックから objectref (this) を取得する
	u2 param_count = get_parameters_count(methodref);
	jobject objectref = (jobject) current_frame->operand_stack[current_frame->operand_stack_position - param_count - 1];
	if (objectref  == NULL) {
		throw_exception(current_frame, "java/lang/NullPointerException");
		CHECK_EXCEPTION;
	}

	// メソッドを実行する
	invoke_method(current_frame, objectref, declaring_class_file, target_method_info);

	CHECK_EXCEPTION;
	bytecode += 3;
}

/**
 * invokenonvirtual_quick命令を実行する（内部命令）
 */
EXECUTOR ( INVOKENONVIRTUAL_QUICK )
{
	u2 index = MAKE_U2(bytecode[1], bytecode[2]);

	// 呼び出し対象となるメソッドの CONSTANT_Methodref_info を取得する
	CONSTANT_Methodref_info* methodref = get_CONSTANT_Methodref_info(current_frame->current_class_file, index);

	// 呼び出し対象となるクラスとメソッドを解決する
	ClassFile* target_class_file = methodref->class_file;
	jmethodID mid = methodref->mid;
	
	// 呼び出し対象となるClassFileとmethod_infoを取得する
	method_info* target_method_info   = get_method_info(target_class_file, mid);
	ClassFile*   declaring_class_file = target_method_info->declaring_ClassFile;

	// オペランドスタックから objectref (this) を取得する
	u2 param_count = get_parameters_count(methodref);
	jobject objectref = (jobject) current_frame->operand_stack[current_frame->operand_stack_position - param_count - 1];
	if (objectref  == NULL) {
		throw_exception(current_frame, "java/lang/NullPointerException");
		CHECK_EXCEPTION;
	}

	// メソッドを実行する
	invoke_method(current_frame, objectref, declaring_class_file, target_method_info);

	CHECK_EXCEPTION;
	bytecode += 3;
}

/**
 * invokestatic命令を実行する
 */
EXECUTOR ( INVOKESTATIC )
{
	u2 index = MAKE_U2(bytecode[1], bytecode[2]);

	// 呼び出し対象となるクラスを取得する
	CONSTANT_Methodref_info* methodref = get_CONSTANT_Methodref_info(current_frame->current_class_file, index);
	
	ClassFile* target_class_file = methodref->class_file;
	if (target_class_file == NULL) {
		class_loader* loader = get_defining_loader(current_frame->current_class_file);
		target_class_file = find_ClassFile(current_frame, loader, methodref->class_name);
		methodref->class_file = target_class_file;
	}
	if (target_class_file == NULL) {
		if (! exception_occurred(current_frame)) {
			// 例外が発生していない場合は、NoClassDefFoundErrorをthrowする
			throw_exception(current_frame, "java/lang/NoClassDefFoundError", methodref->class_name);
		}
		CHECK_EXCEPTION;
	}

	// 呼び出し対象となるメソッドを取得する
	jmethodID mid = methodref->mid;
	if (! mid) {
		mid = get_method_id(target_class_file, methodref->method_name, methodref->method_descriptor);
		// メソッドが見つからなかった場合NoSuchMethodErrorをthrowする
		if (mid == NULL) {
			throw_exception(current_frame, "java/lang/NoSuchMethodError", methodref->method_name);
			CHECK_EXCEPTION;
		}
		methodref->mid = mid;
	}
	
	// メソッドが定義されているクラスと、method_info を取得する
	method_info* target_method_info = get_method_info(target_class_file, mid);
	ClassFile* declaring_class_file = target_method_info->declaring_ClassFile;
	
	// ロード制約を追加する
	if (! add_loading_constraints_of_method(current_frame,
											declaring_class_file,
											target_method_info->descriptor)) {
		CHECK_EXCEPTION;
	}

	// メソッドが定義されているクラスがインタフェースの場合、例外をthrowする
	if (is_interface(declaring_class_file->access_flags)) {
		throw_exception(current_frame, "java/lang/IncompatibleClassChangeError");
		CHECK_EXCEPTION;
	}

	// アクセス権限を調べる
	if (! is_accessible(current_frame,
						current_frame->current_class_file,
						target_class_file,
						target_method_info->access_flags)) {
		throw_exception(current_frame, "java/lang/IllegalAccessError");
		CHECK_EXCEPTION;
	}

	REWRITE_BYTECODE(INVOKESTATIC_QUICK);
	continue;
}

/**
 * invokestatic_quick命令を実行する（内部命令）
 */
EXECUTOR ( INVOKESTATIC_QUICK )
{
	u2 index = MAKE_U2(bytecode[1], bytecode[2]);

	// 呼び出し対象となるクラスとメソッドを取得する
	CONSTANT_Methodref_info* methodref
								= get_CONSTANT_Methodref_info(current_frame->current_class_file, index);
	
	ClassFile* target_class_file = methodref->class_file;
	jmethodID mid = methodref->mid;

	// メソッドが定義されているクラスと、method_info を取得する
	method_info* target_method_info = get_method_info(target_class_file, mid);
	ClassFile* declaring_class_file = target_method_info->declaring_ClassFile;
	
	// メソッドを実行する
	jobject static_data = get_static_data(declaring_class_file);
	invoke_method(current_frame, static_data, declaring_class_file, target_method_info);

	CHECK_EXCEPTION;
	bytecode += 3;
}


/**
 * invokeinterface命令を実行する
 */
EXECUTOR ( INVOKEINTERFACE )
{
	u2 index = MAKE_U2(bytecode[1], bytecode[2]);

	// InterfaceMethodref情報を取得する
	// constant_pool[index]の下位16ビットに class_index が、上位16ビットに name_and_type_indexが格納されている
	u4 interface_methodref = (u4) current_frame->current_class_file->constant_pool[index];
	
	// NameAndType情報を取得する
	// constant_pool[name_and_type_index] の下位ビットに name_index が、
	// 上位16ビットに type_index が格納されている
	u4 name_and_type = (u4) current_frame->current_class_file->constant_pool[(u2) (interface_methodref >> 16)];
	java_utf8* target_method_name = get_java_utf8(current_frame->current_class_file, (u2) name_and_type);
	java_utf8* target_method_desc = get_java_utf8(current_frame->current_class_file, (u2) (name_and_type >> 16));
	
	// オペランドスタックからオブジェクト参照を取得する
	u1 count = GET_PARAMETER(bytecode, 3);
	jobject objectref = (jobject) current_frame->operand_stack[current_frame->operand_stack_position - (count & 0xff)];
	if (objectref == NULL) {
		throw_exception(current_frame, "java/lang/NullPointerException");
		CHECK_EXCEPTION;
	}
	
	// メソッドIDを取得する
	ClassFile* object_class_file = get_ClassFile(objectref);
	jmethodID mid = get_method_id(object_class_file,
								  target_method_name,
								  target_method_desc);
	if (mid == NULL) {
		// メソッドが解決できない
		throw_exception(current_frame, "java/lang/NoSuchMethodError", target_method_name);
		CHECK_EXCEPTION;
	}

	// 呼び出し対象となるメソッドの情報を取得する
	method_info* target_method_info = get_method_info(object_class_file, mid);
	ClassFile* declaring_class_file = target_method_info->declaring_ClassFile;

	// ロード制約を追加する
	if (! add_loading_constraints_of_method(current_frame,
											target_method_info->declaring_ClassFile,
											target_method_desc)) {
		// 制約の追加に失敗
		CHECK_EXCEPTION;
	}

	// メソッド本体を実行する
	invoke_method(current_frame, objectref, declaring_class_file, target_method_info);
	CHECK_EXCEPTION;
	bytecode += 5;
}

/**
 * new命令を処理する
 */
EXECUTOR ( NEW )
{
	u2 index = MAKE_U2(bytecode[1], bytecode[2]);
	ClassFile* cfile = current_frame->current_class_file;
	
	// newの対象となるClassFile構造体へのポインタを得る
	ClassFile* target_class_file
			= resolve_ClassFile(current_frame,
							    cfile,
								index);
	CHECK_EXCEPTION;

	if (is_abstract(target_class_file->access_flags)) {
		// abstractクラスをnewしようとしている
		throw_exception(current_frame, "java/lang/InstantiationError");
		CHECK_EXCEPTION;
	}

	// NEW_QUICKに書き換える
	REWRITE_BYTECODE(NEW_QUICK);
	continue;
}

/**
 * new_quick命令を処理する（内部命令）
 */
EXECUTOR ( NEW_QUICK )
{
	u2 index = MAKE_U2(bytecode[1], bytecode[2]);
	ClassFile* target_class_file = get_resolved_ClassFile(current_frame->current_class_file,
														  index);

	// メモリを確保し、参照をオペランドスタックにpushする
	alloc_object(target_class_file, current_frame);
	CHECK_EXCEPTION;

	if (bytecode[3] == DUP) {
		// new 命令の直後にはdup命令がくることが多いので、
		// ここでまとめて処理してしまう
		DUP_STACK(current_frame);
		bytecode += 4;
	} else {
		bytecode += 3;
	}
}


/**
 * newarray命令を処理する
 */
EXECUTOR ( NEWARRAY )
{
//	execute_newarray(current_frame, bytecode);
	// 生成する配列のタイプを取得する
	u1 atype = bytecode[1];
	
	// 配列サイズをpopする
	__int32 count;
	POP_INT(current_frame, count);
	if (count < 0) {
		throw_exception(current_frame,
						"java/lang/NegativeArraySizeException");
		CHECK_EXCEPTION;
	}

	const java_utf8* name = PRIMITIVE_ARRAY_CLASS_NAMES[atype];
	class_loader* loader = get_defining_loader(current_frame->current_class_file);
	ClassFile* cfile = find_ClassFile(current_frame, loader, name);
	if (! cfile) {
		// 初期化失敗
		CHECK_EXCEPTION;
	}
	if (alloc_array(cfile, count, current_frame) == NULL) {
		CHECK_EXCEPTION;
	}
	CHECK_EXCEPTION;
	bytecode += 2;
}

/**
 * anewarray命令を処理する
 */
EXECUTOR ( ANEWARRAY )
{
	u2 index = MAKE_U2(bytecode[1], bytecode[2]);

	// 配列の要素数をスタックからpopする
	__int32 count;
	POP_INT(current_frame, count);
	if (count < 0) {
		// 要素数が負の値
		throw_exception(current_frame, "java/lang/NegativeArraySizeException");
		CHECK_EXCEPTION;
	}

	// 配列クラスをロードする
	const java_utf8* name
			= get_CONSTANT_Class_info(current_frame->current_class_file, index);
	u4 name_len = strlen(name);
	char* array_name = (char*) malloc(name_len + 2 + 1 + 1);
	if (! array_name) {
		fatal_error(FATAL_ERROR_NO_MEMORY);
	}

	if (name_len >= 2 && name[0] == '[') {
		// 要素が配列クラスの場合（例 [I [Ljava/lang/String; )
		array_name[0] = '[';
		strcpy(&array_name[1], name);
	} else {
		// 要素がクラスの場合
		// "[L" + クラス名 + ";"
		array_name[0] = '[';
		array_name[1] = 'L';
		strcpy(&array_name[2], name);
		strcat(array_name, ";");
	}

	class_loader* loader = get_defining_loader(current_frame->current_class_file);
	ClassFile* cfile = find_ClassFile(current_frame, loader, intern_utf8(array_name));
	free(array_name);
	if (! cfile) {
		// 初期化失敗
		CHECK_EXCEPTION;
	}
	
	alloc_array(cfile, count, current_frame);
	CHECK_EXCEPTION;
	bytecode += 3;
}

/**
 * arraylength命令を実行する
 */
EXECUTOR ( ARRAYLENGTH )
{
	jobject arrayref;
	POP_OBJECT(current_frame, arrayref);
	if (arrayref == NULL) {
		// 配列の参照が null
		throw_exception(current_frame, "java/lang/NullPointerException");
		CHECK_EXCEPTION;
	}
	__int32 length = get_array_length((jarray) arrayref);
	FAST_PUSH_INT(stack_base, pposition, length);
	bytecode++;
}

/**
 * athrow命令を実行する
 */
EXECUTOR ( ATHROW )
{
	jobject ref;
	POP_OBJECT(current_frame, ref);
	if (ref == NULL) {
		throw_exception(current_frame, "java/lang/NullPointerException");
		CHECK_EXCEPTION;
	}
	current_frame->current_exception = (jthrowable) ref;
	CHECK_EXCEPTION;
}

/**
 * checkcast命令を実行する
 */
EXECUTOR ( CHECKCAST )
{
	u2 index = MAKE_U2(bytecode[1], bytecode[2]);

	const java_utf8* class_name = get_CONSTANT_Class_info(current_frame->current_class_file, index);
	// スタックトップのオブジェクトを取得する（popはしない）
	jobject ref;
	get_stack_data(current_frame, 0, (__int32*)&ref);

	if (ref) {
		// キャッシュの内容を調べる
		int result = get_instanceof_cache(current_frame, get_ClassFile(ref), class_name);

#if CHECKCAST_STATISTICS
		// instanceof命令キャッシュにヒットしたかを調べる
		g_checkcast_count++;
		if (result != -1) {
			g_checkcast_hits++;
		}
#endif
		// キャッシュにヒットしなかった場合、チェックを行う
		ClassFile* target_cfile
			= resolve_ClassFile(current_frame,
							    current_frame->current_class_file,
							    index);
		if (target_cfile) {
			if (! result || (result < 0) && (! is_assignable_from(current_frame, get_ClassFile(ref), target_cfile))) {
				// 代入不可能の場合にはClassCastExceptionを発生させる
				throw_exception(current_frame, "java/lang/ClassCastException", get_ClassFile(ref)->this_class_name);
				CHECK_EXCEPTION;
			}
		}
	}
	bytecode += 3;
}

/**
 * instanceof命令を実行する
 */
EXECUTOR ( INSTANCEOF )
{
	u2 index = MAKE_U2(bytecode[1], bytecode[2]);
	
	// クラスをロードする
	ClassFile* target_cfile = resolve_ClassFile(current_frame,
											    current_frame->current_class_file,
												index);
	CHECK_EXCEPTION;

	// 命令を書き換える
	REWRITE_BYTECODE( INSTANCEOF_QUICK );
	continue;
}

/**
 * instanceof_quick命令を実行する（内部命令）
 */
EXECUTOR ( INSTANCEOF_QUICK )
{
	u2 index = MAKE_U2(bytecode[1], bytecode[2]);
	ClassFile* target_cfile = get_resolved_ClassFile(current_frame->current_class_file,
													 index);
	int result;

	// 参照値を取り出す（処理中にガベージコレクタに回収されてしまわないよう、popはしない）
	jobject ref;
	get_stack_data(current_frame, 0, (__int32*)&ref);
	if (ref) {
		ClassFile* lvalue = get_ClassFile(ref);
		java_utf8* class_name = target_cfile->this_class_name;
		// キャッシュの内容を調べる
		result = get_instanceof_cache(current_frame,
									  lvalue,
									  class_name);
		if (result < 0) {
			if (is_assignable_from(current_frame, lvalue, target_cfile)) {
				result = 1;
			} else {
				result = 0;
			}
			// キャッシュに結果を入れる
			update_instanceof_cache(current_frame,
									lvalue,
									class_name,
									result);
		}
	} else {
		result = 0;
	}

	POP_DISCARD(current_frame);
	PUSH_INT(current_frame, result);

	bytecode += 3;
}

/**
 * monitorenter命令を実行する
 */
EXECUTOR ( MONITORENTER )
{
	jobject ref;
	// get_stack_data(current_frame, 0, (__int32*) &ref);
	FAST_PEEK_STACK_DATA(stack_base, pposition, 0, jobject, ref);
	if (ref == NULL) {
		POP_DISCARD(current_frame);
		throw_exception(current_frame, "java/lang/NullPointerException");
		CHECK_EXCEPTION;
	}
	if (! monitor_enter(ref)) {
		POP_DISCARD(current_frame);
		throw_OutOfMemoryError(current_frame);
		CHECK_EXCEPTION;
	}

	POP_DISCARD(current_frame);
	bytecode++;
}

/**
 * monitorexit命令を実行する
 */
EXECUTOR ( MONITOREXIT )
{
	jobject ref;
	// get_stack_data(current_frame, 0, (__int32*) &ref);
	FAST_PEEK_STACK_DATA(stack_base, pposition, 0, jobject, ref);
	if (ref == NULL) {
		POP_DISCARD(current_frame);
		throw_exception(current_frame, "java/lang/NullPointerException");
		CHECK_EXCEPTION;
	}
	if (! monitor_exit(ref)) {
		POP_DISCARD(current_frame);
		throw_exception(current_frame, "java/lang/IllegalMonitorStateException");
		CHECK_EXCEPTION;
	}
	POP_DISCARD(current_frame);
	bytecode++;
}


/**
 * wide命令を実行する
 */
EXECUTOR ( WIDE )
{
	execute_wide(current_frame, bytecode);
	CHECK_EXCEPTION;
}

/**
 * multianewarray命令を処理する
 */
EXECUTOR ( MULTIANEWARRAY )
{
	execute_multianewarray(current_frame, bytecode);
	CHECK_EXCEPTION;
	bytecode += 4;
}

/**
 * ifnull命令を実行する
 */
EXECUTOR( IFNULL )
{
	jobject value;
	POP_OBJECT(current_frame, value);
	SET_JUMP_ADDRESS(current_frame, (value == NULL), bytecode[1], bytecode[2], 3);
}

/**
 * ifnonnull命令を実行する
 */
EXECUTOR( IFNONNULL )
{
	jobject value;
	POP_OBJECT(current_frame, value);
	SET_JUMP_ADDRESS(current_frame, (value != NULL), bytecode[1], bytecode[2], 3);
}

/**
 * goto_w命令を実行する
 */
EXECUTOR( GOTO_W )
{
	// Thread.interrupt()された場合に対応するために、例外発生をチェックする
	CHECK_EXCEPTION;
	bytecode += MAKE_INT32(GET_PARAMETER(bytecode, 1),
									GET_PARAMETER(bytecode, 2),
									GET_PARAMETER(bytecode, 3),
									GET_PARAMETER(bytecode, 4));
}

/**
 * jsr_w命令を実行する
 */
EXECUTOR( JSR_W )
{
	__int32* pbranch = (__int32*) &bytecode[1];
	__int32 branch = READ_BIG_ENDIAN(*pbranch);

	// jsr命令を実行
	execute_jsr(current_frame, branch);
	CHECK_EXCEPTION;
}
