PageRenderTime 28ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/nuitka/build/include/nuitka/exceptions.hpp

https://bitbucket.org/pombredanne/nuitka
C++ Header | 468 lines | 338 code | 106 blank | 24 comment | 28 complexity | 5425eaee04ded97d9928283ab7f99a17 MD5 | raw file
  1. // Copyright 2013, Kay Hayen, mailto:kay.hayen@gmail.com
  2. //
  3. // Part of "Nuitka", an optimizing Python compiler that is compatible and
  4. // integrates with CPython, but also works on its own.
  5. //
  6. // Licensed under the Apache License, Version 2.0 (the "License");
  7. // you may not use this file except in compliance with the License.
  8. // You may obtain a copy of the License at
  9. //
  10. // http://www.apache.org/licenses/LICENSE-2.0
  11. //
  12. // Unless required by applicable law or agreed to in writing, software
  13. // distributed under the License is distributed on an "AS IS" BASIS,
  14. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. // See the License for the specific language governing permissions and
  16. // limitations under the License.
  17. //
  18. #ifndef __NUITKA_EXCEPTIONS_H__
  19. #define __NUITKA_EXCEPTIONS_H__
  20. static bool ERROR_OCCURED( void )
  21. {
  22. PyThreadState *tstate = PyThreadState_GET();
  23. return tstate->curexc_type != NULL;
  24. }
  25. NUITKA_MAY_BE_UNUSED static PyObject *GET_ERROR_OCCURED( void )
  26. {
  27. PyThreadState *tstate = PyThreadState_GET();
  28. return tstate->curexc_type;
  29. }
  30. #if PYTHON_VERSION < 300
  31. NUITKA_MAY_BE_UNUSED static void dumpTraceback( PyTracebackObject *traceback )
  32. {
  33. puts( "Dumping traceback:" );
  34. if ( traceback == NULL ) puts( "<NULL traceback?!>" );
  35. while( traceback )
  36. {
  37. puts( " Frame object chain:" );
  38. PyFrameObject *frame = traceback->tb_frame;
  39. while ( frame )
  40. {
  41. printf( " Frame at %s\n", PyString_AsString( PyObject_Str( (PyObject *)frame->f_code )));
  42. frame = frame->f_back;
  43. }
  44. traceback = traceback->tb_next;
  45. }
  46. puts( "End of Dump." );
  47. }
  48. #endif
  49. NUITKA_MAY_BE_UNUSED static PyTracebackObject *INCREASE_REFCOUNT( PyTracebackObject *traceback_object )
  50. {
  51. Py_INCREF( traceback_object );
  52. return traceback_object;
  53. }
  54. NUITKA_MAY_BE_UNUSED static PyTracebackObject *INCREASE_REFCOUNT_X( PyTracebackObject *traceback_object )
  55. {
  56. Py_XINCREF( traceback_object );
  57. return traceback_object;
  58. }
  59. NUITKA_MAY_BE_UNUSED static PyTracebackObject *MAKE_TRACEBACK( PyFrameObject *frame )
  60. {
  61. // assertFrameObject( frame );
  62. PyTracebackObject *result = PyObject_GC_New( PyTracebackObject, &PyTraceBack_Type );
  63. result->tb_next = NULL;
  64. result->tb_frame = frame;
  65. result->tb_lasti = 0;
  66. result->tb_lineno = frame->f_lineno;
  67. Nuitka_GC_Track( result );
  68. return result;
  69. }
  70. extern PyObject *_python_str_plain_exc_type, *_python_str_plain_exc_value, *_python_str_plain_exc_traceback;
  71. // Helper that sets the current thread exception, releasing the current one, for use in this
  72. // file only.
  73. inline void _SET_CURRENT_EXCEPTION( PyObject *exception_type, PyObject *exception_value, PyTracebackObject *exception_tb )
  74. {
  75. PyThreadState *thread_state = PyThreadState_GET();
  76. PyObject *old_type = thread_state->exc_type;
  77. PyObject *old_value = thread_state->exc_value;
  78. PyObject *old_tb = thread_state->exc_traceback;
  79. thread_state->exc_type = INCREASE_REFCOUNT_X( exception_type );
  80. thread_state->exc_value = INCREASE_REFCOUNT_X( exception_value );
  81. thread_state->exc_traceback = (PyObject *)INCREASE_REFCOUNT_X( exception_tb );
  82. Py_XDECREF( old_type );
  83. Py_XDECREF( old_value );
  84. Py_XDECREF( old_tb );
  85. // Set sys attributes in the fastest possible way.
  86. PyObject *sys_dict = thread_state->interp->sysdict;
  87. assertObject( sys_dict );
  88. PyDict_SetItem( sys_dict, _python_str_plain_exc_type, exception_type ? exception_type : Py_None );
  89. PyDict_SetItem( sys_dict, _python_str_plain_exc_value, exception_value ? exception_value : Py_None );
  90. PyDict_SetItem( sys_dict, _python_str_plain_exc_traceback, exception_tb ? (PyObject *)exception_tb : Py_None );
  91. }
  92. inline void NORMALIZE_EXCEPTION( PyObject **exception_type, PyObject **exception_value, PyTracebackObject **exception_tb )
  93. {
  94. PyErr_NormalizeException( exception_type, exception_value, (PyObject **)exception_tb );
  95. }
  96. class PythonException
  97. {
  98. public:
  99. PythonException()
  100. {
  101. this->_importFromPython();
  102. }
  103. PythonException( PyObject *exception )
  104. {
  105. assertObject( exception );
  106. Py_INCREF( exception );
  107. this->exception_type = exception;
  108. this->exception_value = NULL;
  109. this->exception_tb = NULL;
  110. }
  111. PythonException( PyObject *exception, PyTracebackObject *traceback )
  112. {
  113. assertObject( exception );
  114. assertObject( traceback );
  115. this->exception_type = exception;
  116. this->exception_value = NULL;
  117. this->exception_tb = traceback;
  118. }
  119. PythonException( PyObject *exception, PyObject *value, PyTracebackObject *traceback )
  120. {
  121. assertObject( exception );
  122. assert( value == NULL || Py_REFCNT( value ) > 0 );
  123. assert( traceback == NULL || Py_REFCNT( traceback ) > 0 );
  124. this->exception_type = exception;
  125. this->exception_value = value;
  126. this->exception_tb = traceback;
  127. }
  128. PythonException( const PythonException &other )
  129. {
  130. this->exception_type = other.exception_type;
  131. this->exception_value = other.exception_value;
  132. this->exception_tb = other.exception_tb;
  133. Py_XINCREF( this->exception_type );
  134. Py_XINCREF( this->exception_value );
  135. Py_XINCREF( this->exception_tb );
  136. }
  137. void operator=( const PythonException &other )
  138. {
  139. Py_XINCREF( other.exception_type );
  140. Py_XINCREF( other.exception_value );
  141. Py_XINCREF( other.exception_tb );
  142. Py_XDECREF( this->exception_type );
  143. Py_XDECREF( this->exception_value );
  144. Py_XDECREF( this->exception_tb );
  145. this->exception_type = other.exception_type;
  146. this->exception_value = other.exception_value;
  147. this->exception_tb = other.exception_tb;
  148. }
  149. ~PythonException()
  150. {
  151. Py_XDECREF( this->exception_type );
  152. Py_XDECREF( this->exception_value );
  153. Py_XDECREF( this->exception_tb );
  154. }
  155. inline void _importFromPython()
  156. {
  157. PyErr_Fetch( &this->exception_type, &this->exception_value, (PyObject **)&this->exception_tb );
  158. assertObject( this->exception_type );
  159. }
  160. inline void normalize()
  161. {
  162. NORMALIZE_EXCEPTION( &this->exception_type, &this->exception_value, &this->exception_tb );
  163. #if PYTHON_VERSION >= 300
  164. PyException_SetTraceback( this->exception_value, (PyObject *)this->exception_tb );
  165. #endif
  166. }
  167. inline bool matches( PyObject *exception ) const
  168. {
  169. #if PYTHON_VERSION >= 300
  170. if ( PyTuple_Check( exception ))
  171. {
  172. Py_ssize_t length = PyTuple_Size( exception );
  173. for ( Py_ssize_t i = 0; i < length; i += 1 )
  174. {
  175. PyObject *element = PyTuple_GET_ITEM( exception, i );
  176. if (unlikely( !PyExceptionClass_Check( element ) ))
  177. {
  178. PyErr_Format( PyExc_TypeError, "catching classes that do not inherit from BaseException is not allowed" );
  179. throw PythonException();
  180. }
  181. }
  182. }
  183. else if (unlikely( !PyExceptionClass_Check( exception ) ))
  184. {
  185. PyErr_Format( PyExc_TypeError, "catching classes that do not inherit from BaseException is not allowed" );
  186. throw PythonException();
  187. }
  188. #endif
  189. return
  190. PyErr_GivenExceptionMatches( this->exception_type, exception ) ||
  191. PyErr_GivenExceptionMatches( this->exception_value, exception );
  192. }
  193. inline void toPython()
  194. {
  195. PyErr_Restore( this->exception_type, this->exception_value, (PyObject *)this->exception_tb );
  196. assert( this->exception_type );
  197. #ifndef __NUITKA_NO_ASSERT__
  198. PyThreadState *thread_state = PyThreadState_GET();
  199. #endif
  200. assert( this->exception_type == thread_state->curexc_type );
  201. assert( thread_state->curexc_type );
  202. this->exception_type = NULL;
  203. this->exception_value = NULL;
  204. this->exception_tb = NULL;
  205. }
  206. inline void toExceptionHandler()
  207. {
  208. this->normalize();
  209. _SET_CURRENT_EXCEPTION( this->exception_type, this->exception_value, this->exception_tb );
  210. }
  211. inline PyObject *getType()
  212. {
  213. if ( this->exception_value == NULL )
  214. {
  215. this->normalize();
  216. }
  217. return this->exception_type;
  218. }
  219. inline PyObject *getValue()
  220. {
  221. if ( this->exception_value == NULL )
  222. {
  223. this->normalize();
  224. }
  225. return this->exception_value;
  226. }
  227. inline PyTracebackObject *getTraceback() const
  228. {
  229. return (PyTracebackObject *)this->exception_tb;
  230. }
  231. inline void addTraceback( PyFrameObject *frame )
  232. {
  233. assert( this->exception_tb );
  234. #if 0
  235. printf( "addTraceback %p %s %p %s %d %d\n", exception_tb->tb_frame, PyString_AsString( exception_tb->tb_frame->f_code->co_name ), frame, PyString_AsString( frame->f_code->co_name ), this->exception_tb->tb_lineno, frame->f_lineno );
  236. #endif
  237. if ( this->exception_tb->tb_frame != frame || this->exception_tb->tb_lineno != frame->f_lineno )
  238. {
  239. Py_INCREF( frame );
  240. PyTracebackObject *traceback_new = MAKE_TRACEBACK( frame );
  241. traceback_new->tb_next = this->exception_tb;
  242. this->exception_tb = traceback_new;
  243. }
  244. }
  245. inline void setTraceback( PyTracebackObject *traceback )
  246. {
  247. assert( traceback == NULL || Py_REFCNT( traceback ) > 0 );
  248. PyTracebackObject *old = this->exception_tb;
  249. this->exception_tb = traceback;
  250. Py_XDECREF( old );
  251. }
  252. inline bool hasTraceback() const
  253. {
  254. return this->exception_tb != NULL;
  255. }
  256. void setType( PyObject *exception_type )
  257. {
  258. Py_XDECREF( this->exception_type );
  259. this->exception_type = exception_type;
  260. }
  261. #if PYTHON_VERSION >= 300
  262. void setCause( PyObject *exception_cause )
  263. {
  264. PyException_SetCause( this->exception_value, exception_cause );
  265. }
  266. #endif
  267. void dump() const
  268. {
  269. PRINT_ITEM_TO( NULL, this->exception_type );
  270. }
  271. private:
  272. friend class PythonExceptionKeeper;
  273. // For the restore of saved ones.
  274. PythonException( PyObject *exception, PyObject *value, PyObject *traceback )
  275. {
  276. this->exception_type = exception;
  277. this->exception_value = value;
  278. this->exception_tb = (PyTracebackObject *)traceback;
  279. }
  280. PyObject *exception_type, *exception_value;
  281. PyTracebackObject *exception_tb;
  282. };
  283. class PythonExceptionKeeper
  284. {
  285. public:
  286. PythonExceptionKeeper()
  287. {
  288. this->keeping = false;
  289. #ifndef __NUITKA_NO_ASSERT__
  290. this->exception_type = NULL;
  291. this->exception_value = NULL;
  292. this->exception_tb = NULL;
  293. #endif
  294. }
  295. ~PythonExceptionKeeper()
  296. {
  297. if ( this->keeping )
  298. {
  299. Py_XDECREF( this->exception_type );
  300. Py_XDECREF( this->exception_value );
  301. Py_XDECREF( this->exception_tb );
  302. }
  303. }
  304. void save( const PythonException &e )
  305. {
  306. this->exception_type = INCREASE_REFCOUNT_X( e.exception_type );
  307. this->exception_value = INCREASE_REFCOUNT_X( e.exception_value );
  308. this->exception_tb = INCREASE_REFCOUNT_X( e.exception_tb );
  309. this->keeping = true;
  310. }
  311. void rethrow()
  312. {
  313. if ( this->keeping )
  314. {
  315. Py_XINCREF( this->exception_type );
  316. Py_XINCREF( this->exception_value );
  317. Py_XINCREF( this->exception_tb );
  318. // Restore the frame line number from the traceback, if present. Otherwise it
  319. // will changed already.
  320. if ( this->exception_tb )
  321. {
  322. this->exception_tb->tb_frame->f_lineno = this->exception_tb->tb_lineno;
  323. }
  324. throw PythonException( this->exception_type, this->exception_value, this->exception_tb );
  325. }
  326. }
  327. bool isEmpty() const
  328. {
  329. return !this->keeping;
  330. }
  331. private:
  332. bool keeping;
  333. PyObject *exception_type, *exception_value;
  334. PyTracebackObject *exception_tb;
  335. };
  336. class ContinueException
  337. {
  338. };
  339. class BreakException
  340. {
  341. };
  342. class ReturnValueException
  343. {
  344. public:
  345. explicit ReturnValueException( PyObject *value )
  346. {
  347. assertObject( value );
  348. this->value = value;
  349. }
  350. ~ReturnValueException()
  351. {
  352. assertObject( value );
  353. Py_DECREF( this->value );
  354. }
  355. PyObject *getValue() const
  356. {
  357. return INCREASE_REFCOUNT( this->value );
  358. }
  359. private:
  360. PyObject *value;
  361. };
  362. #endif