/* java_object.h
   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.
*/

#ifndef JAVA_OBJECT_H_INCLUDED
#define JAVA_OBJECT_H_INCLUDED

#include "ClassFile.h"
#include "java_object.h"
#include "frame.h"
#include "monitor.h"

/**
 * ファイナライザ
 */
struct finalizer;

/**
 * インスタンスデータ
 */
struct java_object {
	/**
	 * 次のjava_objectへのポインタ
	 */
	java_object* next;

	/**
	 * ヒープ要素のサイズ
	 */
	unsigned int size;

	/**
	 * ガベージコレクタが使用するフラグ
	 */
	long flags;

	/**
	 * このインスタンスに対応するClassFile構造体
	 */
	ClassFile* class_file;
	
	/**
	 * オブジェクトのモニタ
	 */
	monitor* object_monitor;

	/**
	 * データカウント。
	 * 通常オブジェクトの場合、データ部分のバイト数となる。
	 * 配列オブジェクトの場合、配列の長さを表す。
	 *
	 */
	__int32	count;
	
	// データ本体は、この構造体の後ろに続けて配置される

};

/**
 * ヒープを初期化する
 */
void initialize_heap(unsigned int max_size);

/**
 * ガベージコレクタを初期化する
 */
bool init_gc();

/**
 * 指定されたクラスのstaticデータを作成する。
 *
 * @param	cfile	ClassFile構造体のポインタ。loaderによってロードされたものでなければならない。
 * @return	staticフィールドの内容を保持するオブジェクト。確保できなかった場合はNULL。
 */
jobject alloc_static_data(ClassFile* cfile);

/**
 * 指定されたクラスの非staticフィールドの値を保持するjava_object構造体を作成する
 *
 * @param	cfile	ClassFile構造体のポインタ。loaderによってロードされたものでなければならない。
 * @param	stack	作成したオブジェクトの参照をpushするスタック・フレーム
 * @return	オブジェクトの参照。確保できなかった場合はNULL。
 */
jobject alloc_object(ClassFile* cfile, frame* stack);

/**
 * 指定されたクラスに対応する配列オブジェクト用メモリを確保する
 *
 * @param	cfile	ClassFile構造体のポインタ。
 * @param	count	配列の要素数
 * @param	stack	作成した配列の参照をpushするスタック・フレーム。
 * @return	作成した配列の参照。作成できなかった場合NULL
 */
jarray alloc_array(ClassFile* cfile, __int32 count, frame* stack);

/**
 * 指定されたUTF-8文字列をJavaのchar[]に変換する
 * 指定されたUTF-8文字列がUnicodeに変換された後、そのUnicode文字列を保持する
 * char配列が作成される
 *
 * @param	cfile	char[]を表すClassFile構造体。(クラス名は"[C")
 * @param	utf8	UTF-8文字列
 * @param	stack	作成した配列の参照をpushするスタック・フレーム。
 * @return	作成した配列の参照。作成できなかった場合NULL
 */
jcharArray alloc_char_array(ClassFile* cfile, const java_utf8* utf8, frame* stack);
jcharArray alloc_permanent_char_array(ClassFile* cfile, const java_utf8* utf8, frame* stack);

/**
 * 指定されたUnicode文字列をJavaのchar[]に変換する
 *
 * @param	cfile	char[]を表すClassFile構造体。(クラス名は"[C")
 * @param	unicode	Unicode文字列
 * @param	length	Unicode文字列中、配列に入れる長さ
 * @param	stack	作成した配列の参照をpushするスタック・フレーム。
 * @return	作成した配列の参照。作成できなかった場合NULL
 */
jcharArray alloc_char_array(ClassFile* cfile, _TCHAR* unicode, int length, frame* stack);

/**
 * 指定された参照の内容を複製する
 */
jobject clone(frame* frm, jobject ref);

/**
 * 指定されたフィールドの内容を設定する
 */
void put_field(frame* frame, ClassFile* cfile, jfieldID fid);

/**
 * 指定されたフィールドの内容を設定する
 */
void put_field_by_position(frame* frm, const CONSTANT_Fieldref_info* fieldref);

/**
 * 指定されたstaticフィールドの内容を設定する
 */
void put_static_field(frame* frame, jobject data, jfieldID fid);

/**
 * 指定された非staticフィールドの値を返す
 */
bool get_field(frame* frame, ClassFile* cfile, jfieldID fid);

/**
 * 指定されたフィールドの値を取得し、フレームにpushする
 *
 * @param	frame	フィールドの値を格納するフレーム
 * @param       fieldref   フィールドを参照しているCONSTANT_Fieldref_infoへのポインタ
 */
void get_field_by_position(frame* frame, const CONSTANT_Fieldref_info* fieldref);


/**
 * 指定されたstaticフィールドの値を取得し、フレームにpushする
 *
 */
bool get_static_field(frame* frame, jobject ref, jfieldID fid);

/**
 * 指定されたstaticフィールドの値を返す
 *
 * @param	frame      フィールドの値を格納するフレーム
 * @param       fieldref   スタティックフィールドを参照しているCONSTANT_Fieldref_infoへのポインタ
 */
void get_static_field_by_position(frame* frame, const CONSTANT_Fieldref_info* fieldref);

/**
 * 指定されたstaticフィールドに値を設定する
 *
 * @param	frame             フィールドの値が設定されたframe
 * @param       fieldref   スタティックフィールドを参照しているCONSTANT_Fieldref_infoへのポインタ
 */
void put_static_field_by_position(frame* frame, const CONSTANT_Fieldref_info* fieldref);


/**
 * 指定された配列の長さを返す
 */
inline __int32 get_array_length(jarray arrayref) {
/*
	java_object* obj = lock_address(arrayref);
	__int32 count = obj->count;
	unlock_address(arrayref);
	return count;
*/
	return ((java_object*) arrayref)->count;
}

/**
 * 指定された配列の要素を取得する
 * 
 * @param	arrayref	配列オブジェクトへのポインタ
 * @param	index		インデックス
 * @param	pvalue		取得した値を格納する
 */
bool load_object_array(jarray arrayref, jint inde, jobject* pref);

/**
 * 指定された配列の要素を設定する
 *
 * @param	obj	配列オブジェクト
 * @param	index	インデックス
 * @param	value	設定値
 */
bool store_object_array(jarray arrayref, __int32 index, jobject ref);

/**
 * 指定された参照のClassFileを返す
 */
inline ClassFile* get_ClassFile(jobject ref)
{
  return ((java_object*) ref)->class_file;
}

/**
 * このオブジェクトのモニタを返す
 *
 */
monitor* get_monitor(jobject ref);

/**
 * このオブジェクトのモニタを設定する
 *
 */
void set_monitor(jobject ref, monitor* m);

/**
 * オブジェクト本体へのポインタを返す
 */
inline void* get_object_body(jobject ref) {
	java_object* obj = (java_object*) ref;
	return (obj + 1);
}

/**
 * ガベージコレクタを起動する
 */
void gc();

/**
 * オブジェクトデータ本体が入っている位置のポインタをロックする。
 * この関数を呼び出した時点で、アドレス位置がロックされ、ガベージコレクション
 * 対象ではなくなる。
 * lock_pointerを呼び出したのと同一回数 unlock_pointer関数を呼び出すまで、
 * ロックされた状態となる。
 */
void* pin_object(jobject ref);

/**
 * 指定されたポインタをアンロックする。
 * この関数に渡すポインタは、pin_object()関数から返されたものを
 * 使用しなければならない。
 */
void unpin_object(void* ptr);

/**
 * ファイナライザスレッドを初期化する
 */
bool init_finalizer();

/**
 * ファイナライザを返す
 */
finalizer* get_finalizer();

/**
 * ファイナライズ処理を実行する
 */
void gc_run_finalizer(frame* frm, finalizer* f);

/**
 * 配列のコピーを行う
 */
void array_copy(jobject src, unsigned int src_start, jobject dest, unsigned int dest_start, int length);


#define SOFT_REFERENCE		1
#define WEAK_REFERENCE		2
#define PHANTOM_REFERENCE	3

/**
 * 参照オブジェクトであることをガベージコレクタに通知する。
 * SoftReference/WeakReference/PhantomReferenceのインスタンスは、必ずこの関数を用いて
 * ガベージコレクタに登録しておく必要がある。
 * ガベージコレクタは、この関数で登録されたオブジェクトを特別扱いする。
 * typeに指定する数値は以下のとおり。
 */
void set_reference_type(jobject obj, int reference_type);

/**
 * ガベージコレクタログファイル名を設定する
 */
void set_loggc_filename(const _TCHAR* filename);

/**
 * 空きメモリ量を返す
 */
unsigned int gc_get_free_memory();

/**
 * ヒープ全体のサイズを返す
 */
unsigned int gc_get_total_memory();

/**
 * 最大メモリ量を返す
 */
unsigned int gc_get_max_memory();

/**
 * -verbose:gc オプションを設定する
 */
void gc_set_verbose(bool verbose);

/**
 * オブジェクト参照のロックカウントを１増やした後、オブジェクトのアドレスを返す。
 * 現在未実装。将来は以下のような動作を実装予定。
 * ロックカウントが1以上の場合、ガベージコレクタはオブジェクトのアドレスを移動できない。
 * （オブジェクトの移動をサポートする際に実装する）
 */
#define lock_address(ref)	((java_object*) ref)
/**
 * オブジェクト参照のロックカウントを１つ減らす。
 * 現在未実装。将来は以下のような動作を実装予定。
 * 
 * ロックカウントが1以上の場合、ガベージコレクタはオブジェクトのアドレスを移動できない。
 */
#define	unlock_address(ref)

/**
 * 指定されたjava_objectに対応する jobject を返す
 */
inline jobject make_reference(java_object* obj) {
	// 現在の実装では、jobjectはjava_object*と同一
	return (jobject) obj;
}

/**
 * オブジェクト本体のポインタを返す
 *
 * @param	obj
 * @return	オブジェクトデータ本体が格納されているポインタ
 */
inline void* get_body_ptr(java_object* obj) {
	return (obj + 1);
}

/**
 * 指定された配列クラス名の、各要素サイズを返す。
 */
inline unsigned int get_array_component_size(java_utf8* name) {
	// 配列要素のサイズを判定する
	assert(name[0] == '[');
	switch (name[1]) {
	case 'B':
	case 'Z':
		// byteとboolean型は1バイト
		return 1;

	case 'C':
	case 'S':
		// charとshortは2バイト
		return 2;

	case 'D':
	case 'J':
		// doubleとlongは8バイト
		return 8;

	default:
		// その他の場合は4バイト
		return 4;
	}
}

#endif