#include "stdafx.h"

#include <Compiler.h>

#include "../BasicCompiler_Common/common.h"
#include "Opcode.h"

void FreeTempObject(int reg,const CClass *pobj_c){
	if(!IsSafeReg(reg)) compiler.errorMessenger.Output(300,NULL,cp);

	////////////////////////////////////////////////
	// 演算過程で利用した一時オブジェクトを破棄
	// Thisポインタをr14レジスタを介して渡す
	////////////////////////////////////////////////

	const CMethod *method = pobj_c->GetDestructorMethod();
	if( method ){
		//mov rcx,reg
		compiler.codeGenerator.op_mov_RR(REG_RCX,reg);

		//call DestructorProcAddr
		compiler.codeGenerator.op_call( &method->GetUserProc() );
	}

	//mov rcx,reg
	compiler.codeGenerator.op_mov_RR(REG_RCX,reg);

	//call free
	extern const UserProc *pSub_free;
	compiler.codeGenerator.op_call(pSub_free);
}

int CallOperatorProc(BYTE idCalc, const Type &baseType, int *type_stack,LONG_PTR *index_stack,bool isNeedHeapFreeStructureStack[],int &sp)
{
	Type leftType( type_stack[sp-2], index_stack[sp-2] );
	Type rightType( type_stack[sp-1] & (~FLAG_CAST), index_stack[sp-1] );

	//オーバーロードされたオペレータ関数を呼び出す
	const CClass *pobj_c = &leftType.GetClass();

	std::vector<const UserProc *> subs;
	pobj_c->GetDynamicMethods().Enum( idCalc, subs );
	if( subs.size() == 0 ){
		return 0;
	}


	//項の数
	BOOL bTwoTerm=1;
	if(idCalc==CALC_AS) bTwoTerm=0;


	/////////////////////////////////////////////
	// オーバーロード解決用のパラメータを設定
	/////////////////////////////////////////////

	Parameters params;

	if(bTwoTerm)
	{
		params.push_back( new Parameter( "", rightType ) );
	}

	//オーバーロードを解決
	char temporary[255];
	if(idCalc==CALC_EQUAL) lstrcpy(temporary,"==");
	else GetCalcName(idCalc,temporary);
	const UserProc *pUserProc = OverloadSolution( temporary, subs, params, baseType, leftType );

	if(!pUserProc){
		if(bTwoTerm){
			delete params[0];
		}
		return -1;
	}
	else{
		//オーバーロードされていないが、パラメータ個数が一致しないとき
		if(params.size()!=pUserProc->Params().size()){
			if(bTwoTerm){
				delete params[0];
			}
			return -1;
		}
	}

	for(int i=0;i<(int)params.size();i++){
		CheckDifferentType(
			*pUserProc->Params()[i],
			*params[i],
			NULL,
			i);
	}

	if(bTwoTerm){
		delete params[0];
	}

	int right_side_size = rightType.GetSize();

	if(bTwoTerm){
		if( pUserProc->RealParams()[1]->IsStruct() &&pUserProc->RealParams()[1]->IsRef() == false ){
			//一時オブジェクトはメソッド内で破棄される
			isNeedHeapFreeStructureStack[sp-1] = false;
		}
	}


	if( pUserProc->ReturnType().IsStruct() ){
		//////////////////////////////////////////////////////
		// 戻り値に構造体インスタンスを持つ場合
		// ※ByRef _System_ReturnValue パラメータ用領域を取得
		//////////////////////////////////////////////////////


		//////////////////////////////////////////////////////
		/////    レジスタ資源のバックアップ
		{	BACKUP_REGISTER_RESOURCE
		//////////////////////////////////////////////////////

			int object_size = pUserProc->ReturnType().GetClass().GetSize();

			//mov rcx,object_size
			compiler.codeGenerator.op_mov_RV(sizeof(_int64),REG_RCX,object_size);

			//call calloc
			extern const UserProc *pSub_calloc;
			compiler.codeGenerator.op_call(pSub_calloc);

			//mov r13,rax
			compiler.codeGenerator.op_mov_RR(REG_R13,REG_RAX);

		/////////////////////////////////////////////
		//////   レジスタ資源を復元
			RESTORE_REGISTER_RESOURCE
		}////////////////////////////////////////////
	}

	int reg1,reg2;
	if(bTwoTerm){
		//右の項（実数の場合が未完成）
		SetOneTermToReg_Whole64Calc(type_stack[sp-1],&reg2);
		pobj_reg->UnlockReg();
		if( !pUserProc->RealParams()[1]->IsRef() == false ){
			//一時参照を作成
			pobj_sf->push( reg2 );
			pobj_sf->mov_sp( reg2 );
		}
	}

	//左の項
	SetOneTermToReg_Whole64Calc(DEF_INT64,&reg1);
	pobj_reg->UnlockReg();

	//ヒープ解放用に退避
	if(isNeedHeapFreeStructureStack[sp-1]){
		//mov qword ptr[rsp+offset],reg2     ※スタックフレームを利用
		pobj_sf->push(reg2);
	}
	if(isNeedHeapFreeStructureStack[sp-2]){
		//mov qword ptr[rsp+offset],reg1     ※スタックフレームを利用
		pobj_sf->push(reg1);
	}



	//////////////////////////////////////////////////////
	/////    レジスタ資源のバックアップ
	{	BACKUP_REGISTER_RESOURCE
	//////////////////////////////////////////////////////

		if(reg1==REG_RDX||reg1==REG_R8){
			//mov r14,reg1
			compiler.codeGenerator.op_mov_RR(REG_R14,reg1);
			reg1=REG_R14;
		}


		if(bTwoTerm){
			if( pUserProc->ReturnType().IsStruct() ){
				//mov r8,reg2
				compiler.codeGenerator.op_mov_RR(REG_R8,reg2);
			}
			else{
				//mov rdx,reg2
				compiler.codeGenerator.op_mov_RR(REG_RDX,reg2);
			}
		}

		if( pUserProc->ReturnType().IsStruct() ){
			//mov rdx,r13
			compiler.codeGenerator.op_mov_RR(REG_RDX,REG_R13);
		}

		//mov rcx,reg1
		compiler.codeGenerator.op_mov_RR(REG_RCX,reg1);

		//call operator_proc
		compiler.codeGenerator.op_call(pUserProc);

		if( !pUserProc->ReturnType().IsNull() ){
			//戻り値を一時的に退避

			//mov r13,rax
			compiler.codeGenerator.op_mov_RR(REG_R13,REG_RAX);
		}


	/////////////////////////////////////////////
	//////   レジスタ資源を復元
		RESTORE_REGISTER_RESOURCE
	}////////////////////////////////////////////



	if( isNeedHeapFreeStructureStack[sp-2] || isNeedHeapFreeStructureStack[sp-1] )
	{
		//////////////////////////////////////////////////////
		/////    レジスタ資源のバックアップ
		{	BACKUP_REGISTER_RESOURCE
		//////////////////////////////////////////////////////

			if( isNeedHeapFreeStructureStack[sp-2] )
			{
				//mov r14,qword ptr[rsp+offset]     ※スタックフレームを利用
				pobj_sf->pop(REG_R14);

				FreeTempObject(REG_R14,(CClass *)index_stack[sp-2]);
			}
			if( isNeedHeapFreeStructureStack[sp-1] )
			{
				//mov r14,qword ptr[rsp+offset]     ※スタックフレームを利用
				pobj_sf->pop(REG_R14);

				FreeTempObject(REG_R14,(CClass *)index_stack[sp-1]);
			}

		/////////////////////////////////////////////
		//////   レジスタ資源を復元
			RESTORE_REGISTER_RESOURCE
		}////////////////////////////////////////////
	}

	if(bTwoTerm){
		if( !pUserProc->RealParams()[1]->IsRef() == false ){
			//一時参照を破棄
			pobj_sf->pop();
		}
	}

	if( !pUserProc->ReturnType().IsNull() ){
		//戻り値をreg1にセット
		reg1=pobj_reg->LockReg();

		//mov reg1,r13
		compiler.codeGenerator.op_mov_RR(reg1,REG_R13);
	}

	sp--;
	type_stack[sp-1]=pUserProc->ReturnType().GetBasicType();
	index_stack[sp-1]=pUserProc->ReturnType().GetIndex();

	if( pUserProc->ReturnType().IsStruct() )
	{
		//構造体が戻ったときはヒープ領域にインスタンスが格納されている
		//※後にfreeする必要あり
		isNeedHeapFreeStructureStack[sp-1] = true;
	}
	else
	{
		isNeedHeapFreeStructureStack[sp-1] = false;
	}

	return 1;
}

void CallCastOperatorProc(int reg,Type &calcType,BOOL bCalcUseHeap,const Type &toType){
	int type_stack[10];
	LONG_PTR index_stack[10];
	bool array_bUseHeap[10];
	int sp=2;
	int iRet;


	//////////////////////////////////////////////////////
	/////    レジスタ資源のバックアップ
	{	BACKUP_REGISTER_RESOURCE
	//////////////////////////////////////////////////////

		//regを第一項目としてロック
		pobj_reg=new CRegister(reg);
		pobj_reg->LockReg();

		if(bCalcUseHeap){
			//未解放のインスタンスが存在する旨を示す警告
			compiler.errorMessenger.Output(-105,NULL,cp);
		}

		//左辺
		type_stack[0]=calcType.GetBasicType();
		index_stack[0]=calcType.GetIndex();
		array_bUseHeap[0]=0;
		type_stack[1]=toType.GetBasicType();
		index_stack[1]=toType.GetIndex();
		array_bUseHeap[1]=0;

		iRet=CallOperatorProc(CALC_AS,toType,type_stack,index_stack,array_bUseHeap,sp);

		pobj_reg->UnlockReg();

	/////////////////////////////////////////////
	//////   レジスタ資源を復元
		RESTORE_REGISTER_RESOURCE
	}////////////////////////////////////////////


	if(iRet==1){
		//成功したとき
		calcType.SetType( type_stack[0], index_stack[0] );
		return;
	}
	else if(iRet==-1){
		//エラーが発行されたとき
		return;
	}

	//エラーを発行
	compiler.errorMessenger.Output(-1,"キャスト演算子がオーバーロードされていません。",cp);
}

//インデクサ（getter）を呼び出す
void CallIndexerGetterProc(int reg, const Type &classType, const char *ObjectName,char *Parameter,Type &resultType, DWORD dwProcFlags ){

	std::vector<const UserProc *> subs;
	classType.GetClass().GetDynamicMethods().Enum( CALC_ARRAY_GET, subs );
	if( subs.size() == 0 ){
		return;
	}

	const UserProc *pUserProc = subs[0];

	//////////////////////////////////////////////////////
	/////    レジスタ資源のバックアップ
	{	BACKUP_REGISTER_RESOURCE
	//////////////////////////////////////////////////////

		Opcode_CallProc(Parameter,pUserProc,dwProcFlags,ObjectName);
		resultType = pUserProc->ReturnType();

		//mov reg,rax
		compiler.codeGenerator.op_mov_RR(reg,REG_RAX);

	/////////////////////////////////////////////
	//////   レジスタ資源を復元
		RESTORE_REGISTER_RESOURCE
	}////////////////////////////////////////////


	// 型パラメータを解決
	ResolveFormalGenericTypeParameter( resultType, classType, pUserProc );
}
