#include "stdafx.h" #ifdef _AMD64_ #include "../../BasicCompiler64/opcode.h" #else #include "../../BasicCompiler32/opcode.h" #endif #include namespace Exception{ class CatchScope { Type paramType; long codePos; public: CatchScope( const Type ¶mType, long codePos ) : paramType( paramType ) , codePos( codePos ) { } ~CatchScope() { } const Type &GetParamType() const { return paramType; } long GetCodePos() const { return codePos; } }; typedef std::vector CatchScopes; class TryScope { int sourceCodePos; bool isDefinedFinally; CatchScopes catchScopes; std::vector finallySchedules; void JmpFinally() { finallySchedules.push_back( compiler.codeGenerator.op_jmp( 0, sizeof(long), true ) ); } void ResolveJmpFinally() { BOOST_FOREACH( const PertialSchedule *pPertialSchedule, finallySchedules ) { compiler.codeGenerator.opfix_JmpPertialSchedule( pPertialSchedule ); } } const PertialSchedule *pPertialScheduleForCatchAddress; const PertialSchedule *pPertialScheduleForFinallyAddress; public: TryScope( int sourceCodePos ) : sourceCodePos( sourceCodePos ) , isDefinedFinally( false ) { } ~TryScope() { } int GetSourceCodePos() const { return sourceCodePos; } const CatchScopes &GetCatchScopes() const { return catchScopes; } bool IsCatched() const { return ( catchScopes.size() != 0 ); } bool IsDefinedFinally() const { return isDefinedFinally; } void RegistPertialScheduleForCatchAddress( const PertialSchedule *pPertialScheduleForCatchAddress ) { this->pPertialScheduleForCatchAddress = pPertialScheduleForCatchAddress; } const PertialSchedule *GetPertialScheduleForCatchAddress() const { return pPertialScheduleForCatchAddress; } void RegistPertialScheduleForFinallyAddress( const PertialSchedule *pPertialScheduleForFinallyAddress ) { this->pPertialScheduleForFinallyAddress = pPertialScheduleForFinallyAddress; } const PertialSchedule *GetPertialScheduleForFinallyAddress() const { return pPertialScheduleForFinallyAddress; } void Try() { // レキシカルスコープをレベルアップ compiler.codeGenerator.lexicalScopes.Start( compiler.codeGenerator.GetNativeCodeSize(), LexicalScope::SCOPE_TRY ); } void Catch( Type ¶mType ) { if( isDefinedFinally ) { SetError(71,NULL,cp); return; } if( catchScopes.size() ) { // 既に1回以上のCatchが存在するとき // レキシカルスコープをレベルダウン compiler.codeGenerator.lexicalScopes.End(); } JmpFinally(); catchScopes.push_back( CatchScope( paramType, compiler.codeGenerator.GetNativeCodeSize() ) ); // レキシカルスコープをレベルアップ compiler.codeGenerator.lexicalScopes.Start( compiler.codeGenerator.GetNativeCodeSize(), LexicalScope::SCOPE_CATCH ); } void Finally() { if( isDefinedFinally ) { SetError(70,NULL,cp); return; } if( catchScopes.size() ) { // 既に1回以上のCatchが存在するとき // レキシカルスコープをレベルダウン compiler.codeGenerator.lexicalScopes.End(); } isDefinedFinally = true; ResolveJmpFinally(); // レキシカルスコープをレベルアップ compiler.codeGenerator.lexicalScopes.Start( compiler.codeGenerator.GetNativeCodeSize(), LexicalScope::SCOPE_FINALLY ); } void EndTry() { if( !isDefinedFinally ) { Finally(); } if( catchScopes.size() || isDefinedFinally ) { // 既に1回以上のCatch、またはFinallyが存在するとき // レキシカルスコープをレベルダウン compiler.codeGenerator.lexicalScopes.End(); } // レキシカルスコープをレベルダウン compiler.codeGenerator.lexicalScopes.End(); } int GenerateCatchTable() { int size = static_cast(( (catchScopes.size()+1)*2 ) * sizeof(LONG_PTR)); BYTE *buffer = (BYTE *)calloc( size, 1 ); int pos = 0; BOOST_FOREACH( const CatchScope &catchScope, catchScopes ) { // パラメータのクラス名 char paramName[VN_SIZE] = ""; int paramNameDataTableOffset = 0; if( catchScope.GetParamType().IsObject() ) { lstrcpy( paramName, catchScope.GetParamType().GetClass().GetFullName().c_str() ); } paramNameDataTableOffset = compiler.GetObjectModule().dataTable.AddString( paramName ); *((LONG_PTR *)(buffer+pos)) = paramNameDataTableOffset; pos += sizeof(LONG_PTR); // Catchアドレス *((LONG_PTR *)(buffer+pos)) = catchScope.GetCodePos(); pos += sizeof(LONG_PTR); } int dataTableOffset = compiler.GetObjectModule().dataTable.AddBinary( buffer, size ); free( buffer ); pos = 0; BOOST_FOREACH( const CatchScope &catchScope, catchScopes ) { // パラメータのクラス名 compiler.GetObjectModule().dataTable.schedules.push_back( Schedule( Schedule::DataTable, dataTableOffset + pos ) ); pos += sizeof(LONG_PTR); // Catchアドレス const UserProc *pUserProc = &UserProc::CompilingUserProc(); if( UserProc::IsGlobalAreaCompiling() ) { pUserProc = UserProc::pGlobalProc; } compiler.GetObjectModule().dataTable.schedules.push_back( Schedule( pUserProc, dataTableOffset + pos ) ); compiler.GetObjectModule().dataTable.schedules.back().SpecifyCatchAddress(); pos += sizeof(LONG_PTR); } return dataTableOffset; } }; typedef std::vector TryScopes; TryScopes tryScopes; void TryCommand() { tryScopes.push_back( TryScope( cp ) ); tryScopes.back().Try(); int backCp = cp; char temporary[1024]; lstrcpy( temporary, "ExceptionService.BeginTryScope( _System_GetNowScopeCatchAddresses() As VoidPtr, _System_GetNowScopeFinallyAddresses() As VoidPtr, _System_GetBp() As LONG_PTR, _System_GetSp() As LONG_PTR )" ); MakeMiddleCode( temporary ); ChangeOpcode( temporary ); cp = backCp; } void CatchCommand( const char *parameter ) { if( tryScopes.size() == 0 ) { SetError(1,NULL,cp); return; } char varName[VN_SIZE]; Type paramType; if( parameter[0] ) { char typeName[VN_SIZE]; SplitSyntacticForAs( parameter, varName, typeName ); if( !typeName[0] ) { SetError(72,NULL,cp); } else { if( !compiler.StringToType( typeName, paramType ) ) { SetError(73,NULL,cp); } } } tryScopes.back().Catch( paramType ); if( paramType.IsObject() ) { int backCp = cp; char temporary[1024]; sprintf( temporary, "Dim %s = Thread.CurrentThread().__GetThrowintParamObject() As %s", varName, paramType.GetClass().GetFullName().c_str() ); MakeMiddleCode( temporary ); ChangeOpcode( temporary ); lstrcpy( temporary, "Thread.CurrentThread().__Catched()" ); MakeMiddleCode( temporary ); ChangeOpcode( temporary ); cp = backCp; } } void FinallyCommand() { tryScopes.back().Finally(); int backCp = cp; char temporary[1024]; lstrcpy( temporary, "_System_pobj_AllThreads->GetCurrentException()->FinishFinally()" ); MakeMiddleCode( temporary ); ChangeOpcode( temporary ); cp = backCp; //Tryスコープに入るときに引き渡されるパラメータ値を解決 compiler.codeGenerator.opfix( tryScopes.back().GetPertialScheduleForFinallyAddress(), compiler.codeGenerator.GetNativeCodeSize() ); } void EndTryCommand( bool isNoWarning ) { if( tryScopes.size() == 0 ) { SetError(12,"End Try",cp); return; } if( !isNoWarning && !tryScopes.back().IsDefinedFinally() && !tryScopes.back().IsCatched() ) { // CatchもFinallyも存在しないとき SetError(-108,NULL,tryScopes.back().GetSourceCodePos() ); } int dataTableOffset = tryScopes.back().GenerateCatchTable(); // _System_GetNowScopeCatchAddressesを解決 compiler.codeGenerator.opfix( tryScopes.back().GetPertialScheduleForCatchAddress(), dataTableOffset ); if( !tryScopes.back().IsDefinedFinally() ) { // Finallyが定義されていないときは空のFinallyを定義しておく FinallyCommand(); } int backCp = cp; char temporary[1024]; lstrcpy( temporary, "_System_pobj_AllThreads->GetCurrentException()->EndTryScope()" ); MakeMiddleCode( temporary ); ChangeOpcode( temporary ); cp = backCp; tryScopes.back().EndTry(); tryScopes.pop_back(); } void InspectTryScope() { while( tryScopes.size() > 0 ) { SetError(22, "Try", tryScopes.back().GetSourceCodePos() ); EndTryCommand( true ); } } void ThrowCommand( const char *Parameter ) { int backCp = cp; char temporary[1024]; if( Parameter[0] ) { sprintf( temporary, "_System_pobj_AllThreads->GetCurrentException()->_ThrowWithParam(%s)", Parameter ); } else { lstrcpy( temporary, "_System_pobj_AllThreads->GetCurrentException()->_ThrowNoneParam()" ); } MakeMiddleCode( temporary ); ChangeOpcode( temporary ); cp = backCp; } void Opcode_Func_System_GetNowScopeCatchAddress() { if( tryScopes.size() == 0 ) { SetError(1,NULL,cp); return; } #ifdef _WIN64 //mov rax,catchAddress const PertialSchedule *pPertialSchedule = compiler.codeGenerator.op_mov_RV( sizeof(long), REG_RAX, 0, Schedule::DataTable, true ); #else //mov eax,catchAddress const PertialSchedule *pPertialSchedule = compiler.codeGenerator.op_mov_RV( REG_EAX, 0, Schedule::DataTable, true ); #endif tryScopes.back().RegistPertialScheduleForCatchAddress( pPertialSchedule ); /* int dataTableOffset = compiler.GetObjectModule().dataTable.Add( static_cast(0) ); #ifdef _WIN64 //mov rax,dataTableOffset compiler.codeGenerator.op_mov_RV( sizeof(_int64), REG_RAX, dataTableOffset, Schedule::DataTable); #else //mov eax,dataTableOffset compiler.codeGenerator.op_mov_RV( REG_EAX, dataTableOffset, Schedule::DataTable); #endif */ } void Opcode_Func_System_GetNowScopeFinallyAddress() { if( tryScopes.size() == 0 ) { SetError(1,NULL,cp); return; } #ifdef _WIN64 //mov rax,finallyAddress const PertialSchedule *pPertialSchedule = compiler.codeGenerator.op_mov_RV( sizeof(long), REG_RAX, 0, Schedule::CatchAddress, true ); #else //mov eax,finallyAddress const PertialSchedule *pPertialSchedule = compiler.codeGenerator.op_mov_RV( REG_EAX, 0, Schedule::CatchAddress, true ); #endif tryScopes.back().RegistPertialScheduleForFinallyAddress( pPertialSchedule ); /* int dataTableOffset = compiler.GetObjectModule().dataTable.Add( static_cast(0) ); #ifdef _WIN64 //mov rax,dataTableOffset compiler.codeGenerator.op_mov_RV( sizeof(_int64), REG_RAX, dataTableOffset, Schedule::DataTable); #else //mov eax,dataTableOffset compiler.codeGenerator.op_mov_RV( REG_EAX, dataTableOffset, Schedule::DataTable); #endif */ } } // Exception