source: dev/trunk/abdev/BasicCompiler_Common/src/Exception.cpp @ 365

Last change on this file since 365 was 365, checked in by dai_9181, 16 years ago

32ビットコンパイラでグローバル領域のTryスコープが正常にコンパイルできないバグを修正。
Catch、Finally節を持たないTryスコープを警告の対象とした。

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