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

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

DataTable::AddWStringメソッドを追加。

File size: 11.0 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            if( compiler.IsUnicode() )
204            {
205                paramNameDataTableOffset = compiler.GetObjectModule().dataTable.AddWString( Jenga::Common::ToWString( paramName ) );
206            }
207            else
208            {
209                paramNameDataTableOffset = compiler.GetObjectModule().dataTable.AddString( paramName );
210            }
211            *((LONG_PTR *)(buffer+pos)) = paramNameDataTableOffset;
212            pos += sizeof(LONG_PTR);
213
214            // Catchアドレス
215            *((LONG_PTR *)(buffer+pos)) = catchScope.GetCodePos();
216            pos += sizeof(LONG_PTR);
217        }
218
219        int dataTableOffset = compiler.GetObjectModule().dataTable.AddBinary( buffer, size );
220
221        free( buffer );
222
223        pos = 0;
224        BOOST_FOREACH( const CatchScope &catchScope, catchScopes )
225        {
226            // パラメータのクラス名
227            compiler.GetObjectModule().dataTable.schedules.push_back( Schedule( Schedule::DataTable, dataTableOffset + pos ) );
228            pos += sizeof(LONG_PTR);
229
230            // Catchアドレス
231            const UserProc *pUserProc = &compiler.GetCompilingUserProc();
232            if( compiler.IsGlobalAreaCompiling() )
233            {
234                pUserProc = UserProc::pGlobalProc;
235            }
236            compiler.GetObjectModule().dataTable.schedules.push_back(
237                Schedule( Schedule::CatchAddress, pUserProc, dataTableOffset + pos )
238            );
239            pos += sizeof(LONG_PTR);
240        }
241
242        return dataTableOffset;
243    }
244};
245typedef std::vector<TryScope> TryScopes;
246
247TryScopes tryScopes;
248
249void TryCommand()
250{
251    tryScopes.push_back( TryScope( cp ) );
252    tryScopes.back().Try();
253
254    int backCp = cp;
255
256    char temporary[1024];
257    lstrcpy( temporary, "ExceptionService.BeginTryScope( _System_GetNowScopeCatchAddresses() As VoidPtr, _System_GetNowScopeFinallyAddresses() As VoidPtr, _System_GetBp() As LONG_PTR, _System_GetSp() As LONG_PTR )" );
258    MakeMiddleCode( temporary );
259    ChangeOpcode( temporary );
260
261    cp = backCp;
262}
263void CatchCommand( const char *parameter )
264{
265    if( tryScopes.size() == 0 )
266    {
267        compiler.errorMessenger.Output(1,NULL,cp);
268        return;
269    }
270
271    char varName[VN_SIZE];
272    Type paramType;
273    if( parameter[0] )
274    {
275        char typeName[VN_SIZE];
276        SplitSyntacticForAs( parameter, varName, typeName );
277        if( !typeName[0] )
278        {
279            compiler.errorMessenger.Output(72,NULL,cp);
280        }
281        else
282        {
283            if( !compiler.StringToType( typeName, paramType ) )
284            {
285                compiler.errorMessenger.Output(74,typeName,cp);
286            }
287            else
288            {
289                if( !paramType.IsObject() )
290                {
291                    compiler.errorMessenger.Output(73,typeName,cp);
292                }
293            }
294        }
295    }
296
297    tryScopes.back().Catch( paramType );
298
299    int backCp = cp;
300
301    char temporary[1024];
302    if( paramType.IsObject() )
303    {
304        sprintf( temporary, "Dim %s = System.Threading.Thread.CurrentThread().__GetThrowintParamObject() As %s", varName, paramType.GetClass().GetFullName().c_str() );
305        MakeMiddleCode( temporary );
306        ChangeOpcode( temporary );
307    }
308    lstrcpy( temporary, "System.Threading.Thread.CurrentThread().__Catched()" );
309    MakeMiddleCode( temporary );
310    ChangeOpcode( temporary );
311
312    cp = backCp;
313}
314void FinallyCommand()
315{
316    tryScopes.back().Finally();
317
318    int backCp = cp;
319
320    char temporary[1024];
321    lstrcpy( temporary, "_System_pobj_AllThreads->GetCurrentException()->FinishFinally()" );
322    MakeMiddleCode( temporary );
323    ChangeOpcode( temporary );
324
325    cp = backCp;
326
327    //Tryスコープに入るときに引き渡されるパラメータ値を解決
328    compiler.codeGenerator.opfix( tryScopes.back().GetPertialScheduleForFinallyAddress(), compiler.codeGenerator.GetNativeCodeSize() );
329}
330void EndTryCommand( bool isNoWarning )
331{
332    if( tryScopes.size() == 0 )
333    {
334        compiler.errorMessenger.Output(12,"End Try",cp);
335        return;
336    }
337
338    if( !isNoWarning && !tryScopes.back().IsDefinedFinally() && !tryScopes.back().IsCatched() )
339    {
340        // CatchもFinallyも存在しないとき
341        compiler.errorMessenger.Output(-108,NULL,tryScopes.back().GetSourceCodePos() );
342    }
343
344    int dataTableOffset = tryScopes.back().GenerateCatchTable();
345
346    // _System_GetNowScopeCatchAddressesを解決
347    compiler.codeGenerator.opfix( tryScopes.back().GetPertialScheduleForCatchAddress(), dataTableOffset );
348
349    if( !tryScopes.back().IsDefinedFinally() )
350    {
351        // Finallyが定義されていないときは空のFinallyを定義しておく
352        FinallyCommand();
353    }
354
355    int backCp = cp;
356
357    char temporary[1024];
358    lstrcpy( temporary, "_System_pobj_AllThreads->GetCurrentException()->EndTryScope()" );
359    MakeMiddleCode( temporary );
360    ChangeOpcode( temporary );
361
362    cp = backCp;
363
364    tryScopes.back().EndTry();
365    tryScopes.pop_back();
366}
367
368void InspectTryScope()
369{
370    while( tryScopes.size() > 0 )
371    {
372        compiler.errorMessenger.Output(22, "Try", tryScopes.back().GetSourceCodePos() );
373
374        EndTryCommand( true );
375    }
376}
377
378void ThrowCommand( const char *Parameter )
379{
380    int backCp = cp;
381
382    char temporary[1024];
383    if( Parameter[0] )
384    {
385        sprintf( temporary, "_System_pobj_AllThreads->GetCurrentException()->_ThrowWithParam(%s)", Parameter );
386    }
387    else
388    {
389        lstrcpy( temporary, "_System_pobj_AllThreads->GetCurrentException()->_ThrowNoneParam()" );
390    }
391    MakeMiddleCode( temporary );
392    ChangeOpcode( temporary );
393
394    cp = backCp;
395}
396
397void Opcode_Func_System_GetNowScopeCatchAddress()
398{
399    if( tryScopes.size() == 0 )
400    {
401        compiler.errorMessenger.Output(1,NULL,cp);
402        return;
403    }
404
405#ifdef _WIN64
406    //mov rax,catchAddress
407    const PertialSchedule *pPertialSchedule = compiler.codeGenerator.op_mov_RV( sizeof(long), REG_RAX, 0, Schedule::DataTable, true );
408#else
409    //mov eax,catchAddress
410    const PertialSchedule *pPertialSchedule = compiler.codeGenerator.op_mov_RV( REG_EAX, 0, Schedule::DataTable, true );
411#endif
412
413    tryScopes.back().RegistPertialScheduleForCatchAddress( pPertialSchedule );
414
415    /*
416    int dataTableOffset = compiler.GetObjectModule().dataTable.Add( static_cast<LONG_PTR>(0) );
417
418#ifdef _WIN64
419    //mov rax,dataTableOffset
420    compiler.codeGenerator.op_mov_RV( sizeof(_int64), REG_RAX, dataTableOffset, Schedule::DataTable);
421#else
422    //mov eax,dataTableOffset
423    compiler.codeGenerator.op_mov_RV( REG_EAX, dataTableOffset, Schedule::DataTable);
424#endif
425    */
426}
427
428void Opcode_Func_System_GetNowScopeFinallyAddress()
429{
430    if( tryScopes.size() == 0 )
431    {
432        compiler.errorMessenger.Output(1,NULL,cp);
433        return;
434    }
435
436#ifdef _WIN64
437    //mov rax,finallyAddress
438    const PertialSchedule *pPertialSchedule = compiler.codeGenerator.op_mov_RV( sizeof(long), REG_RAX, 0, Schedule::CatchAddress, true );
439#else
440    //mov eax,finallyAddress
441    const PertialSchedule *pPertialSchedule = compiler.codeGenerator.op_mov_RV( REG_EAX, 0, Schedule::CatchAddress, true );
442#endif
443
444    tryScopes.back().RegistPertialScheduleForFinallyAddress( pPertialSchedule );
445
446    /*
447    int dataTableOffset = compiler.GetObjectModule().dataTable.Add( static_cast<LONG_PTR>(0) );
448
449#ifdef _WIN64
450    //mov rax,dataTableOffset
451    compiler.codeGenerator.op_mov_RV( sizeof(_int64), REG_RAX, dataTableOffset, Schedule::DataTable);
452#else
453    //mov eax,dataTableOffset
454    compiler.codeGenerator.op_mov_RV( REG_EAX, dataTableOffset, Schedule::DataTable);
455#endif
456    */
457}
458
459
460}   // Exception
Note: See TracBrowser for help on using the repository browser.