root/src/VM/cil/cilVMExceptionHandling.cpp

Revision 195, 13.0 kB (checked in by hak, 4 months ago)

Ver.0.91.0.137
- Added OSX/GCC support!
- Can compile in XCode 3.1/GCC 4.0.1 & Visual Studio 2005.
- Runs in OSX 10.5.4 & Windows XP/Vista
- Number::toString support a radix.
- BRFALSE bug fix
- Minor code clean up

Line 
1 /****************************************************************************
2  *
3  * CRI Middleware SDK
4  *
5  * Copyright (c) 2008 CRI Middleware, Inc. All rights reserved.
6  *
7  * Use, modification and distribution are subject to the CRI Script Software
8  * License, Version 1.0(see accompanying file "CriScript_License_1_0.txt" or
9  * copy at www.criscript.com/trac/wiki/CRI%20Script%20Software%20License%201.0 ).
10  *
11  *
12  * Library  : CRIScript
13  * Module   : cil Virtual Machine Exception handler
14  * File     : cilVMExceptionHandling.cpp
15  * Date     :
16  * Version  :
17  *
18  ****************************************************************************/
19
20 /***************************************************************************
21  *      Include file
22  ***************************************************************************/
23 #include "stdafx.h"
24 #include "criScript.h"
25 #include "cilVm.h"
26 namespace cri {
27 /***************************************************************************
28  *      Variables
29  ***************************************************************************/
30
31 /***************************************************************************
32  *      Throw exception operator
33  ***************************************************************************/
34 void CCilVm::ThrowOperator()
35 {
36         //Rewind the stack!!
37         VM_CALLSTACK* pHandler = getCurrentCallStack();
38         if( pHandler->status != 0 )
39         {
40                 if( pHandler->status == VM_EHCLAUSE_EXECUTING_CATCH )
41                 {
42                         //Dispose current argument
43                         disposeArgumentList( 1 );
44                         VM_CALLSTACK* pCurrentCallstack = getCurrentCallStack( VM_CALLSTACK_CALLSTACK );
45                         pCurrentCallstack->iNumArgument --;
46                 }
47
48                 //Jump to 'leave'.
49                 pHandler->status = VM_EHCLAUSE_EXECUTING_FINALLY;
50                 pHandler->ridCatch = RID_NEED_CATCHCLAUSE;
51                 m_pCurrentInstruction = pHandler->pInstruction;
52                 return;
53         }
54
55         //Look into call stack if catch clause is provided
56         vector< VM_CALLSTACK >::reverse_iterator itBegin = m_CallStack.rbegin();
57         vector< VM_CALLSTACK >::reverse_iterator itEnd = m_CallStack.rend() - 1;
58         bool bEHFound = false;
59         while( itBegin != itEnd )
60         {
61                 if( itBegin->type == VM_CALLSTACK_EH )
62                 {
63                         bEHFound = true;
64                         break; 
65                 }
66                 ++itBegin;
67         }
68
69         if( !bEHFound )
70         {
71                 //Or Exception not handled!
72                 Debug_Warning( "Unhandled exception!!\n" );
73                 if( m_Handler[ VM_HANDLER_EXCEPTIONNOTHANDLED ] )
74                 {
75                         m_Handler[ VM_HANDLER_EXCEPTIONNOTHANDLED ]( 0, &getEvalStackFirstEntry() );
76                 }
77                 else
78                 {
79                         Debug_Warning( "No default exception handler provided\n" );
80                 }
81
82                 //Pop error object
83                 popEvalStack();
84                 return;
85         }
86
87         while( pHandler->type != VM_CALLSTACK_EH )
88         {
89                 if( m_CallStack.size() == 1 )
90                 {
91                         //Or Exception not handled!
92                         Debug_Warning( "Unhandled exception!!\n" );
93                         if( m_Handler[ VM_HANDLER_EXCEPTIONNOTHANDLED ] )
94                         {
95                                 m_Handler[ VM_HANDLER_EXCEPTIONNOTHANDLED ]( 0, &getEvalStackFirstEntry() );
96                         }
97                         else
98                         {
99                                 Debug_Warning( "No default exception handler provided\n" );
100                         }
101                         return;
102                 }
103                 //Dispose local variable
104                 disposeLocalVariables( getCurrentLocalVariableIndex() - pHandler->iLocalVariableStartIndex );
105                 //Dispose arglist
106                 disposeArgumentList( pHandler->iNumArgument );
107
108                 m_CallStack.pop_back();
109
110                 pHandler = getCurrentCallStack();
111         }
112        
113         VM_CALLSTACK* pCurrentCallstack = getCurrentCallStack( VM_CALLSTACK_CALLSTACK );
114         m_iCurrentThisPointerIndex = pCurrentCallstack->iArgumentListStartIndex;
115
116         //I got EH clause
117         if( pHandler->ridCatch != 0 )
118         {
119                 assert( TypeFromToken( pHandler->ridCatch ) == MDT_METHODDEF );
120                
121                 METHOD_DEF* pMethod;
122                 pMethod = &m_MetaData.getMethod( pHandler->ridCatch );
123                 assert( MethodType( pMethod->MethodType ) == METHOD_CIL );
124
125                 //tweak arglist
126
127                 //Inc the # of arg
128                 pCurrentCallstack->iNumArgument++;
129
130                 getEvalStackFirstEntry().moveTo( m_ArgList[ m_iArgListIndex ] );
131                 updateArgListIndex();
132                 popEvalStackFast();
133                
134                 //Invoke catch clause
135                 pHandler->ridCatch = 0;
136                 pHandler->status = VM_EHCLAUSE_EXECUTING_CATCH;
137
138                 m_pCurrentInstruction = &m_CurrentILPool.ILPool[ pMethod->iILOffset ];
139
140                 //Need to store an offset of leave ops.
141                 pMethod = &m_MetaData.getMethod( pHandler->ridMethod );
142                 assert( MethodType( pMethod->MethodType ) == METHOD_EHCLAUSE );
143                 pHandler->pInstruction = &m_CurrentILPool.ILPool[ pMethod->iILOffset ];
144
145                 return;
146         }
147         else if( pHandler->ridFinally != 0 )
148         {
149                 //Does not dispose it!!
150                 //Dispose throw argument
151                 //popEvalStack();
152
153                 //Invoke finally clause
154                 assert( TypeFromToken( pHandler->ridFinally ) == MDT_METHODDEF );
155                
156                 METHOD_DEF* pMethod;
157                 pMethod = &m_MetaData.getMethod( pHandler->ridFinally );
158                 assert( MethodType( pMethod->MethodType ) == METHOD_CIL );
159                
160                 //When I back here in future, finally/catch node is already executed
161                 //Good luck
162                 pHandler->ridFinally = 0;
163                 pHandler->status = VM_EHCLAUSE_EXECUTING_FINALLY;
164                 m_pCurrentInstruction = &m_CurrentILPool.ILPool[ pMethod->iILOffset ];
165
166                 //Need to store an offset of leave ops.
167                 pMethod = &m_MetaData.getMethod( pHandler->ridMethod );
168                 assert( MethodType( pMethod->MethodType ) == METHOD_EHCLAUSE );
169                 pHandler->pInstruction = &m_CurrentILPool.ILPool[ pMethod->iILOffset ];
170
171                 //Still need to execute catch clause...
172                 pHandler->ridCatch = RID_NEED_CATCHCLAUSE;
173
174                 return;
175         }
176         else
177         {
178                 //Or Exception not handled.
179                 //It's fine by the spec
180         }
181
182         return;
183 }
184
185 /***************************************************************************
186  *      Enter operator
187  ***************************************************************************/
188 void CCilVm::EnterOperator()
189 {
190         RID tokenTarget = getNextToken();
191         assert( TypeFromToken( tokenTarget ) == MDT_METHODDEF );
192         assert( m_CallStack.size() <= MAX_CALLSTACK );
193
194         METHOD_DEF* pMethod;
195         pMethod = &m_MetaData.getMethod( tokenTarget );
196
197         VM_CALLSTACK callstack;
198         callstack.type = VM_CALLSTACK_EH;
199         callstack.pInstruction = 0;
200         callstack.status = VM_EHCLAUSE_NORMAL;
201         callstack.ridMethod = tokenTarget;
202         callstack.ridCatch = pMethod->ridCatch;
203         callstack.ridFinally = pMethod->ridFinally;
204         callstack.iNumArgument = (uint32_t)getEvalStackSize();
205         callstack.bConstructor = false;
206         m_CallStack.push_back( callstack );
207
208         //Increase exception handler level
209         m_ExceptionHandlerNestingLevel++;
210
211         return;
212 }
213
214 /***************************************************************************
215  *      Leave operator Methods
216  ***************************************************************************/
217 void CCilVm::LeaveOperator()
218 {
219         VM_CALLSTACK* pHandler = getCurrentCallStack();
220         if( pHandler->type != VM_CALLSTACK_EH )
221         {
222                 return;
223         }
224
225         //Now IP point this 'leave' ops
226         m_pCurrentInstruction--;
227
228         if( pHandler->status == VM_EHCLAUSE_EXECUTING_CATCH )
229         {
230                 //EH object
231                 disposeArgumentList( 1 );
232                 VM_CALLSTACK* pCurrentCallstack = getCurrentCallStack( VM_CALLSTACK_CALLSTACK );
233                 pCurrentCallstack->iNumArgument--;
234                
235                 //Restore instruction pointer
236                 m_pCurrentInstruction = pHandler->pInstruction;
237         }
238
239         if( pHandler->ridFinally != 0 )
240         {
241                 //Invoke finally clause
242                 assert( TypeFromToken( pHandler->ridFinally ) == MDT_METHODDEF );
243                
244                 METHOD_DEF* pMethod;
245                 pMethod = &m_MetaData.getMethod( pHandler->ridFinally );
246                 assert( MethodType( pMethod->MethodType ) == METHOD_CIL );
247                
248                 //When I back here in future, finally/catch node is already executed
249                 //Good luck
250                 if( pHandler->ridCatch != RID_NEED_CATCHCLAUSE )
251                         pHandler->ridCatch = 0;
252                 pHandler->ridFinally = 0;
253                 pHandler->status = VM_EHCLAUSE_EXECUTING_FINALLY;
254
255                 pHandler->pInstruction = m_pCurrentInstruction;
256                 m_pCurrentInstruction = &m_CurrentILPool.ILPool[ pMethod->iILOffset ];
257                 return;
258         }
259
260         if( pHandler->status == VM_EHCLAUSE_RETURNING )
261         {
262                 //Decrease exception handler level
263                 m_ExceptionHandlerNestingLevel--;
264                 //Good bye try clause
265                 m_CallStack.pop_back();
266                 RetOperator();
267                 return;
268         }
269
270         //Now I'm back from the finally clause
271         if( pHandler->pInstruction )
272         {
273                 m_pCurrentInstruction = pHandler->pInstruction;
274         }
275
276         //Now point next instruction
277         m_pCurrentInstruction++;
278
279         if( pHandler->ridCatch == RID_NEED_CATCHCLAUSE )
280         {
281                 //Decrease exception handler level
282                 m_ExceptionHandlerNestingLevel--;
283
284                 //Executed final clause however still need to seek catch clause
285                 m_CallStack.pop_back();
286
287                 ThrowOperator();
288         }
289         else
290         {
291                 if( pHandler->iNumArgument + 1 != (uint32_t)getEvalStackSize() )
292                 {
293                         //Decrease exception handler level
294                         m_ExceptionHandlerNestingLevel--;
295
296                         //Good bye try clause
297                         m_CallStack.pop_back();
298                         return;
299                 }
300                 //Decrease exception handler level
301                 m_ExceptionHandlerNestingLevel--;
302
303                 //Good bye try clause
304                 m_CallStack.pop_back();
305         }
306
307         return;
308 }
309
310 /***************************************************************************
311  *      Finally operator Methods
312  ***************************************************************************/
313 void CCilVm::FinallyOperator()
314 {
315         VM_CALLSTACK* pHandler = getCurrentCallStack();
316         if( pHandler->type != VM_CALLSTACK_EH )
317         {
318                 return;
319         }
320
321         //Now IP point this 'leave' ops
322         m_pCurrentInstruction--;
323
324         if( pHandler->status == VM_EHCLAUSE_EXECUTING_CATCH )
325         {
326                 //EH object
327                 disposeArgumentList( 1 );
328                 VM_CALLSTACK* pCurrentCallstack = getCurrentCallStack( VM_CALLSTACK_CALLSTACK );
329                 pCurrentCallstack->iNumArgument --;
330                
331         }
332
333         if( pHandler->ridFinally != 0 )
334         {
335                 //Invoke finally clause
336                 assert( TypeFromToken( pHandler->ridFinally ) == MDT_METHODDEF );
337                
338                 METHOD_DEF* pMethod;
339                 pMethod = &m_MetaData.getMethod( pHandler->ridFinally );
340                 assert( MethodType( pMethod->MethodType ) == METHOD_CIL );
341                
342                 //When I back here in future, finally/catch node is already executed
343                 //Good luck
344                 if( pHandler->ridCatch != RID_NEED_CATCHCLAUSE )
345                         pHandler->ridCatch = 0;
346                 pHandler->ridFinally = 0;
347                 pHandler->status = VM_EHCLAUSE_EXECUTING_FINALLY;
348
349                 pHandler->pInstruction = m_pCurrentInstruction;
350                 m_pCurrentInstruction = &m_CurrentILPool.ILPool[ pMethod->iILOffset ];
351                 return;
352         }
353
354         if( pHandler->status == VM_EHCLAUSE_RETURNING )
355         {
356                 //Good bye try clause
357                 m_CallStack.pop_back();
358                 RetOperator();
359                 return;
360         }
361
362         //Now point next instruction
363         m_pCurrentInstruction++;
364        
365         //Good bye try clause
366         m_CallStack.pop_back();
367
368         return;
369 }
370
371 /***************************************************************************
372  *      Throw an exception from the API
373  *      Exposed API
374  ***************************************************************************/
375 void CCilVm::throwException( CVariable* pvarError )
376 {
377         pushEvalStack( *pvarError );
378         disposeArgumentList( m_iNumGivenArguments );
379         ThrowOperator();
380         m_iNumGivenArguments = 0;
381         return;
382 }
383
384 /***************************************************************************
385  *      Throw an exception
386  ***************************************************************************/
387 void CCilVm::throwException( wstring* pstrMessage, wstring* pstrName, int32_t iNumber )
388 {
389         CVariable obj;
390
391         CVmObject* pObj = createObject( m_ridErrorObject );
392         obj.setObjectRef( pObj );
393
394         //Set prototype: String prototype object
395         obj.refObject->setPrototypeObject(
396                 &getPrototypeObject( m_ridErrorObject ) );
397
398         CVariable var( pstrMessage, OPERAND_FLAG( OPERAND_FLAG_READONLY | OPERAND_FLAG_DONTENUM | OPERAND_FLAG_DONTDELETE ) );
399         obj.refObject->setProperty( NAME_BUILTIN_ERROR_PROPERTY_MESSAGE, var );
400        
401         if( pstrName != NULL )
402         {
403                 CVariable varString( pstrName,
404                                                         OPERAND_FLAG( OPERAND_FLAG_READONLY | OPERAND_FLAG_DONTENUM | OPERAND_FLAG_DONTDELETE ) );
405                 obj.refObject->setProperty( NAME_BUILTIN_ERROR_PROPERTY_NAME, varString );
406         }
407         CVariable varInt( iNumber,
408                                          OPERAND_FLAG( OPERAND_FLAG_READONLY | OPERAND_FLAG_DONTENUM | OPERAND_FLAG_DONTDELETE ) );
409         obj.refObject->setProperty( NAME_BUILTIN_ERROR_PROPERTY_NUMBER, varInt );
410
411         //Push the ObjectRef to a eval stack
412         pushEvalStackVariable( obj );
413
414         disposeArgumentList( m_iNumGivenArguments );
415
416         ////Current instruction index is decremented in the ThrowOperator for throw instruction to keep IP of throw.
417         ////However since this routine is called from inside a VM, it does not have to be adjusted
418         //m_pCurrentInstruction++;
419         ThrowOperator();
420         m_iNumGivenArguments = 0;
421         return;
422 }
423
424 /***************************************************************************
425  *      Throw an exception from inside the VM
426  ***************************************************************************/
427 void CCilVm::ThrowExceptionFromVm( wstring* pstrMessage, wstring* pstrName, int32_t iNumber )
428 {
429         CVariable obj;
430
431         CVmObject* pObj = createObject( m_ridErrorObject );
432         obj.setObjectRef( pObj );
433
434         //Set prototype: String prototype object
435         obj.refObject->setPrototypeObject(
436                 &getPrototypeObject( m_ridErrorObject ) );
437
438         CVariable var( pstrMessage, OPERAND_FLAG( OPERAND_FLAG_READONLY | OPERAND_FLAG_DONTENUM | OPERAND_FLAG_DONTDELETE ) );
439         obj.refObject->setProperty( NAME_BUILTIN_ERROR_PROPERTY_MESSAGE, var );
440        
441         if( pstrName != NULL )
442         {
443                 CVariable varString( pstrName,
444                                                         OPERAND_FLAG( OPERAND_FLAG_READONLY | OPERAND_FLAG_DONTENUM | OPERAND_FLAG_DONTDELETE ) );
445                 obj.refObject->setProperty( NAME_BUILTIN_ERROR_PROPERTY_NAME, varString );
446         }
447
448         CVariable varInt( iNumber,
449                                          OPERAND_FLAG( OPERAND_FLAG_READONLY | OPERAND_FLAG_DONTENUM | OPERAND_FLAG_DONTDELETE ) );
450         obj.refObject->setProperty( NAME_BUILTIN_ERROR_PROPERTY_NUMBER, varInt );
451
452         //Push the ObjectRef to a eval stack
453         pushEvalStackVariable( obj );
454
455         //Does not dispose argument since those are not disposed after the throw call
456         ThrowOperator();
457         return;
458 }
459
460 } //namespace CRI
Note: See TracBrowser for help on using the browser.