#include "stdafx.h"

#include <Compiler.h>

#include "../BasicCompiler_Common/common.h"
#include "opcode.h"

void _call_constructor( const CClass *pobj_c,const char *CreateParameter,int ObjectSize,BOOL bSomeObjects){
	////////////////////////////
	// コンストラクタの呼び出し
	////////////////////////////
	
	//この関数を使用する場合は、
	//・ebxにオブジェクトの個数（複数個の場合のみ）
	//・スタックフレームの先頭参照位置に先頭Thisポインタ
	//をセットしておかなければならない


	//jnzの番地
	/*extern int obp;
	int jnz_back = obp;*/

	if(bSomeObjects){
		compiler.errorMessenger.OutputFatalError();
		//mov qword ptr[rsp+offset],rbx     ※スタックフレームを利用
		//pobj_sf->push(REG_RBX);

		// ※ここでプッシュされた値はコンストラクタのthisポインタとなる
		//mov qword ptr[rsp+offset],rax     ※スタックフレームを利用
		//pobj_sf->push(REG_RAX);
	}


	////////////////////////
	// オーバーロードを解決
	////////////////////////

	std::vector<const UserProc *> subs;
	pobj_c->GetDynamicMethods().Enum( pobj_c->GetName().c_str(), subs );

	const UserProc *pUserProc;
	if( subs.size() > 0 ){
		//オーバーロードを解決
		pUserProc=OverloadSolutionWithStrParam(pobj_c->GetName().c_str(),
			subs,CreateParameter,"");

		if(!pUserProc) return;
	}

	{
		// 動的型情報をセットする
		// obj._System_SetType( _System_TypeBase_Search( fullName ) )
		subs.clear();
		pobj_c->GetDynamicMethods().Enum( "_System_SetType", subs );
		if( subs.size() == 1 ){
			char temporary[VN_SIZE];
			sprintf( temporary, "_System_TypeBase_Search(\"%s\"))", pobj_c->GetFullName().c_str() );

			Opcode_CallProc(temporary,
				subs[0],
				PROCFLAG_NEW,"");
		}
		else{
			compiler.errorMessenger.OutputFatalError();
		}
	}

	//コンストラクタを呼び出す
	Opcode_CallProc(CreateParameter,
		pUserProc,
		PROCFLAG_NEW,"");

	if(bSomeObjects){
		/*
		//mov rax,qword ptr[rsp+offset]     ※スタックフレームを利用
		pobj_sf->pop(REG_RAX);

		//mov rbx,qword ptr[rsp+offset]     ※スタックフレームを利用
		pobj_sf->pop(REG_RBX);

		//add rax,TypeSize
		compiler.codeGenerator.op_add_RV( REG_RAX, ObjectSize );

		//sub rbx,1
		compiler.codeGenerator.op_sub_RV( sizeof(_int64), REG_RBX, 1 );

		//jnz ↑
		compiler.codeGenerator.op_jne( jnz_back-obp, sizeof(long), false, true );
		*/
	}
}
void Operator_New( const CClass &objClass, const char *objectSizeStr, const char *parameter, const Type &baseType )
{
	const CClass *pClass = &objClass;

	if( pClass->IsInterface() )
	{
		pClass = compiler.GetObjectModule().meta.GetClasses().GetInterfaceInfoClassPtr();
	}

	int typeSize = pClass->GetSize();

	if( pClass->IsAbstract() ){
		//抽象クラスだったとき
		compiler.errorMessenger.Output(125,pClass->GetName().c_str(),cp);
	}

	BOOL bSomeObjects=0;
	if(objectSizeStr[0]){
		bSomeObjects=1;

		int reg=REG_RAX;
		Type tempType;
		NumOpe(&reg,objectSizeStr,Type(),tempType);
		if( !tempType.IsWhole() ) compiler.errorMessenger.Output(49,NULL,cp);

		//※添え字上限値であることを考慮
		//add rax,1
		compiler.codeGenerator.op_add_RV(REG_RAX,1);

		//オブジェクトの個数をrbxに一時保持
		//※rbxは関数が呼ばれても不変
		//mov rbx,rax
		compiler.codeGenerator.op_mov_RR(REG_RBX,REG_RAX);

		//imul rax,size
		compiler.codeGenerator.op_imul_RV(sizeof(_int64),REG_RAX,typeSize);

		//add rax,OBJECT_HEAD_SIZE
		compiler.codeGenerator.op_add_RV(REG_RAX,OBJECT_HEAD_SIZE);

		//mov rcx,rax
		compiler.codeGenerator.op_mov_RR(REG_RCX,REG_RAX);
	}
	else{
		//オブジェクトの個数をrbxに一時保持
		//※rbxは関数が呼ばれても不変
		//mov rbx,1
		compiler.codeGenerator.op_mov_RV(sizeof(_int64),REG_RBX,1);

		//mov rcx,typeSize+OBJECT_HEAD_SIZE
		compiler.codeGenerator.op_mov_RV(sizeof(_int64),REG_RCX,typeSize+OBJECT_HEAD_SIZE);
	}

	if( baseType.IsObject() ){
		// オブジェクト インスタンス
		// ※DeleteはGCで処理

		//call _System_GC_malloc_ForObject
		extern const UserProc *pSub_System_GC_malloc_ForObject;
		compiler.codeGenerator.op_call(pSub_System_GC_malloc_ForObject);
	}
	else{
		// オブジェクトポインタ
		// ※明示的なDeleteが必要

		//call _System_GC_malloc_ForObjectPtr
		extern const UserProc *pSub_System_GC_malloc_ForObjectPtr;
		compiler.codeGenerator.op_call(pSub_System_GC_malloc_ForObjectPtr);
	}


	/*
	確保されたヒープ領域のポインタ（callocの戻り値eax）をpPtrとすると、
	pPtr-=OBJECT_HEAD_SIZE ... ( sizeof(DWORD)*4 )
	pPtr[0]=オブジェクトの個数
	pPtr[1]=オブジェクトのサイズ
	pPtr[2]=デストラクタの関数ポインタ
	pPtr[3]=reserve
	*/


	//mov qword ptr[rax],rbx（オブジェクトの個数）
	compiler.codeGenerator.op_mov_MR(sizeof(_int64),REG_RBX,REG_RAX,0,MOD_BASE);

	//add rax,PTR_SIZE
	compiler.codeGenerator.op_add_RV(REG_RAX,PTR_SIZE);


	//mov qword ptr[rax],typeSize（オブジェクトのサイズ）
	compiler.codeGenerator.op_mov_MV(sizeof(_int64),REG_RAX,0, Schedule::None, false, NON_OFFSET,typeSize);

	//add rax,PTR_SIZE
	compiler.codeGenerator.op_add_RV(REG_RAX,PTR_SIZE);


	const CMethod *method = pClass->GetDestructorMethod();
	if( method == NULL ) return;

	//mov rcx,DestructorProcAddr（デストラクタの関数ポインタ）
	compiler.codeGenerator.op_addressof( REG_RCX, &method->GetUserProc() );

	//mov qword ptr[rax],rcx
	compiler.codeGenerator.op_mov_MR(sizeof(_int64),REG_RCX,REG_RAX,0,MOD_BASE);

	//add rax,PTR_SIZE
	compiler.codeGenerator.op_add_RV(REG_RAX,PTR_SIZE);


	// リザーブ領域
	//add rax,PTR_SIZE
	compiler.codeGenerator.op_add_RV(REG_RAX,PTR_SIZE);


	// ※ここでプッシュされた値はNew演算子の戻り値となる
	//mov qword ptr[rsp+offset],rax     ※スタックフレームを利用
	pobj_sf->push(REG_RAX);


	//仮想関数テーブルを初期化
	if( pClass->IsExistVirtualFunctions()
		&& !pClass->IsAbstract() )
	{
		// mov rcx,com_vtbl
		compiler.codeGenerator.op_mov_RV_com_vtbl( REG_RCX, pClass );

		//mov qword ptr[rax],rcx
		compiler.codeGenerator.op_mov_MR(sizeof(_int64),REG_RCX,REG_RAX,0,MOD_BASE);

		// mov rcx,vtblAddress
		compiler.codeGenerator.op_mov_RV_vtbl( REG_RCX, pClass );

		//mov qword ptr[rax+sizeof(com_vtbl)],rcx
		compiler.codeGenerator.op_mov_MR(sizeof(_int64),REG_RCX,REG_RAX,PTR_SIZE,MOD_BASE_DISP8);


		// 仮想関数になるメソッドに使用チェックをつける
		BOOST_FOREACH( const CMethod *pMethod, pClass->GetDynamicMethods() )
		{
			if( pMethod->IsVirtual() )
			{
				pMethod->GetUserProc().Using();
			}
		}
		BOOST_FOREACH( const ::Interface *pInterface, pClass->GetInterfaces() )
		{
			BOOST_FOREACH( const CMethod *pMethod, pInterface->GetDynamicMethods() )
			{
				if( pMethod->IsVirtual() )
				{
					pMethod->GetUserProc().Using();
				}
			}
		}
	}


	/////////////////////////////////////////////////////////////////////

	////////////////////////////
	// コンストラクタの呼び出し
	////////////////////////////

	_call_constructor(pClass,parameter,typeSize,bSomeObjects);


	//mov rax,qword ptr[rsp+offset]     ※スタックフレームを利用
	pobj_sf->pop(REG_RAX);
}
void OpcodeDelete(const char *Parameter, bool isSweeping){
	int reg=REG_RAX;
	Type tempType;
	if( !NumOpe(&reg,Parameter,Type(),tempType) ){
		return;
	}
	if(!( tempType.IsObjectPtr() || tempType.IsVoidPtr() )) compiler.errorMessenger.Output(122,NULL,cp);

	//sub rax,OBJECT_HEAD_SIZE
	compiler.codeGenerator.op_sub_RV(sizeof(_int64),REG_RAX,OBJECT_HEAD_SIZE);

	//mov qword ptr[rsp+offset],rax     ※スタックフレームを利用
	pobj_sf->push(REG_RAX);


	//mov rbx,qword ptr[rax]（オブジェクトの個数）
	compiler.codeGenerator.op_mov_RM(sizeof(_int64),REG_RBX,REG_RAX,0,MOD_BASE);

	//add rax,PTR_SIZE
	compiler.codeGenerator.op_add_RV(REG_RAX,PTR_SIZE);


	//mov rsi,qword ptr[rax]（オブジェクトのサイズ）
	compiler.codeGenerator.op_mov_RM(sizeof(_int64),REG_RSI,REG_RAX,0,MOD_BASE);

	//add rax,PTR_SIZE
	compiler.codeGenerator.op_add_RV(REG_RAX,PTR_SIZE);


	//mov rdi,qword ptr[rax]（デストラクタの関数ポインタ）
	compiler.codeGenerator.op_mov_RM(sizeof(_int64),REG_RDI,REG_RAX,0,MOD_BASE);

	//add rax,PTR_SIZE
	compiler.codeGenerator.op_add_RV(REG_RAX,PTR_SIZE);


	// リザーブ領域
	//add rax,PTR_SIZE
	compiler.codeGenerator.op_add_RV(REG_RAX,PTR_SIZE);


	//mov rcx,rax
	compiler.codeGenerator.op_mov_RR(REG_RCX,REG_RAX);


	//jnzの番地
	//int jnz_back=obp;

	//mov qword ptr[rsp+offset],rcx     ※スタックフレームを利用
	pobj_sf->push(REG_RCX);

	//call rdi
	compiler.codeGenerator.PutOld(
		(char)0xFF,
		(char)0xD7
	);

	//mov rcx,qword ptr[rsp+offset]     ※スタックフレームを利用
	pobj_sf->pop(REG_RCX);

	//add rcx,rsi
	compiler.codeGenerator.op_add_RR(REG_RCX,REG_RSI);

	//sub rbx,1
	compiler.codeGenerator.op_sub_RV(sizeof(_int64),REG_RBX,1);

	//jnz ↑
	//compiler.codeGenerator.op_jne( jnz_back-obp, sizeof(long), false, true );


	//////////////////////////////////////////
	// オブジェクトメンバ変数用のメモリを解放
	//////////////////////////////////////////

	//mov rcx,qword ptr[rsp+offset]     ※スタックフレームを利用
	pobj_sf->pop(REG_RCX);

	if( isSweeping ){
		//call _System_GC_free_for_SweepingDelete
		extern const UserProc *pSub_System_GC_free_for_SweepingDelete;
		compiler.codeGenerator.op_call(pSub_System_GC_free_for_SweepingDelete);
	}
	else{
		//call free
		extern const UserProc *pSub_free;
		compiler.codeGenerator.op_call(pSub_free);
	}
}
