except_branchful.inc 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by Michael Van Canneyt
  4. member of the Free Pascal development team
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {****************************************************************************
  12. Exception support
  13. ****************************************************************************}
  14. {$ifdef FPC_HAS_FEATURE_THREADING}
  15. ThreadVar
  16. {$else FPC_HAS_FEATURE_THREADING}
  17. Var
  18. {$endif FPC_HAS_FEATURE_THREADING}
  19. ExceptObjectStack : PExceptObject;
  20. ExceptTryLevel : ObjpasInt;
  21. RaisedException : Boolean;
  22. {$ifdef FPC_USE_PSABIEH}
  23. {$i psabieh.inc}
  24. {$endif}
  25. function fpc_raised_exception_flag: Boolean;[public,alias:'FPC_RAISED_EXCEPTION_FLAG']compilerproc;
  26. begin
  27. result:=RaisedException;
  28. end;
  29. procedure fpc_clear_exception_flag;[public,alias:'FPC_CLEAR_EXCEPTION_FLAG']compilerproc;
  30. begin
  31. RaisedException:=false;
  32. end;
  33. Function RaiseList : PExceptObject;
  34. begin
  35. RaiseList:=ExceptObjectStack;
  36. end;
  37. function AcquireExceptionObject: Pointer;
  38. var
  39. _ExceptObjectStack : PExceptObject;
  40. begin
  41. _ExceptObjectStack:=ExceptObjectStack;
  42. If _ExceptObjectStack<>nil then
  43. begin
  44. Inc(_ExceptObjectStack^.refcount);
  45. AcquireExceptionObject := _ExceptObjectStack^.FObject;
  46. end
  47. else
  48. RunError(231);
  49. end;
  50. procedure ReleaseExceptionObject;
  51. var
  52. _ExceptObjectStack : PExceptObject;
  53. begin
  54. _ExceptObjectStack:=ExceptObjectStack;
  55. If _ExceptObjectStack <> nil then
  56. begin
  57. if _ExceptObjectStack^.refcount > 0 then
  58. Dec(_ExceptObjectStack^.refcount);
  59. end
  60. else
  61. RunError(231);
  62. end;
  63. { This routine is called only from fpc_raiseexception, which uses ExceptTryLevel
  64. flag to guard against repeated exceptions which can occur due to corrupted stack
  65. or heap. }
  66. function PushExceptObject(Obj : TObject; AnAddr : CodePointer; AFrame : Pointer): PExceptObject;
  67. var
  68. Newobj : PExceptObject;
  69. _ExceptObjectStack : ^PExceptObject;
  70. framebufsize,
  71. framecount : PtrInt;
  72. frames : PCodePointer;
  73. prev_frame,
  74. curr_frame : Pointer;
  75. curr_addr : CodePointer;
  76. begin
  77. {$ifdef excdebug}
  78. writeln ('In PushExceptObject');
  79. {$endif}
  80. _ExceptObjectStack:=@ExceptObjectStack;
  81. NewObj:=AllocMem(sizeof(TExceptObject));
  82. NewObj^.Next:=_ExceptObjectStack^;
  83. _ExceptObjectStack^:=NewObj;
  84. NewObj^.FObject:=Obj;
  85. NewObj^.Addr:=AnAddr;
  86. if assigned(get_frame) then
  87. begin
  88. NewObj^.refcount:=0;
  89. { Backtrace }
  90. curr_frame:=AFrame;
  91. curr_addr:=AnAddr;
  92. frames:=nil;
  93. framecount:=0;
  94. framebufsize:=0;
  95. { The frame pointer of this procedure is used as initial stack bottom value. }
  96. prev_frame:=get_frame;
  97. while (framecount<RaiseMaxFrameCount) and (curr_frame > prev_frame) and
  98. (curr_frame<StackTop) do
  99. Begin
  100. prev_frame:=curr_frame;
  101. get_caller_stackinfo(curr_frame,curr_addr);
  102. if (curr_addr=nil) or
  103. (curr_frame=nil) then
  104. break;
  105. if (framecount>=framebufsize) then
  106. begin
  107. inc(framebufsize,16);
  108. reallocmem(frames,framebufsize*sizeof(codepointer));
  109. end;
  110. frames[framecount]:=curr_addr;
  111. inc(framecount);
  112. End;
  113. NewObj^.framecount:=framecount;
  114. NewObj^.frames:=frames;
  115. end;
  116. Result:=NewObj;
  117. end;
  118. Procedure DoUnHandledException;[Public, Alias : 'FPC_DOUNHANDLEDEXCEPTION'];
  119. var
  120. _ExceptObjectStack : PExceptObject;
  121. begin
  122. _ExceptObjectStack:=ExceptObjectStack;
  123. If (ExceptProc<>Nil) and (_ExceptObjectStack<>Nil) then
  124. with _ExceptObjectStack^ do
  125. begin
  126. TExceptProc(ExceptProc)(FObject,Addr,FrameCount,Frames);
  127. halt(217)
  128. end;
  129. if erroraddr = nil then
  130. RunError(217)
  131. else
  132. Halt(errorcode);
  133. end;
  134. {$ifndef FPC_SYSTEM_HAS_RAISEEXCEPTION}
  135. procedure fpc_RaiseException (Obj : TObject; AnAddr : CodePointer; AFrame : Pointer);[Public, Alias : 'FPC_RAISEEXCEPTION']; compilerproc;
  136. var
  137. _ExceptObjectStack : PExceptObject;
  138. _ExceptAddrstack : PExceptAddr;
  139. begin
  140. {$ifdef excdebug}
  141. writeln ('In RaiseException');
  142. {$endif}
  143. if ExceptTryLevel<>0 then
  144. Halt(217);
  145. ExceptTryLevel:=1;
  146. PushExceptObject(Obj,AnAddr,AFrame);
  147. { if PushExceptObject causes another exception, the following won't be executed,
  148. causing halt upon entering this routine recursively. }
  149. ExceptTryLevel:=0;
  150. // _ExceptAddrstack:=ExceptAddrStack;
  151. // If _ExceptAddrStack=Nil then
  152. // DoUnhandledException;
  153. _ExceptObjectStack:=ExceptObjectStack;
  154. if (RaiseProc <> nil) and (_ExceptObjectStack <> nil) then
  155. with _ExceptObjectStack^ do
  156. RaiseProc(FObject,Addr,FrameCount,Frames);
  157. //longjmp(_ExceptAddrStack^.Buf^,FPC_Exception);
  158. //fpc_wasm32_throw_fpcexception;
  159. RaisedException:=true;
  160. end;
  161. {$endif FPC_SYSTEM_HAS_RAISEEXCEPTION}
  162. function fpc_PopObjectStack : TObject;[Public, Alias : 'FPC_POPOBJECTSTACK']; compilerproc;
  163. var
  164. hp : PExceptObject;
  165. begin
  166. {$ifdef excdebug}
  167. writeln ('In PopObjectstack');
  168. {$endif}
  169. hp:=ExceptObjectStack;
  170. if hp=nil then
  171. begin
  172. {$ifdef excdebug}
  173. writeln ('At end of ExceptionObjectStack');
  174. {$endif}
  175. halt (1);
  176. end
  177. else
  178. begin
  179. { we need to return the exception object to dispose it }
  180. if hp^.refcount = 0 then
  181. fpc_PopObjectStack:=hp^.FObject
  182. else
  183. fpc_PopObjectStack:=nil;
  184. ExceptObjectStack:=hp^.next;
  185. if assigned(hp^.frames) then
  186. freemem(hp^.frames);
  187. dispose(hp);
  188. erroraddr:=nil;
  189. end;
  190. end;
  191. { this is for popping exception objects when a second exception is risen }
  192. { in an except/on }
  193. function fpc_PopSecondObjectStack : TObject;[Public, Alias : 'FPC_POPSECONDOBJECTSTACK']; compilerproc;
  194. var
  195. hp,_ExceptObjectStack : PExceptObject;
  196. begin
  197. {$ifdef excdebug}
  198. writeln ('In PopSecondObjectstack');
  199. {$endif}
  200. _ExceptObjectStack:=ExceptObjectStack;
  201. If not(assigned(_ExceptObjectStack)) or
  202. not(assigned(_ExceptObjectStack^.next)) then
  203. begin
  204. {$ifdef excdebug}
  205. writeln ('At end of ExceptionObjectStack');
  206. {$endif}
  207. halt (1);
  208. end
  209. else
  210. begin
  211. if _ExceptObjectStack^.next^.refcount=0 then
  212. { we need to return the exception object to dispose it if refcount=0 }
  213. fpc_PopSecondObjectStack:=_ExceptObjectStack^.next^.FObject
  214. else
  215. fpc_PopSecondObjectStack:=nil;
  216. hp:=_ExceptObjectStack^.next;
  217. _ExceptObjectStack^.next:=hp^.next;
  218. if assigned(hp^.frames) then
  219. freemem(hp^.frames);
  220. dispose(hp);
  221. end;
  222. end;
  223. {$ifndef FPC_SYSTEM_HAS_RERAISE}
  224. Procedure fpc_ReRaise;[Public, Alias : 'FPC_RERAISE']; compilerproc;
  225. var
  226. _ExceptAddrStack : PExceptAddr;
  227. begin
  228. {$ifdef excdebug}
  229. writeln ('In reraise');
  230. {$endif}
  231. // _ExceptAddrStack:=ExceptAddrStack;
  232. // If _ExceptAddrStack=Nil then
  233. // DoUnHandledException;
  234. ExceptObjectStack^.refcount := 0;
  235. // longjmp(_ExceptAddrStack^.Buf^,FPC_Exception);
  236. // fpc_wasm32_throw_fpcexception;
  237. RaisedException:=true;
  238. end;
  239. {$endif FPC_SYSTEM_HAS_RERAISE}
  240. function Internal_PopSecondObjectStack : TObject; external name 'FPC_POPSECONDOBJECTSTACK';
  241. function Internal_PopObjectStack: TObject; external name 'FPC_POPOBJECTSTACK';
  242. procedure Internal_Reraise; external name 'FPC_RERAISE';
  243. Procedure fpc_ReRaise2;[Public, Alias : 'FPC_RERAISE2']; compilerproc;
  244. var
  245. Newobj : PExceptObject;
  246. _ExceptObjectStack : PExceptObject;
  247. begin
  248. {$ifdef excdebug}
  249. writeln ('In reraise2');
  250. {$endif}
  251. _ExceptObjectStack:=ExceptObjectStack;
  252. NewObj:=AllocMem(sizeof(TExceptObject));
  253. NewObj^.Next:=_ExceptObjectStack^.Next;
  254. _ExceptObjectStack^.Next:=NewObj;
  255. Internal_Reraise;
  256. end;
  257. Function fpc_Catches(Objtype : TClass) : TObject;[Public, Alias : 'FPC_CATCHES']; compilerproc;
  258. var
  259. _ExceptObjectStack : PExceptObject;
  260. begin
  261. _ExceptObjectStack:=ExceptObjectStack;
  262. If _ExceptObjectStack=Nil then
  263. begin
  264. {$ifdef excdebug}
  265. Writeln ('Internal error.');
  266. {$endif}
  267. halt (255);
  268. end;
  269. if Not ((Objtype = TClass(CatchAllExceptions)) or
  270. (_ExceptObjectStack^.FObject is ObjType)) then
  271. fpc_Catches:=Nil
  272. else
  273. begin
  274. // catch !
  275. fpc_Catches:=_ExceptObjectStack^.FObject;
  276. { this can't be done, because there could be a reraise (PFV)
  277. PopObjectStack;
  278. Also the PopAddrStack shouldn't be done, we do it now
  279. immediatly in the exception handler (FK)
  280. PopAddrStack; }
  281. end;
  282. end;
  283. Procedure SysInitExceptions;
  284. {
  285. Initialize exceptionsupport
  286. }
  287. begin
  288. RaisedException:=false;
  289. ExceptObjectstack:=Nil;
  290. end;
  291. {$ifndef FPC_SYSTEM_HAS_DONEEXCEPTION}
  292. procedure fpc_doneexception;[public,alias:'FPC_DONEEXCEPTION'] compilerproc;
  293. begin
  294. {$ifdef excdebug}
  295. Writeln('In doneexception');
  296. {$endif}
  297. Internal_PopObjectStack.Free;
  298. end;
  299. {$endif FPC_SYSTEM_HAS_DONEEXCEPTION}
  300. {$ifndef FPC_SYSTEM_HAS_RAISENESTED}
  301. procedure fpc_raise_nested;[public,alias:'FPC_RAISE_NESTED']compilerproc;
  302. begin
  303. {$ifdef excdebug}
  304. Writeln('In raise_nested');
  305. {$endif}
  306. Internal_PopSecondObjectStack.Free;
  307. Internal_Reraise;
  308. end;
  309. {$endif FPC_SYSTEM_HAS_RAISENESTED}
  310. {$ifndef FPC_SYSTEM_HAS_SAFECALLHANDLER}
  311. function fpc_safecallhandler(obj: TObject): HResult; [public,alias:'FPC_SAFECALLHANDLER']; compilerproc;
  312. var
  313. raiselist: PExceptObject;
  314. adr: CodePointer;
  315. exc: TObject;
  316. begin
  317. raiselist:=ExceptObjectStack;
  318. if Assigned(raiseList) then
  319. adr:=raiseList^.Addr
  320. else
  321. adr:=nil;
  322. exc:=Internal_PopObjectStack;
  323. if Assigned(obj) and Assigned(exc) then
  324. result:=obj.SafeCallException(exc,adr)
  325. else
  326. result:=E_UNEXPECTED;
  327. exc.Free;
  328. end;
  329. {$endif FPC_SYSTEM_HAS_SAFECALLHANDLER}