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

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

Throw→Catch間のパラメータ引渡しに対応。
グローバル領域でのTryスコープを可能にした。これで例外処理機構実装完了。
エディタの補間機能にTry/Catch/Finally/EndTryを追加。

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