/* frame.cpp
   Copyright (C) 2005 Free Software Foundation, Inc.

This file is part of Mysaifu JVM

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

Mysaifu JVM is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

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

#include "StdAfx.h"
#include "frame.h"
#include "java_thread.h"
#include "common_funcs.h"
#include "instruction.h"

/**
 * ルートフレーム数
 */
#define	MAX_ROOT_FRAMES_COUNT	128

/**
 * スタック内の予約領域数
 */
#define STACK_RESERVED_SIZE	128

/**
 * フレームの要素数
 */
static unsigned int g_total_count;

/**
 * グローバル参照の最大数
 */
static const unsigned int g_global_references_count = 8192;


/**
 * ルートフレームの配列
 * 現在の実装では固定長配列にしている（可変長にすると性能に影響が出ることがわかっため）
 * ToDo:性能を維持したまま可変長にする
 */
static frame* g_root_frames[MAX_ROOT_FRAMES_COUNT];

/**
 * グローバル参照格納用フレーム（ネイティブ・メソッドが使用する）
 */
static frame* g_global_references_frame;

/**
 * フレームの本体。
 * 1スレッドにつき１つ作成する。
 */
struct frame_body {
	/**
	 * フレーム内の要素数（32ビット単位）
	 */
	unsigned int count;

	/**
	 * フレーム内のリミット
	 */
	unsigned int limit_count;

	/**
	 * フレームのデータ本体
	 */
	__int32* data;

	/**
	 * 参照値が入る領域
	 */
	__int32* references;

	/**
	 * カレントフレーム
	 */
	frame* current_frame;
	
	/**
	 * 直前に実行したinstanceof演算子の左辺
	 */
	ClassFile* instanceof_lvalue;

	/**
	 * 直前に実行されたinstanceof演算子の右辺
	 */
	const java_utf8* instanceof_rvalue;
	
	/**
	 * 直前に実行されたinstanceof演算子の結果
	 */
	int instanceof_result;

	/**
	 * カレントスレッド
	 */
	jobject current_thread;

	/**
	 * JNIEnv
	 */
	JNIEnv* env;

	/**
	 * ローカル参照
	 */
	frame* local_references_frame;
};


// static関数宣言
static inline bool check_stack_overflow(frame* frm, int max_stack);

/**
 * フレーム関連変数を初期化する
 */
void init_frame_settings(unsigned int java_stack_size) {
	g_global_references_frame = alloc_root_frame(NULL, g_global_references_count);
	g_total_count= (java_stack_size / 4) + STACK_RESERVED_SIZE;
}

/**
 * フレーム本体領域を確保する。
 * 新しいスレッドを作成する際に、この関数を呼び出してフレームを作成する
 */
static frame_body* alloc_frame_body(unsigned int total_count) {

	// malloc()の呼び出し回数を削減する
	frame_body* body = (frame_body*) calloc(sizeof(frame_body)
											+ sizeof(frame)
											+ sizeof(__int32) * total_count
											+ sizeof(__int32) * total_count, 1);
	if (body == NULL) {
		fatal_error(FATAL_ERROR_NO_MEMORY);
	}
	body->count = total_count;
	body->limit_count = total_count - STACK_RESERVED_SIZE;
	body->current_frame = (frame*) (body + 1);
	body->data = (__int32*) (body->current_frame + 1);
	body->references = (__int32*) (body->data + total_count);
	
	return body;
}

/**
 * フレーム本体領域を解放する
 * スレッドが終了した後、この関数を呼び出してメモリを開放する
 */
static void free_frame_body(frame_body* body) {
	if (body->env) {
		free(body->env);
	}
	if (body->local_references_frame) {
		// ローカル参照を削除する
		free_root_frame(body->local_references_frame);
	}
	free(body);
}

/**
 * 一番先頭（底）のフレームを確保する
 * スレッドの最初のメソッドを呼び出す前に、この関数を使用して最初のフレームを
 * 作成する
 */
frame* alloc_root_frame(ClassFile* current_class_file) {
	return alloc_root_frame(current_class_file, g_total_count);
}

/**
 * 「ルート」フレームを作成する。
 */
frame* alloc_root_frame(ClassFile* current_class_file, unsigned int max_count) {
	EnterCriticalSection(&g_global_critical_section);
	bool result = false;

	frame_body* body = alloc_frame_body(max_count); 
	frame* new_frame = body->current_frame;
	new_frame->body = body;
	new_frame->current_class_file = current_class_file;
	new_frame->current_method_info = NULL;
	new_frame->current_exception = NULL;
	new_frame->local_variables = body->data;
	new_frame->local_variables_references = body->references;
	new_frame->operand_stack = body->data;
	new_frame->operand_stack_position = 0;
	new_frame->operand_stack_references = body->references;
	new_frame->current_bytecode_pointer = NULL;
	new_frame->previous_frame = NULL;
	
	// ルートフレームの配列を更新する
	bool success = false;
	for (int i = 0; i < MAX_ROOT_FRAMES_COUNT; ++i) {
		if (! g_root_frames[i]) {
			g_root_frames[i] = new_frame;
			success = true;
			break;
		}
	}
	if (! success) {
		fatal_error(_T("Too many root frames"));
	}

	LeaveCriticalSection(&g_global_critical_section);
	return new_frame;
}

/**
 * 一番先頭（底）のフレームを開放する
 * スレッドの終了後、この関数を呼び出してメモリを開放する
 */
void free_root_frame(frame* root_frame) {
	EnterCriticalSection(&g_global_critical_section);
	
	assert(root_frame->previous_frame == NULL);

	// ルートフレームの配列から、指定されたフレームを取り除く
	bool success = false;
	for (int i = 0; i < MAX_ROOT_FRAMES_COUNT; ++i) {
		if (g_root_frames[i] == root_frame) {
			g_root_frames[i] = NULL;
			success = true;
			break;
		}
	}
	assert(success);

	frame_body* body = root_frame->body;
	free_frame_body(body);

	LeaveCriticalSection(&g_global_critical_section);
}

/**
 * JVM上に存在するルートフレームの数を返す
 *
 * @return	ルートフレーム数
 */
unsigned int get_root_frame_count() {
//	return g_root_frame_count;
	return MAX_ROOT_FRAMES_COUNT;
}

/**
 * 指定されたインデックスに対応するルートフレームを返す
 *
 * @param	index	インデックス
 * @return	ルートフレームへのポインタ
 */
frame* get_root_frame(unsigned int index) {
	return	g_root_frames[index];
}

/**
 * 指定されたルートフレームの情報を返す。
 *
 * @param	root_frame	ルートフレーム
 * @param	pdata		フレーム内データへのポインタを返す。
 * @param	prefflags	参照値フラグのポインタを返す。
 * @param	pcount		フレーム内の有効データ数を返す。
 * @param	pcurrent_exception	カレントの例外オブジェクトを返す。
 * @return	正常にデータを取得できた場合true
 */
bool get_root_frame_info(frame* root_frame, __int32** pdata, __int32** preferences, unsigned int* pcount, jobject* pcurrent_exception) {
	frame_body* body = root_frame->body;
	*pdata = body->data;
	*preferences = body->references;
	
	frame* current_frame = body->current_frame;
	__int32* topaddr = current_frame->operand_stack + current_frame->operand_stack_position;
	assert(topaddr >= body->data);
	*pcount = topaddr - body->data;
	*pcurrent_exception = current_frame->current_exception;

	return true;
}

/**
 * 指定されたメソッドを呼び出せるように、フレームの内容を設定する
 */
bool enter_method(frame* caller_frame,
				  frame* new_frame,
				  ClassFile* current_class_file,
				  method_info* target_method_info) {

	memset(new_frame, 0, sizeof(frame));
	new_frame->body = caller_frame->body;
	new_frame->current_class_file = current_class_file;
	new_frame->current_method_info = target_method_info;
	// new_frame->current_exception = NULL;

	// このメソッドの引数を数える
	u2 parameter_count = get_parameters_count(target_method_info);
	// インスタンスメソッドの場合、this があるため、パラメータ数に１つ追加する
	if (! is_static(target_method_info->access_flags)) {
		parameter_count++;
	}

	// ローカル変数の開始アドレスを決める
	// 呼び出し元オペランドスタックの引数が入っている位置に、ローカル変数の
	// 先頭位置を合わせる
	int parameter_offset = caller_frame->operand_stack_position - parameter_count;
	new_frame->local_variables
			= caller_frame->operand_stack + parameter_offset;
	new_frame->local_variables_references
			= caller_frame->operand_stack_references + parameter_offset;

	// 呼び出し元のオペランドスタックポジションを変更する
	// （引数がすべてpopされた状態にする）
	caller_frame->operand_stack_position -= parameter_count;
	new_frame->previous_frame = caller_frame;

	// ローカル変数の数と、スタック領域の最大値を決定する
	u2 max_locals;
	u2 max_stack;
	if (is_native(target_method_info->access_flags)) {
		// ネイティブメソッドの場合
		max_locals = parameter_count;		// ローカル変数はパラメータ数分使用可能とする
		max_stack = 2;						// スタックは戻り値用に2つ使用可能とする
	} else {
		Code_attribute* code_attr = get_Code_attribute(current_class_file, target_method_info);
		max_locals = code_attr->max_locals;
		max_stack = code_attr->max_stack;
	}

	// ローカル変数領域のうち、まだ使用されていない部分の参照フラグをすべてfalseにする
	// （そうしないと、ガベージコレクタがでたらめな値を参照とみなして追跡してしまう）
	memset(new_frame->local_variables_references + parameter_count,
		   0,
		   sizeof(new_frame->local_variables_references[0]) * (max_locals - parameter_count));

	// オペランド・スタックの開始アドレスを決定する
	// ローカル変数領域に max_locals を加算したアドレスを、オペランド・スタックの開始アドレスとする
	new_frame->operand_stack = new_frame->local_variables + max_locals;
	new_frame->operand_stack_references = new_frame->local_variables_references + max_locals;
	// new_frame->operand_stack_position = 0;
	// new_frame->pc = 0;
	
	// スタックがオーバーフローしないか調べる
	if (! check_stack_overflow(new_frame, max_stack)) {
		// スタックオーバーフロー
		if (new_frame->body->limit_count < new_frame->body->count) {
			// まだ拡張可能
			new_frame->body->limit_count = new_frame->body->count;
			// StackOverflowErrorをthrowする
			throw_exception(caller_frame, "java/lang/StackOverflowError");
		} else {
			// もう拡張できない
			// StackTraceElementを持たないStackOverflowErrorを投げる
			throw_StackOverflowError(caller_frame);
		}
		return false;
	}
	
	// カレントフレームを設定する
	new_frame->body->current_frame = new_frame;

	return true;
}

/**
 * メソッド終了後のフレーム処理を行う。
 */
bool leave_method(frame* current_frame) {
	assert(current_frame == current_frame->body->current_frame);

	frame* previous = current_frame->previous_frame;
	if (! current_frame->current_exception) {
		// 例外が発生していない場合、戻り値をpopし、呼び出し元フレームにpushする
		const java_utf8* return_type = get_return_type(current_frame->current_method_info);
		switch (*return_type) {
		case 'V':	// void
			break;

		case 'Z':	// boolean
		case 'B':	// byte
		case 'C':	// char
		case 'S':	// short
		case 'I':	// int
		case 'F':	// float
			{
				// カテゴリ１
				__int32 ret;
				// POP_INT(current_frame, ret);
				get_stack_data(current_frame, 0, &ret);
				PUSH_INT(previous, ret);
				break;
			}
		case 'J':	// long
		case 'D':	// double
			{
				// カテゴリ2
				__int64 ret;
				POP_LONG(current_frame, ret);
				PUSH_LONG(previous, ret);
				break;
			}

		case 'L':	// Lクラス名;
		case '[':	// 配列
			{
				// 参照
				jobject ref;
				get_stack_data(current_frame, 0, (__int32*) &ref);
				PUSH_OBJECT(previous, ref);
				break;
			}
		default:
			// ここにくることはないはず
			assert(false);
		}
	} else {
		// 処理できなかった例外を呼び出し元のフレームにセットする
		previous->current_exception = current_frame->current_exception;
	}

	// 誤ってカレントフレームが継続使用された場合、アクセス違反が起きるようにする
#ifdef DEBUG
	memset(current_frame, 0, sizeof(frame));
#endif

	// カレントフレームを１つ前に戻す
	previous->body->current_frame = previous;
	
	return true;
}

/**
 * オペランド・スタックに対して "dup_x1" 命令を実行する
 */
void dup_x1(frame* stack) {
	unsigned int position = stack->operand_stack_position;
	__int32 value1 = stack->operand_stack[position - 1];
	__int32 ref1 = stack->operand_stack_references[position - 1];
	__int32 value2 = stack->operand_stack[position - 2];
	__int32 ref2 = stack->operand_stack_references[position - 2];
	
	// 値を挿入する
	stack->operand_stack[position - 2] = value1;
	stack->operand_stack_references[position - 2] = ref1;

	stack->operand_stack[position - 1] = value2;
	stack->operand_stack_references[position - 1] = ref2;

	stack->operand_stack[position] = value1;
	stack->operand_stack_references[position] = ref1;
	stack->operand_stack_position++;
}

/**
 * オペランド・スタックに対して "dup_x2" 命令を実行する
 */
void dup_x2(frame* stack) {
	unsigned int position = stack->operand_stack_position;
	__int32 value1 = stack->operand_stack[position - 1];
	__int32 value2 = stack->operand_stack[position - 2];
	__int32 value3 = stack->operand_stack[position - 3];
	__int32 ref1 = stack->operand_stack_references[position - 1];
	__int32 ref2 = stack->operand_stack_references[position - 2];
	__int32 ref3 = stack->operand_stack_references[position - 3];
	
	// 値を挿入する
	stack->operand_stack[position - 3] = value1;
	stack->operand_stack[position - 2] = value3;
	stack->operand_stack[position - 1] = value2;
	stack->operand_stack[position] = value1;

	stack->operand_stack_references[position - 3] = ref1;
	stack->operand_stack_references[position - 2] = ref3;
	stack->operand_stack_references[position - 1] = ref2;
	stack->operand_stack_references[position] = ref1;

	stack->operand_stack_position++;
}

/**
 * オペランド・スタックに対して "dup2" 命令を実行する
 */
void dup2(frame* stack) {
	unsigned int position = stack->operand_stack_position;
	__int32 value1 = stack->operand_stack[position - 1];
	__int32 value2 = stack->operand_stack[position - 2];
	__int32 ref1 = stack->operand_stack_references[position - 1];
	__int32 ref2 = stack->operand_stack_references[position - 2];

	// 値をコピーする
	stack->operand_stack[position] = value2;
	stack->operand_stack_references[position] = ref2;
	stack->operand_stack[position + 1] = value1;
	stack->operand_stack_references[position + 1] = ref1;

	stack->operand_stack_position += 2;
}

/**
 * オペランド・スタックに対して "dup2_x1" 命令を実行する
 */
void dup2_x1(frame* stack) {
	unsigned int position = stack->operand_stack_position;
	__int32 value1 = stack->operand_stack[position - 1];
	__int32 value2 = stack->operand_stack[position - 2];
	__int32 value3 = stack->operand_stack[position - 3];
	__int32 ref1 = stack->operand_stack_references[position - 1];
	__int32 ref2 = stack->operand_stack_references[position - 2];
	__int32 ref3 = stack->operand_stack_references[position - 3];


	// 値を挿入する
	stack->operand_stack[position - 3] = value2;
	stack->operand_stack[position - 2] = value1;
	stack->operand_stack[position - 1] = value3;
	stack->operand_stack[position    ] = value2;
	stack->operand_stack[position + 1] = value1;

	stack->operand_stack_references[position - 3] = ref2;
	stack->operand_stack_references[position - 2] = ref1;
	stack->operand_stack_references[position - 1] = ref3;
	stack->operand_stack_references[position    ] = ref2;
	stack->operand_stack_references[position + 1] = ref1;

	stack->operand_stack_position += 2;
}

/**
 * オペランド・スタックに対して "dup2_x2" 命令を実行する
 */
void dup2_x2(frame* stack) {
	unsigned int position = stack->operand_stack_position;
	__int32 value1 = stack->operand_stack[position - 1];
	__int32 value2 = stack->operand_stack[position - 2];
	__int32 value3 = stack->operand_stack[position - 3];
	__int32 value4 = stack->operand_stack[position - 4];
	__int32 ref1 = stack->operand_stack_references[position - 1];
	__int32 ref2 = stack->operand_stack_references[position - 2];
	__int32 ref3 = stack->operand_stack_references[position - 3];
	__int32 ref4 = stack->operand_stack_references[position - 4];

	// 値を挿入する
	stack->operand_stack[position - 4] = value2;
	stack->operand_stack[position - 3] = value1;
	stack->operand_stack[position - 2] = value4;
	stack->operand_stack[position - 1] = value3;
	stack->operand_stack[position    ] = value2;
	stack->operand_stack[position + 1] = value1;

	stack->operand_stack_references[position - 4] = ref2;
	stack->operand_stack_references[position - 3] = ref1;
	stack->operand_stack_references[position - 2] = ref4;
	stack->operand_stack_references[position - 1] = ref3;
	stack->operand_stack_references[position    ] = ref2;
	stack->operand_stack_references[position + 1] = ref1;
	stack->operand_stack_position += 2;
}

/**
 * "swap"命令を実行する
 */
void swap(frame* stack) {
	unsigned int position = stack->operand_stack_position;
	// 値を入れ替える
	__int32 value1 = stack->operand_stack[position - 1];
	__int32 value2 = stack->operand_stack[position - 2];
	__int32 ref1 = stack->operand_stack_references[position - 1];
	__int32 ref2 = stack->operand_stack_references[position - 2];

	stack->operand_stack[position - 2] = value1;
	stack->operand_stack[position - 1] = value2;

	stack->operand_stack_references[position - 2] = ref1;
	stack->operand_stack_references[position - 1] = ref2;
}

static jobject new_reference(frame* frm, jobject ref) {
	if (ensure_stack_capacity(frm)) {
		PUSH_OBJECT(frm, ref);
	} else {
		// フレームの有効領域内で、NULLが入っている空き領域を探す
		bool done = false;
		__int32* data;
		__int32* references;
		unsigned int count;
		jobject current_exception;
		get_root_frame_info(frm, &data, &references, &count, &current_exception);
		for (unsigned int i = 0; i < count; ++i) {
			if (data[i] == NULL) {
				references[i] = data[i] = (__int32) ref;
				done = true;
				break;
			}
		}
		if (! done) {
			// ToDo: エラー処理方法を考える必要がある
			assert(false);
			ref = NULL;
		}
	}
	return ref;
}

static void delete_reference(frame* frm, jobject ref) {
	__int32 value;
	get_stack_data(frm, 0, &value);
	if (value == (__int32) ref) {
		// スタックトップのオブジェクトが一致する場合、単純にpopする
	    POP_DISCARD(frm);
	} else {
		// 渡されたフレームから、ルートフレームを検索する
		frame* prev;
		while ((prev = frm->previous_frame) != NULL) {
			frm = prev;
		}
		// フレームの有効領域内で、指定された参照と一致するものを探す
		__int32* data;
		// unsigned char* refflags;
		__int32* references;
		unsigned int count;
		jobject current_exception;
		get_root_frame_info(frm, &data, &references, &count, &current_exception);
		for (unsigned int i = 0; i < count; ++i) {
			value = data[i];
			if (value == (__int32) ref) {
				// 対象位置にNULLを設定する（ガベージコレクト対象とする）
				data[i] = NULL;
				break;
			}
		}
	}
}

/**
 * 新しいローカル参照を作成する（フレームに格納し、ガベージコレクトされないようにする）
 */
jobject new_local_reference(frame* current_frame, jobject ref) {
	return new_reference(get_current_frame(current_frame->body->local_references_frame), ref);
}

/**
 * 指定されたローカル参照を削除する（ガベージコレクト対象とする）
 */
void delete_local_reference(frame* current_frame, jobject ref) {
	delete_reference(get_current_frame(current_frame->body->local_references_frame), ref);
}

/**
 * 新しいグローバル参照を作成する（ガベージコレクトされないようにする）
 */
jobject new_global_reference(jobject ref) {
	EnterCriticalSection(&g_global_critical_section);
	jobject result = new_reference(g_global_references_frame, ref);
	LeaveCriticalSection(&g_global_critical_section);
	return result;
}

/**
 * 指定されたグローバル参照を削除する（ガベージコレクト対象とする）
 */
void delete_global_reference(jobject ref) {
	EnterCriticalSection(&g_global_critical_section);
	delete_reference(g_global_references_frame, ref);
	LeaveCriticalSection(&g_global_critical_section);
}

/**
 * スタック・フレームに１つ要素をpush可能かを調べる
 */
bool ensure_stack_capacity(frame* frm) {
	frame_body* body = frm->body;
	unsigned int count = body->count;
	__int32* current_addr = frm->operand_stack + frm->operand_stack_position;
	__int32* base_addr = body->data;
	int diff = current_addr - base_addr;
	assert(diff >= 0);
	return (unsigned int)diff < count;
}

/**
 * 指定されたフレームに対応するスレッドのカレントフレームを返す。
 */
frame* get_current_frame(frame* frm) {
	return frm->body->current_frame;
}

/**
 * instanceofの結果をキャッシュに入れる
 */
void update_instanceof_cache(frame* frm, ClassFile* lvalue, const java_utf8* rvalue, int result) {
	frame_body* body = frm->body;
	body->instanceof_lvalue = lvalue;
	body->instanceof_rvalue = rvalue;
	body->instanceof_result = result;
}

/**
 * instanceofの結果をキャッシュから取得する
 * 負数が帰った場合にはキャッシュ内にヒットする条件が存在しないことを示す。
 */
int get_instanceof_cache(frame* frm, ClassFile* lvalue, const java_utf8* rvalue) {
	frame_body* body = frm->body;
	if (body->instanceof_lvalue == lvalue && body->instanceof_rvalue == rvalue) {
		return body->instanceof_result;
	}
	return -1;
}

/**
 * 指定された frame のカレントスレッドを指定する
 * １つのframeにつき、この関数は1回しか呼び出せない。（2回目以降の呼び出しは無視される）
 */
void set_current_thread(frame* frm, jobject thread) {
	frame_body* body = frm->body;
	assert(! body->current_thread);
	body->current_thread = thread;
}

/**
 * 指定された frame のカレントスレッド(java.lang.Threadのインスタンス）を返す
 */
jobject get_current_thread(frame* frm) {
	return frm->body->current_thread;
}

/**
 * 指定されたThreadオブジェクトに対応するframeオブジェクトを返す
 * 対応するframeが存在しない場合はNULLを返す。
 */
frame* get_current_frame_of(jobject thread) {
	frame* current_frame = NULL;
	for (int i = 0; i < MAX_ROOT_FRAMES_COUNT; ++i) {
		if (get_current_thread(g_root_frames[i]) == thread) {
			current_frame = g_root_frames[i]->body->current_frame;
			break;
		}
	}
	return current_frame;
}


/**
 * 指定された

/**
 * JNIEnv* を取得する
 */
JNIEnv* get_JNIEnv(frame* frm) {
	return frm->body->env;
}

/**
 * JNIEnv* を設定する
 */
void set_JNIEnv(frame* frm, JNIEnv* env) {
	assert(! frm->body->env);
	frm->body->env = env;
	frm->body->local_references_frame = alloc_root_frame(NULL);
}

/**
 * ローカル参照用frameをpushする
 * ToDo: enter_method()との共通化
 */
int push_local_frame(frame* current_frame, frame* new_frame, int capacity) {
	memset(new_frame, 0, sizeof(frame));
	
	// ローカルフレームを取得する
	frame* local_frame = current_frame->body->local_references_frame;
	local_frame = local_frame->body->current_frame;

	new_frame->body = local_frame->body;
	
	// 変数のアドレスを計算する
	frame* previous_frame = local_frame;
	new_frame->local_variables
			= local_frame->operand_stack
				+ previous_frame->operand_stack_position;
	new_frame->local_variables_references
			= previous_frame->operand_stack_references
				+ previous_frame->operand_stack_position;

	// スタック領域の最大値を決定する
	u2 max_stack = capacity;

	// オペランド・スタックの開始アドレスを決定する
	new_frame->operand_stack = new_frame->local_variables;
	new_frame->operand_stack_position = 0;
	new_frame->operand_stack_references
			= new_frame->local_variables_references;

	// スタックがオーバーフローしないか調べる
	if (! check_stack_overflow(new_frame, max_stack)) {
		// リミットを拡張する
		if (new_frame->body->limit_count < new_frame->body->count) {
			new_frame->body->limit_count = new_frame->body->count;
		}
		// OutOfMemoryError を throw する
		throw_exception(current_frame, "java/lang/OutOfMemoryError");
		return -1;
	}
	new_frame->previous_frame = previous_frame;
	
	// カレントフレームを設定する
	new_frame->body->current_frame = new_frame;

	return 0;
}

/**
 * ローカル参照用 frame を pop する
 * ToDo: leave_method()との共通化
 */
jobject pop_local_frame(frame* current_frame, jobject ref) {
	frame* new_frame = current_frame->body->local_references_frame;
	new_frame = new_frame->body->current_frame;
	frame* previous = new_frame->previous_frame;
	if (ref) {
		// 前のframeに戻すべき値がある場合は、pushする
		PUSH_OBJECT(previous, ref);
	}

	// 誤ってカレントフレームが継続使用された場合、アクセス違反が起きるようにする
	memset(new_frame, 0, sizeof(frame));

	// カレントフレームを１つ前に戻す
	previous->body->current_frame = previous;

	return ref;
}

/**
 * スタックがオーバーフローするかを調べる
 * オーバーフローする場合は false を返す
 */
static inline bool check_stack_overflow(frame* frm,	int max_stack) {
	return (frm->operand_stack + max_stack) < (frm->body->data + frm->body->limit_count);
}

