/* instruction_inc.h
   Copyright (C) 2005-2008 freebeans <freebeans@xqb.biglobe.ne.jp>.

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.

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("java/lang/NullPointerException", NULL); \
	} \
	if (index < 0 || index >= get_array_length((jarray) ref)) { \
	    STORE_CONTEXT(); \
		throw_exception_int(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("java/lang/NullPointerException", NULL); \
	} \
	if (index < 0 || index >= get_array_length((jarray) ref)) { \
	    STORE_CONTEXT(); \
		throw_exception_int(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("java/lang/NullPointerException", NULL);
	}

	// 配列境界チェック
	if (idx < 0 || idx >= get_array_length((jarray) aref)) {
	    STORE_CONTEXT();
		throw_exception_int(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_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("java/lang/NullPointerException", NULL);
	}
	
	// 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("java/lang/ArrayStoreException", NULL);
	}

	// 配列境界チェック
	if (index < 0 || index >= get_array_length((jarray) ref)) {
	    STORE_CONTEXT(); \
		throw_exception_int(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("java/lang/ArithmeticException", "/ by zero");
	}

	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("java/lang/ArithmeticException", "/ by zero");
	}
	__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("java/lang/ArithmeticException", "% by zero");
	}

	__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("java/lang/ArithmeticException", "% by zero");
	}

	__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 )
{
	STORE_CONTEXT();

	__int16 offset = MAKE_INT16(bytecode[1], bytecode[2]);
	execute_jsr(current_frame, (__int32) offset);
	
	CHECK_EXCEPTION;
	bytecode = code + current_frame->current_pc;
}

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

/**
 * tableswitch命令を実行する
 */
EXECUTOR ( TABLESWITCH )
{
	// プリロードする
	// _PreLoad((unsigned long*) bytecode);

	// ４バイト境界からデータを読み込む
	unsigned int padding = (unsigned int) (bytecode + 1) % 4;
	if (padding != 0) {
		padding = 4 - padding;
	}
	const unsigned int startpos = padding + 1;
	const __int32* data = (__int32*) &bytecode[startpos];

	const __int32 defaultoffset = READ_BIG_ENDIAN(data[0]);
	const __int32 lowvalue      = READ_BIG_ENDIAN(data[1]);
	const __int32 highvalue     = READ_BIG_ENDIAN(data[2]);
	const __int32* jump_table   = &data[3];

	__int32 index;
	POP_INT(current_frame, index);
	if (index < lowvalue || index > highvalue) {
		bytecode += defaultoffset;
	} else {
		__int32 offset = jump_table[index - lowvalue];
		offset = READ_BIG_ENDIAN(offset);
		bytecode += offset;
	}
}

/**
 * lookupswitch命令を実行する
 */
EXECUTOR ( LOOKUPSWITCH )
{
	// ４バイト境界からデータを読み込む
	unsigned int padding = (unsigned int) (bytecode + 1) % 4;
	if (padding != 0) {
		padding = 4 - padding;
	}
	const unsigned int startpos = padding + 1;
	const __int32* data = (__int32*) &bytecode[startpos];
	
	const __int32 defaultoffset = READ_BIG_ENDIAN(data[0]);
	const __int32 npairs = READ_BIG_ENDIAN(data[1]);
	const __int32* match_offset = (__int32*) &data[2];
	
	__int32 key;
	POP_INT(current_frame, key);

	// キーに一致する値を検索する
	// ToDo:npairsが大きな場合は二分探索処理を行う
	bool found = false;
	for (int i = 0; i < npairs; ++i) {
		__int32 match = READ_BIG_ENDIAN(match_offset[i * 2]);
		if (key == match) {
			__int32 offset = READ_BIG_ENDIAN(match_offset[i * 2 + 1]);
			bytecode += offset;
			found = true;
			break;
		}
	}
	// match-offsetに一致しなかった場合
	if (! found) {
		bytecode += defaultoffset;
	}
}

/**
 * ireturn命令を実行する
 */
EXECUTOR       ( IRETURN )
EXECUTOR_ALIAS ( LRETURN )
EXECUTOR_ALIAS ( FRETURN )
EXECUTOR_ALIAS ( DRETURN )
EXECUTOR_ALIAS ( ARETURN )
EXECUTOR_ALIAS (  RETURN )
{
#if 0
#ifdef DEBUG
	// RETURN命令だけのJavaメソッドを呼び出した場合、そのことをデバッグ出力する
	if (bytecode == code && *bytecode == RETURN) {
		DBG(_T("Empty Java method called."));
		DBG_UTF8(current_frame->current_class_file->this_class_name);
		DBG(_T("."));
		DBG_UTF8(current_frame->current_method_info->name);
		DBG_UTF8(current_frame->current_method_info->descriptor);
		DBG(_T("\n"));
	}
#endif
#endif

	if (current_frame == start_frame) {
		goto END;	// リターンする
	} else {
		frame* prev = leave_method(current_frame);
		current_frame = prev;
		LOAD_CONTEXT();
		if (*bytecode == INVOKEINTERFACE) {
			// invokeinterface命令は5バイト
			bytecode += 5;
		} else {
			bytecode += 3;
		}
		continue;
	}
}

/**
 * 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 )
{
	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("java/lang/NoSuchFieldError", fieldref->field_name);
		}
		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("java/lang/IllegalAccessError", finfo->name);
	}

	// フィールドのオフセットをキャッシュしておく
	// 無効な値と区別するために、最上位ビットを立てておく
	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("java/lang/NoSuchFieldError", fieldref->field_name);
		}
		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("java/lang/IllegalAccessError", finfo->name);
	}
	// フィールドのポジションをキャッシュしておく
	// 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);

	// 対象クラスを解決する
	class_loader* loader = get_defining_loader(current_frame->current_class_file);
	ClassFile* target_class_file = find_ClassFile(current_frame, loader, methodref->class_name);
	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("java/lang/IllegalAccessError", target_class_file->this_class_name);
	}

	// 呼び出し対象となるメソッドを解決する
	// 検索は、メソッドテーブルに対してのみ行う
	int method_table_index = methodref->method_table_index;
	if (method_table_index == -1) {
		method_table_index = get_method_table_index(target_class_file,
													methodref->method_name,
													methodref->method_descriptor);
		if (method_table_index == -1) {
		    STORE_CONTEXT(); \
			throw_exception(current_frame,
							"java/lang/NoSuchMethodError",
							methodref->method_name);
			CHECK_EXCEPTION;
		}
	}
	method_info* target_method_info = get_method_info_by_table_index(target_class_file, method_table_index);
	assert(target_method_info->name == methodref->method_name && target_method_info->descriptor == methodref->method_descriptor);

	// メソッドにアクセスできるかを調べる
	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("java/lang/IllegalAccessError", target_method_info->name);
		}
	}

	// staticメソッドの場合はエラー
	if (is_static(target_method_info->access_flags)) {
		THROW("java/lang/IncompatibleClassChangeError", target_method_info->name);
	}

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

	if (is_final(target_class_file->access_flags) || is_final(target_method_info->access_flags)) {
		// オーバーライドされることはないので、INVOKENONVIRTUAL_QUICK命令に書き換える
		methodref->target_method_info_cache = target_method_info;
		REWRITE_BYTECODE( INVOKENONVIRTUAL_QUICK );
	} else {
		// インデックス値をキャッシュした後、INVOKEVIRTUAL_QUICK命令に書き換える
		methodref->method_table_index = method_table_index;
		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);

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

	if (! objectref) {
	    THROW("java/lang/NullPointerException", NULL);
	}
	ClassFile* object_class_file = get_ClassFile(objectref);

	// 呼び出し対象となるClassFileとmethod_infoを取得する
	// (スタック上のオブジェクトから取得する必要がある）
	method_info* target_method_info = get_method_info_by_table_index(object_class_file,
																	 methodref->method_table_index);

	assert(methodref->method_table_index != -1 && ! is_interface(object_class_file->access_flags));
	assert(target_method_info->name == methodref->method_name && target_method_info->descriptor == methodref->method_descriptor);
	ClassFile* declaring_class_file = target_method_info->declaring_ClassFile;

	// abstractメソッドの場合は例外をthrow
	if (is_abstract(target_method_info->access_flags)) {
		THROW("java/lang/AbstractMethodError", target_method_info->name);
	}

	// メソッド本体を実行する
	INVOKE_METHOD(objectref, declaring_class_file, target_method_info);
	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);

	// 呼び出し対象となるクラスを解決する
	class_loader* loader = get_defining_loader(current_frame->current_class_file);
	ClassFile* target_class_file = find_ClassFile(current_frame, loader, methodref->class_name);
	if (! target_class_file) {
		// ロード失敗
		CHECK_EXCEPTION;
	}
	const java_utf8* target_method_name = methodref->method_name;
	const java_utf8* target_method_desc = methodref->method_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))) {
			// "super.method()"呼び出し
			super_method = true;
			target_class_file = get_superclass_ClassFile(current_frame->current_class_file);

		} else {
			// non-virtual呼び出し(privateメソッド)
			super_method = false;
		}
	} else {
		// <init>メソッドの呼び出し
		super_method = false;
	}

	// 呼び出し対象メソッドの method_info を得る
	// 検索の基準となるクラスはオペランドスタック上のオブジェクトではなく、
	// CONSTANT_Methodref_infoで指定されたクラス（またはそのスーパークラス）を使用する点に注意
	method_info* target_method_info;
	int method_table_index = get_method_table_index(target_class_file,
													target_method_name,
													target_method_desc);
	if (method_table_index != -1) {
		target_method_info = get_method_info_by_table_index(target_class_file, method_table_index);
	} else {
		// メソッドテーブルにない場合は、直接宣言しているメソッドから検索する
		target_method_info = get_declared_method_info(target_class_file, target_method_name, target_method_desc);
	}
	if (! target_method_info) {
		// 見つからなかった場合、AbstractMethodErrorを設定し、リターンする
		THROW("java/lang/AbstractMethodError", target_method_name);
	}
	assert((target_method_info->name == target_method_name) && (target_method_info->descriptor == target_method_desc));
	
	// abstractメソッドだった場合、例外をthrow
	if (is_abstract(target_method_info->access_flags)) {
		THROW("java/lang/AbstractMethodError", target_method_name);
	}
	// staticメソッドだった場合、IncompatibleClassChangeError を投げる
	if (is_static(target_method_info->access_flags)) {
		THROW("java/lang/IncompatibleClassChangeError", target_method_name);
	}

	// ロード制約を追加する
	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;
	}

	// アクセス権限を調べる
	if (! is_accessible(current_frame,
						current_frame->current_class_file,
						target_class_file,
						target_method_info->access_flags)) {
		THROW("java/lang/IllegalAccessError", target_method_info->name);
	}
	
	// キャッシュする
	methodref->target_method_info_cache = target_method_info;


	// 命令を書き換える
	if ((target_method_info->access_flags & ACC_EMPTY)) {
		// 空メソッド
		REWRITE_BYTECODE( INVOKEEMPTY_QUICK );
	} else if (super_method) {
		// super.method()
		REWRITE_BYTECODE( INVOKESUPER_QUICK );
	} else {
		// non-virtual呼び出し
		REWRITE_BYTECODE( INVOKENONVIRTUAL_QUICK );
	}
	continue;
}

/**
 * 空メソッド呼び出し（内部命令）
 */
EXECUTOR ( INVOKEEMPTY_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);

	method_info* target_method_info   = methodref->target_method_info_cache;

	// スタックからパラメータ数+1分POPする
	// staticメソッドではないため、常にthisが積まれているはず
	POP_DISCARD_N(current_frame, get_parameters_count(target_method_info) + 1);
	bytecode += 3;
}

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

	method_info* target_method_info   = methodref->target_method_info_cache;
	assert(target_method_info);

	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("java/lang/NullPointerException", NULL);
	}

	// メソッドを実行する
	INVOKE_METHOD(objectref, declaring_class_file, target_method_info);
	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);
	method_info* target_method_info   = methodref->target_method_info_cache;
	assert(target_method_info);

	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("java/lang/NullPointerException", NULL);
	}

	// メソッドを実行する
	INVOKE_METHOD(objectref, declaring_class_file, target_method_info);
	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);
	
	class_loader* loader = get_defining_loader(current_frame->current_class_file);
	ClassFile* target_class_file = find_ClassFile(current_frame, loader, methodref->class_name);
	if (target_class_file == NULL) {
		if (! exception_occurred(current_frame)) {
			// 例外が発生していない場合は、NoClassDefFoundErrorをthrowする
		    THROW("java/lang/NoClassDefFoundError", methodref->class_name);
		}
		CHECK_EXCEPTION;
	}

	// 呼び出し対象となるメソッドを取得する
	method_info* target_method_info = methodref->target_method_info_cache;
	if (! target_method_info) {
		// 最初に、メソッドテーブルから探す
		int table_index = get_method_table_index(target_class_file, methodref->method_name, methodref->method_descriptor);
		if (table_index != -1) {
			target_method_info = get_method_info_by_table_index(target_class_file, table_index);
		} else {
			// メソッドテーブルで見つからなかった場合は、宣言されているメソッドを探す
			// （private static メソッドの場合は、ここで見つかる）
			target_method_info = get_declared_method_info(target_class_file, methodref->method_name, methodref->method_descriptor);
		}
		if (! target_method_info) {
		    THROW("java/lang/NoSuchMethodError", methodref->method_name);
		} else if (! is_static(target_method_info->access_flags)) {
			// staticメソッドでない場合
			THROW("java/lang/IncompatibleClassChangeError", methodref->method_name);
		}
		
		methodref->target_method_info_cache = target_method_info;
	}

	// メソッドが定義されているクラスと、method_info を取得する
	ClassFile* declaring_class_file = target_method_info->declaring_ClassFile;

	// abstractメソッドだった場合、例外をthrow
	if (is_abstract(target_method_info->access_flags)) {
		THROW("java/lang/AbstractMethodError", target_method_info->name);
	}
	// staticメソッドでない場合、例外をthrow
	if (! is_static(target_method_info->access_flags)) {
		THROW("java/lang/IncompatibleClassChangeError", target_method_info->name);
	}
	// メソッドが定義されているクラスがインタフェースの場合、例外をthrowする
	if (is_interface(declaring_class_file->access_flags)) {
		THROW("java/lang/IncompatibleClassChangeError", target_method_info->name);
	}
	
	// アクセス権限を調べる
	if (! is_accessible(current_frame,
						current_frame->current_class_file,
						target_class_file,
						target_method_info->access_flags)) {
		THROW("java/lang/IllegalAccessError", target_method_info->name);
	}

	// ロード制約を追加する
	if (! add_loading_constraints_of_method(current_frame,
											declaring_class_file,
											target_method_info->descriptor)) {
		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);
	
	// method_info を取得する
	method_info* target_method_info = methodref->target_method_info_cache;
	assert(target_method_info);

	ClassFile* declaring_class_file = target_method_info->declaring_ClassFile;

	assert((target_method_info->name == methodref->method_name)
			&& (target_method_info->descriptor == methodref->method_descriptor));
	
	// メソッドを実行する
	jobject static_data = get_static_data(declaring_class_file);

	INVOKE_METHOD(static_data, declaring_class_file, target_method_info);

	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("java/lang/NullPointerException", NULL);
	}
	
	// 呼び出し対象となるメソッドの情報を取得する
	ClassFile* object_class_file = get_ClassFile(objectref);
	method_info* target_method_info;
	int method_table_index = get_method_table_index(object_class_file,
													target_method_name,
													target_method_desc);
	if (method_table_index != -1) {
		target_method_info = get_method_info_by_table_index(object_class_file, method_table_index);
	} else {
		// 直接宣言しているメソッドを検索する
		// （ここに来たら場合はprivateメソッドのはずなので、エラーにしてもよい？）
		target_method_info = get_declared_method_info(object_class_file,
													  target_method_name,
													  target_method_desc);
	}
	if (! target_method_info) {
		// メソッドが解決できない
	    THROW("java/lang/AbstractMethodError", target_method_name);
	}
	ClassFile* declaring_class_file = target_method_info->declaring_ClassFile;

	// abstractメソッドだった場合、例外をthrow
	if (is_abstract(target_method_info->access_flags)) {
		THROW("java/lang/AbstractMethodError", target_method_info->name);
	}
	// メソッドがpublicでなければエラー
	if (! is_public(target_method_info->access_flags)) {
		THROW("java/lang/IllegalAccessError", target_method_info->name);
	}

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

	// メソッド本体を実行する
	INVOKE_METHOD(objectref, declaring_class_file, target_method_info);

	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("java/lang/InstantiationError", target_class_file->this_class_name);
	}

	// 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) {
	    STORE_CONTEXT();
		throw_exception_int(current_frame,
						"java/lang/NegativeArraySizeException",
						count);
		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) {
		// 要素数が負の値
	    STORE_CONTEXT();
		throw_exception_int(current_frame, "java/lang/NegativeArraySizeException", count);
		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; )
		sprintf(array_name, "[%s", name);
	} else {
		// 要素がクラスの場合
		// "[L" + クラス名 + ";"
		sprintf(array_name, "[L%s;", 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("java/lang/NullPointerException", NULL);
	}
	__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("java/lang/NullPointerException", NULL);
	}
	// コンテキストを保存した後、指定された例外を設定し、例外の発生をチェックする
	STORE_CONTEXT();
	current_frame->body->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("java/lang/ClassCastException", get_ClassFile(ref)->this_class_name);
			}
		}
	}
	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("java/lang/NullPointerException", NULL);
	}
	if (! monitor_enter(ref)) {
		POP_DISCARD(current_frame);
		// メモリ不足が原因で発生する
		STORE_CONTEXT();
		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("java/lang/NullPointerException", NULL);
	}
	if (! monitor_exit(ref)) {
		POP_DISCARD(current_frame);
	    THROW("java/lang/IllegalMonitorStateException", NULL);
	}
	POP_DISCARD(current_frame);
	bytecode++;
}


/**
 * wide命令を実行する
 */
EXECUTOR ( WIDE )
{
	// この部分はあまりデバッグできていないのでassert()を仕掛けておく
	// assert(false);

	u1 opcode = GET_PARAMETER(bytecode, 1);
	u1 indexbyte1 = GET_PARAMETER(bytecode, 2);
	u1 indexbyte2 = GET_PARAMETER(bytecode, 3);
	u2 index = MAKE_U2(indexbyte1, indexbyte2);

	switch (opcode) {
	case ILOAD:	// iload
		LOAD(current_frame, index);
		bytecode += 4;
		break;

	case LLOAD:	// lload
		LOAD2(current_frame, index);
		bytecode += 4;
		break;

	case FLOAD:	// fload
		LOAD(current_frame, index);
		bytecode += 4;
		break;

	case DLOAD:	// dload
		LOAD2(current_frame, index);
		bytecode += 4;
		break;

	case ALOAD:	// aload
		LOAD(current_frame, index);
		bytecode += 4;
		break;

	case ISTORE:	// istore
		STORE(current_frame, index);
		bytecode += 4;
		break;

	case LSTORE:	// lstore
		STORE2(current_frame, index);
		bytecode += 4;
		break;

	case FSTORE:	// fstore
		STORE(current_frame, index);
		bytecode += 4;
		break;

	case DSTORE:	// dstore
		STORE2(current_frame, index);
		bytecode += 4;
		break;

	case ASTORE:	// astore
		STORE(current_frame, index);
		bytecode += 4;
		break;

	case IINC:	// iinc
		{
			u1 constbyte1 = GET_PARAMETER(bytecode, 4);
			u1 constbyte2 = GET_PARAMETER(bytecode, 5);
			__int16 count = MAKE_INT16(constbyte1, constbyte2);
			IINC_LOCAL(current_frame, index, count);
			bytecode += 6;
		}
		break;
	
	case RET:	// ret
		{
			__int32 address = get_int(current_frame, index);
			// jsr命令で最上位ビットが立てられているため、最上位ビットをクリアする
			bytecode = (code + (address & ~0x80000000));
		}
		break;

	default:
		THROW("java/lang/VirtualMachineError", "Unknown WIDE  opcode");
		break;

	}
}

/**
 * multianewarray命令を処理する
 */
EXECUTOR ( MULTIANEWARRAY )
{
	STORE_CONTEXT();
	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;
}
