source: dev/trunk/ab5.0/abdev/BasicCompiler_Common/src/Exception.cpp @ 537

Last change on this file since 537 was 537, checked in by dai_9181, 15 years ago

UserProcクラスによるコンパイル中関数管理用メソッドを除去(すべてCompilerクラス内で処理するようにした)。

File size: 10.9 KB
Line 
1#include "stdafx.h"
2
3#ifdef _AMD64_
4#include "../../compiler_x64/opcode.h"
5#else
6#include "../../compiler_x86/opcode.h"
7#endif
8
9namespace Exception{
10
11class CatchScope
12{
13    Type paramType;
14    long codePos;
15public:
16    CatchScope( const Type &paramType, long codePos )
17        : paramType( paramType )
18        , codePos( codePos )
19    {
20    }
21    ~CatchScope()
22    {
23    }
24
25    const Type &GetParamType() const
26    {
27        return paramType;
28    }
29    long GetCodePos() const
30    {
31        return codePos;
32    }
33};
34typedef std::vector<CatchScope> CatchScopes;
35
36class TryScope
37{
38    int sourceCodePos;
39    bool isDefinedFinally;
40
41    CatchScopes catchScopes;
42
43    std::vector<const PertialSchedule *> finallySchedules;
44    void JmpFinally()
45    {
46        finallySchedules.push_back(
47            compiler.codeGenerator.op_jmp( 0, sizeof(long), true )
48        );
49    }
50    void ResolveJmpFinally()
51    {
52        BOOST_FOREACH( const PertialSchedule *pPertialSchedule, finallySchedules )
53        {
54            compiler.codeGenerator.opfix_JmpPertialSchedule( pPertialSchedule );
55        }
56    }
57
58    const PertialSchedule *pPertialScheduleForCatchAddress;
59    const PertialSchedule *pPertialScheduleForFinallyAddress;
60
61public:
62    TryScope( int sourceCodePos )
63        : sourceCodePos( sourceCodePos )
64        , isDefinedFinally( false )
65    {
66    }
67    ~TryScope()
68    {
69    }
70
71    int GetSourceCodePos() const
72    {
73        return sourceCodePos;
74    }
75    const CatchScopes &GetCatchScopes() const
76    {
77        return catchScopes;
78    }
79    bool IsCatched() const
80    {
81        return ( catchScopes.size() != 0 );
82    }
83    bool IsDefinedFinally() const
84    {
85        return isDefinedFinally;
86    }
87
88    void RegistPertialScheduleForCatchAddress( const PertialSchedule *pPertialScheduleForCatchAddress )
89    {
90        this->pPertialScheduleForCatchAddress = pPertialScheduleForCatchAddress;
91    }
92    const PertialSchedule *GetPertialScheduleForCatchAddress() const
93    {
94        return pPertialScheduleForCatchAddress;
95    }
96    void RegistPertialScheduleForFinallyAddress( const PertialSchedule *pPertialScheduleForFinallyAddress )
97    {
98        this->pPertialScheduleForFinallyAddress = pPertialScheduleForFinallyAddress;
99    }
100    const PertialSchedule *GetPertialScheduleForFinallyAddress() const
101    {
102        return pPertialScheduleForFinallyAddress;
103    }
104   
105   
106
107    void Try()
108    {
109        // レキシカルスコープをレベルアップ
110        compiler.codeGenerator.lexicalScopes.Start(
111            compiler.codeGenerator.GetNativeCodeSize(),
112            LexicalScope::SCOPE_TRY
113        );
114    }
115
116    void Catch( Type &paramType )
117    {
118        if( isDefinedFinally )
119        {
120            compiler.errorMessenger.Output(71,NULL,cp);
121            return;
122        }
123
124        if( catchScopes.size() )
125        {
126            // 既に1回以上のCatchが存在するとき
127
128            // レキシカルスコープをレベルダウン
129            compiler.codeGenerator.lexicalScopes.End();
130        }
131
132        JmpFinally();
133
134        catchScopes.push_back( CatchScope( paramType, compiler.codeGenerator.GetNativeCodeSize() ) );
135
136        // レキシカルスコープをレベルアップ
137        compiler.codeGenerator.lexicalScopes.Start(
138            compiler.codeGenerator.GetNativeCodeSize(),
139            LexicalScope::SCOPE_CATCH
140        );
141    }
142    void Finally()
143    {
144        if( isDefinedFinally )
145        {
146            compiler.errorMessenger.Output(70,NULL,cp);
147            return;
148        }
149
150        if( catchScopes.size() )
151        {
152            // 既に1回以上のCatchが存在するとき
153
154            // レキシカルスコープをレベルダウン
155            compiler.codeGenerator.lexicalScopes.End();
156        }
157
158        isDefinedFinally = true;
159
160        ResolveJmpFinally();
161
162        // レキシカルスコープをレベルアップ
163        compiler.codeGenerator.lexicalScopes.Start(
164            compiler.codeGenerator.GetNativeCodeSize(),
165            LexicalScope::SCOPE_FINALLY
166        );
167    }
168
169    void EndTry()
170    {
171        if( !isDefinedFinally )
172        {
173            compiler.errorMessenger.OutputFatalError();
174        }
175
176        if( catchScopes.size() || isDefinedFinally )
177        {
178            // 既に1回以上のCatch、またはFinallyが存在するとき
179
180            // レキシカルスコープをレベルダウン
181            compiler.codeGenerator.lexicalScopes.End();
182        }
183
184        // レキシカルスコープをレベルダウン
185        compiler.codeGenerator.lexicalScopes.End();
186    }
187
188    int GenerateCatchTable()
189    {
190        int size = static_cast<int>(( (catchScopes.size()+1)*2 ) * sizeof(LONG_PTR));
191        BYTE *buffer = (BYTE *)calloc( size, 1 );
192
193        int pos = 0;
194        BOOST_FOREACH( const CatchScope &catchScope, catchScopes )
195        {
196            // パラメータのクラス名
197            char paramName[VN_SIZE] = "";
198            int paramNameDataTableOffset = 0;
199            if( catchScope.GetParamType().IsObject() )
200            {
201                lstrcpy( paramName, catchScope.GetParamType().GetClass().GetFullName().c_str() );
202            }
203            paramNameDataTableOffset = compiler.GetObjectModule().dataTable.AddString( paramName );
204            *((LONG_PTR *)(buffer+pos)) = paramNameDataTableOffset;
205            pos += sizeof(LONG_PTR);
206
207            // Catchアドレス
208            *((LONG_PTR *)(buffer+pos)) = catchScope.GetCodePos();
209            pos += sizeof(LONG_PTR);
210        }
211
212        int dataTableOffset = compiler.GetObjectModule().dataTable.AddBinary( buffer, size );
213
214        free( buffer );
215
216        pos = 0;
217        BOOST_FOREACH( const CatchScope &catchScope, catchScopes )
218        {
219            // パラメータのクラス名
220            compiler.GetObjectModule().dataTable.schedules.push_back( Schedule( Schedule::DataTable, dataTableOffset + pos ) );
221            pos += sizeof(LONG_PTR);
222
223            // Catchアドレス
224            const UserProc *pUserProc = &compiler.GetCompilingUserProc();
225            if( compiler.IsGlobalAreaCompiling() )
226            {
227                pUserProc = UserProc::pGlobalProc;
228            }
229            compiler.GetObjectModule().dataTable.schedules.push_back( Schedule( pUserProc, dataTableOffset + pos ) );
230            compiler.GetObjectModule().dataTable.schedules.back().SpecifyCatchAddress();
231            pos += sizeof(LONG_PTR);
232        }
233
234        return dataTableOffset;
235    }
236};
237typedef std::vector<TryScope> TryScopes;
238
239TryScopes tryScopes;
240
241void TryCommand()
242{
243    tryScopes.push_back( TryScope( cp ) );
244    tryScopes.back().Try();
245
246    int backCp = cp;
247
248    char temporary[1024];
249    lstrcpy( temporary, "ExceptionService.BeginTryScope( _System_GetNowScopeCatchAddresses() As VoidPtr, _System_GetNowScopeFinallyAddresses() As VoidPtr, _System_GetBp() As LONG_PTR, _System_GetSp() As LONG_PTR )" );
250    MakeMiddleCode( temporary );
251    ChangeOpcode( temporary );
252
253    cp = backCp;
254}
255void CatchCommand( const char *parameter )
256{
257    if( tryScopes.size() == 0 )
258    {
259        compiler.errorMessenger.Output(1,NULL,cp);
260        return;
261    }
262
263    char varName[VN_SIZE];
264    Type paramType;
265    if( parameter[0] )
266    {
267        char typeName[VN_SIZE];
268        SplitSyntacticForAs( parameter, varName, typeName );
269        if( !typeName[0] )
270        {
271            compiler.errorMessenger.Output(72,NULL,cp);
272        }
273        else
274        {
275            if( !compiler.StringToType( typeName, paramType ) )
276            {
277                compiler.errorMessenger.Output(74,typeName,cp);
278            }
279            else
280            {
281                if( !paramType.IsObject() )
282                {
283                    compiler.errorMessenger.Output(73,typeName,cp);
284                }
285            }
286        }
287    }
288
289    tryScopes.back().Catch( paramType );
290
291    int backCp = cp;
292
293    char temporary[1024];
294    if( paramType.IsObject() )
295    {
296        sprintf( temporary, "Dim %s = System.Threading.Thread.CurrentThread().__GetThrowintParamObject() As %s", varName, paramType.GetClass().GetFullName().c_str() );
297        MakeMiddleCode( temporary );
298        ChangeOpcode( temporary );
299    }
300    lstrcpy( temporary, "System.Threading.Thread.CurrentThread().__Catched()" );
301    MakeMiddleCode( temporary );
302    ChangeOpcode( temporary );
303
304    cp = backCp;
305}
306void FinallyCommand()
307{
308    tryScopes.back().Finally();
309
310    int backCp = cp;
311
312    char temporary[1024];
313    lstrcpy( temporary, "_System_pobj_AllThreads->GetCurrentException()->FinishFinally()" );
314    MakeMiddleCode( temporary );
315    ChangeOpcode( temporary );
316
317    cp = backCp;
318
319    //Tryスコープに入るときに引き渡されるパラメータ値を解決
320    compiler.codeGenerator.opfix( tryScopes.back().GetPertialScheduleForFinallyAddress(), compiler.codeGenerator.GetNativeCodeSize() );
321}
322void EndTryCommand( bool isNoWarning )
323{
324    if( tryScopes.size() == 0 )
325    {
326        compiler.errorMessenger.Output(12,"End Try",cp);
327        return;
328    }
329
330    if( !isNoWarning && !tryScopes.back().IsDefinedFinally() && !tryScopes.back().IsCatched() )
331    {
332        // CatchもFinallyも存在しないとき
333        compiler.errorMessenger.Output(-108,NULL,tryScopes.back().GetSourceCodePos() );
334    }
335
336    int dataTableOffset = tryScopes.back().GenerateCatchTable();
337
338    // _System_GetNowScopeCatchAddressesを解決
339    compiler.codeGenerator.opfix( tryScopes.back().GetPertialScheduleForCatchAddress(), dataTableOffset );
340
341    if( !tryScopes.back().IsDefinedFinally() )
342    {
343        // Finallyが定義されていないときは空のFinallyを定義しておく
344        FinallyCommand();
345    }
346
347    int backCp = cp;
348
349    char temporary[1024];
350    lstrcpy( temporary, "_System_pobj_AllThreads->GetCurrentException()->EndTryScope()" );
351    MakeMiddleCode( temporary );
352    ChangeOpcode( temporary );
353
354    cp = backCp;
355
356    tryScopes.back().EndTry();
357    tryScopes.pop_back();
358}
359
360void InspectTryScope()
361{
362    while( tryScopes.size() > 0 )
363    {
364        compiler.errorMessenger.Output(22, "Try", tryScopes.back().GetSourceCodePos() );
365
366        EndTryCommand( true );
367    }
368}
369
370void ThrowCommand( const char *Parameter )
371{
372    int backCp = cp;
373
374    char temporary[1024];
375    if( Parameter[0] )
376    {
377        sprintf( temporary, "_System_pobj_AllThreads->GetCurrentException()->_ThrowWithParam(%s)", Parameter );
378    }
379    else
380    {
381        lstrcpy( temporary, "_System_pobj_AllThreads->GetCurrentException()->_ThrowNoneParam()" );
382    }
383    MakeMiddleCode( temporary );
384    ChangeOpcode( temporary );
385
386    cp = backCp;
387}
388
389void Opcode_Func_System_GetNowScopeCatchAddress()
390{
391    if( tryScopes.size() == 0 )
392    {
393        compiler.errorMessenger.Output(1,NULL,cp);
394        return;
395    }
396
397#ifdef _WIN64
398    //mov rax,catchAddress
399    const PertialSchedule *pPertialSchedule = compiler.codeGenerator.op_mov_RV( sizeof(long), REG_RAX, 0, Schedule::DataTable, true );
400#else
401    //mov eax,catchAddress
402    const PertialSchedule *pPertialSchedule = compiler.codeGenerator.op_mov_RV( REG_EAX, 0, Schedule::DataTable, true );
403#endif
404
405    tryScopes.back().RegistPertialScheduleForCatchAddress( pPertialSchedule );
406
407    /*
408    int dataTableOffset = compiler.GetObjectModule().dataTable.Add( static_cast<LONG_PTR>(0) );
409
410#ifdef _WIN64
411    //mov rax,dataTableOffset
412    compiler.codeGenerator.op_mov_RV( sizeof(_int64), REG_RAX, dataTableOffset, Schedule::DataTable);
413#else
414    //mov eax,dataTableOffset
415    compiler.codeGenerator.op_mov_RV( REG_EAX, dataTableOffset, Schedule::DataTable);
416#endif
417    */
418}
419
420void Opcode_Func_System_GetNowScopeFinallyAddress()
421{
422    if( tryScopes.size() == 0 )
423    {
424        compiler.errorMessenger.Output(1,NULL,cp);
425        return;
426    }
427
428#ifdef _WIN64
429    //mov rax,finallyAddress
430    const PertialSchedule *pPertialSchedule = compiler.codeGenerator.op_mov_RV( sizeof(long), REG_RAX, 0, Schedule::CatchAddress, true );
431#else
432    //mov eax,finallyAddress
433    const PertialSchedule *pPertialSchedule = compiler.codeGenerator.op_mov_RV( REG_EAX, 0, Schedule::CatchAddress, true );
434#endif
435
436    tryScopes.back().RegistPertialScheduleForFinallyAddress( pPertialSchedule );
437
438    /*
439    int dataTableOffset = compiler.GetObjectModule().dataTable.Add( static_cast<LONG_PTR>(0) );
440
441#ifdef _WIN64
442    //mov rax,dataTableOffset
443    compiler.codeGenerator.op_mov_RV( sizeof(_int64), REG_RAX, dataTableOffset, Schedule::DataTable);
444#else
445    //mov eax,dataTableOffset
446    compiler.codeGenerator.op_mov_RV( REG_EAX, dataTableOffset, Schedule::DataTable);
447#endif
448    */
449}
450
451
452}   // Exception
Note: See TracBrowser for help on using the repository browser.