{
    Copyright (c) 2011 by Free Pascal development team

    Generate Win32-specific exception handling code

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

 ****************************************************************************
}
unit n386flw;

{$i fpcdefs.inc}

interface

  uses
    node,nflw,ncgflw,psub;

  type
    ti386raisenode=class(tcgraisenode)
      function pass_1 : tnode;override;
    end;

    ti386onnode=class(tcgonnode)
      procedure pass_generate_code;override;
    end;

    ti386tryexceptnode=class(tcgtryexceptnode)
      procedure pass_generate_code;override;
    end;

    ti386tryfinallynode=class(tcgtryfinallynode)
      finalizepi: tcgprocinfo;
      constructor create(l,r:TNode);override;
      constructor create_implicit(l,r:TNode);override;
      function pass_1: tnode;override;
	  function dogetcopy : tnode;override;
      function simplify(forinline: boolean): tnode;override;
      procedure pass_generate_code;override;
    end;

implementation

  uses
    cutils,globtype,globals,verbose,systems,
    nbas,ncal,nmem,nutils,
    symconst,symbase,symtable,symsym,symdef,
    cgbase,cgobj,cgcpu,cgutils,tgobj,
    cpubase,htypechk,
    parabase,paramgr,pass_1,pass_2,ncgutil,cga,
    aasmbase,aasmtai,aasmdata,aasmcpu,procinfo,cpupi,procdefutil;

  var
    endexceptlabel: tasmlabel;


{ ti386raisenode }

function ti386raisenode.pass_1 : tnode;
  var
    statements : tstatementnode;
    raisenode : tcallnode;
  begin
    { difference from generic code is that address stack is not popped on reraise }
    if (target_info.system<>system_i386_win32) or assigned(left) then
      result:=inherited pass_1
    else
      begin
        result:=internalstatements(statements);
        raisenode:=ccallnode.createintern('fpc_reraise',nil);
        include(raisenode.callnodeflags,cnf_call_never_returns);
        addstatement(statements,raisenode);
      end;
end;

{ ti386onnode }

procedure ti386onnode.pass_generate_code;
  var
    oldflowcontrol : tflowcontrol;
    exceptvarsym : tlocalvarsym;
  begin
    if (target_info.system<>system_i386_win32) then
      begin
        inherited pass_generate_code;
        exit;
      end;

    location_reset(location,LOC_VOID,OS_NO);

    oldflowcontrol:=flowcontrol;
    flowcontrol:=[fc_inflowcontrol];

    { RTL will put exceptobject into EAX when jumping here }
    cg.a_reg_alloc(current_asmdata.CurrAsmList,NR_FUNCTION_RESULT_REG);

    { Retrieve exception variable }
    if assigned(excepTSymtable) then
      exceptvarsym:=tlocalvarsym(excepTSymtable.SymList[0])
    else
      exceptvarsym:=nil;

    if assigned(exceptvarsym) then
      begin
        exceptvarsym.localloc.loc:=LOC_REFERENCE;
        exceptvarsym.localloc.size:=OS_ADDR;
        tg.GetLocal(current_asmdata.CurrAsmList,sizeof(pint),voidpointertype,exceptvarsym.localloc.reference);
        cg.a_load_reg_ref(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,NR_FUNCTION_RESULT_REG,exceptvarsym.localloc.reference);
      end;
    cg.a_reg_dealloc(current_asmdata.CurrAsmList,NR_FUNCTION_RESULT_REG);

    if assigned(right) then
      secondpass(right);

    { deallocate exception symbol }
    if assigned(exceptvarsym) then
      begin
        tg.UngetLocal(current_asmdata.CurrAsmList,exceptvarsym.localloc.reference);
        exceptvarsym.localloc.loc:=LOC_INVALID;
      end;
    cg.g_call(current_asmdata.CurrAsmList,'FPC_DONEEXCEPTION');
    cg.a_jmp_always(current_asmdata.CurrAsmList,endexceptlabel);

    flowcontrol:=oldflowcontrol+(flowcontrol-[fc_inflowcontrol]);
  end;

{ ti386tryfinallynode }

function reset_regvars(var n: tnode; arg: pointer): foreachnoderesult;
  begin
    case n.nodetype of
      temprefn:
        make_not_regable(n,[]);
      calln:
        include(tprocinfo(arg).flags,pi_do_call);
      else ;
    end;
    result:=fen_true;
  end;

function copy_parasize(var n: tnode; arg: pointer): foreachnoderesult;
  begin
    if n.nodetype=calln then
        tcgprocinfo(arg).allocate_push_parasize(tcallnode(n).pushed_parasize);
    result:=fen_true;
  end;

constructor ti386tryfinallynode.create(l, r: TNode);
  begin
    inherited create(l,r);
    if (target_info.system<>system_i386_win32) or
      { Don't create child procedures for generic methods, their nested-like
        behavior causes compilation errors because real nested procedures
        aren't allowed for generics. Not creating them doesn't harm because
        generic node tree is discarded without generating code. }
      (df_generic in current_procinfo.procdef.defoptions)
      then
      exit;
    finalizepi:=tcgprocinfo(current_procinfo.create_for_outlining('$fin$',current_procinfo.procdef.struct,potype_exceptfilter,voidtype,r));
    { Regvar optimization for symbols is suppressed when using exceptions, but
      temps may be still placed into registers. This must be fixed. }
    foreachnodestatic(r,@reset_regvars,finalizepi);
    include(finalizepi.flags,pi_has_assembler_block);
    include(finalizepi.flags,pi_do_call);
    include(finalizepi.flags,pi_uses_exceptions);
  end;

constructor ti386tryfinallynode.create_implicit(l, r: TNode);
  begin
    inherited create_implicit(l, r);
    if (target_info.system<>system_i386_win32) then
      exit;

    { safecall procedures can handle implicit finalization as part of "except" flow }
    if implicitframe and (current_procinfo.procdef.proccalloption=pocall_safecall) then
      exit;

    if df_generic in current_procinfo.procdef.defoptions then
      InternalError(2013012501);

    finalizepi:=tcgprocinfo(current_procinfo.create_for_outlining('$fin$',current_procinfo.procdef.struct,potype_exceptfilter,voidtype,r));
    include(finalizepi.flags,pi_has_assembler_block);
    include(finalizepi.flags,pi_do_call);
    include(finalizepi.flags,pi_uses_exceptions);
  end;


function ti386tryfinallynode.pass_1: tnode;
  var
    selfsym: tparavarsym;
  begin
    result:=inherited pass_1;
    if (target_info.system=system_i386_win32) then
      begin
        { safecall method will access 'self' from except block -> make it non-regable }
        if implicitframe and (current_procinfo.procdef.proccalloption=pocall_safecall) and
          is_class(current_procinfo.procdef.struct) then
          begin
            selfsym:=tparavarsym(current_procinfo.procdef.parast.Find('self'));
            if (selfsym=nil) or (selfsym.typ<>paravarsym) then
              InternalError(2011123101);
            selfsym.varregable:=vr_none;
          end;
      end;
  end;

function ti386tryfinallynode.dogetcopy: tnode;
  var
    n: ti386tryfinallynode;
  begin
	n:=ti386tryfinallynode(inherited dogetcopy);
	if target_info.system=system_i386_win32 then
	  begin
	    n.finalizepi:=tcgprocinfo(cprocinfo.create(finalizepi.parent));
		n.finalizepi.force_nested;
		n.finalizepi.procdef:=create_outline_procdef('$fin$',current_procinfo.procdef.struct,potype_exceptfilter,voidtype);
		n.finalizepi.entrypos:=finalizepi.entrypos;
		n.finalizepi.entryswitches:=finalizepi.entryswitches;
		n.finalizepi.exitpos:=finalizepi.exitpos;
		n.finalizepi.exitswitches:=finalizepi.exitswitches;
		n.finalizepi.flags:=finalizepi.flags;
		{ node already transformed? }
		if assigned(finalizepi.code) then
		  begin
			n.finalizepi.code:=finalizepi.code.getcopy;
			n.right:=ccallnode.create(nil,tprocsym(n.finalizepi.procdef.procsym),nil,nil,[],nil);
		  end;
	  end;
	result:=n;
  end;

function ti386tryfinallynode.simplify(forinline: boolean): tnode;
  begin
    result:=inherited simplify(forinline);
    if (target_info.system<>system_i386_win32) then
      exit;

    { actually, this is not really the right place to do a node transformation like this }
    if (result=nil) and assigned(finalizepi) and (not(assigned(finalizepi.code))) then
      begin
        finalizepi.code:=right;
        foreachnodestatic(right,@copy_parasize,finalizepi);
        right:=ccallnode.create(nil,tprocsym(finalizepi.procdef.procsym),nil,nil,[],nil);
        firstpass(right);
        { For implicit frames, no actual code is available at this time,
          it is added later in assembler form. So store the nested procinfo
          for later use. }
        if implicitframe then
          begin
            current_procinfo.finalize_procinfo:=finalizepi;
            { don't leave dangling pointer }
            tcgprocinfo(current_procinfo).final_asmnode:=nil;
          end;
      end;
  end;


procedure emit_scope_start(handler,data: TAsmSymbol);
  var
    href: treference;
    hreg: tregister;
  begin
    hreg:=cg.getintregister(current_asmdata.CurrAsmList,OS_ADDR);
    reference_reset_base(href,hreg,0,ctempposinvalid,sizeof(pint),[]);
    href.segment:=NR_FS;
    emit_reg_reg(A_XOR,S_L,hreg,hreg);
    emit_sym(A_PUSH,S_L,data);
    emit_reg(A_PUSH,S_L,NR_FRAME_POINTER_REG);
    emit_sym(A_PUSH,S_L,handler);
    emit_ref(A_PUSH,S_L,href);
    emit_reg_ref(A_MOV,S_L,NR_ESP,href);
  end;

procedure emit_scope_end;
  var
    href: treference;
    hreg,hreg2: tregister;
  begin
    hreg:=cg.getintregister(current_asmdata.CurrAsmList,OS_ADDR);
    hreg2:=cg.getintregister(current_asmdata.CurrAsmList,OS_ADDR);
    reference_reset_base(href,hreg,0,ctempposinvalid,sizeof(pint),[]);
    href.segment:=NR_FS;
    emit_reg_reg(A_XOR,S_L,hreg,hreg);
    emit_reg(A_POP,S_L,hreg2);
    emit_const_reg(A_ADD,S_L,3*sizeof(pint),NR_ESP);
    emit_reg_ref(A_MOV,S_L,hreg2,href);
  end;

procedure ti386tryfinallynode.pass_generate_code;
  var
    finallylabel,
    exceptlabel,
    safecalllabel,
    endfinallylabel,
    exitfinallylabel,
    continuefinallylabel,
    breakfinallylabel,
    oldCurrExitLabel,
    oldContinueLabel,
    oldBreakLabel : tasmlabel;
    oldflowcontrol,tryflowcontrol : tflowcontrol;
    is_safecall: boolean;
    hreg: tregister;
  begin
    if (target_info.system<>system_i386_win32) then
      begin
        inherited pass_generate_code;
        exit;
      end;
    location_reset(location,LOC_VOID,OS_NO);
    tryflowcontrol:=[];
    oldBreakLabel:=nil;
    oldContinueLabel:=nil;
    continuefinallylabel:=nil;
    breakfinallylabel:=nil;
    exceptlabel:=nil;
    safecalllabel:=nil;
    hreg:=NR_NO;
    is_safecall:=implicitframe and (current_procinfo.procdef.proccalloption=pocall_safecall);

    { check if child nodes do a break/continue/exit }
    oldflowcontrol:=flowcontrol;
    flowcontrol:=[fc_inflowcontrol];
    current_asmdata.getjumplabel(finallylabel);
    current_asmdata.getjumplabel(endfinallylabel);

    { the finally block must catch break, continue and exit }
    { statements                                            }
    oldCurrExitLabel:=current_procinfo.CurrExitLabel;
    if implicitframe then
      exitfinallylabel:=finallylabel
    else
      current_asmdata.getjumplabel(exitfinallylabel);
    current_procinfo.CurrExitLabel:=exitfinallylabel;
    if assigned(current_procinfo.CurrBreakLabel) then
      begin
        oldContinueLabel:=current_procinfo.CurrContinueLabel;
        oldBreakLabel:=current_procinfo.CurrBreakLabel;
        if implicitframe then
          begin
            breakfinallylabel:=finallylabel;
            continuefinallylabel:=finallylabel;
          end
        else
          begin
            current_asmdata.getjumplabel(breakfinallylabel);
            current_asmdata.getjumplabel(continuefinallylabel);
          end;
        current_procinfo.CurrContinueLabel:=continuefinallylabel;
        current_procinfo.CurrBreakLabel:=breakfinallylabel;
      end;

    { Start of scope }
    if is_safecall then
      begin
        with cg.rg[R_INTREGISTER] do
          used_in_proc:=used_in_proc+[RS_EBX,RS_ESI,RS_EDI];

        current_asmdata.getjumplabel(exceptlabel);
        emit_scope_start(
          current_asmdata.RefAsmSymbol('__FPC_except_safecall',AT_FUNCTION),
          exceptlabel
        );
      end
    else
      emit_scope_start(
        current_asmdata.RefAsmSymbol('__FPC_finally_handler',AT_FUNCTION),
        current_asmdata.RefAsmSymbol(finalizepi.procdef.mangledname,AT_FUNCTION)
      );

    { try code }
    if assigned(left) then
      begin
        secondpass(left);
        tryflowcontrol:=flowcontrol;
        if codegenerror then
          exit;
      end;

    { don't generate line info for internal cleanup }
    current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));

    cg.a_label(current_asmdata.CurrAsmList,finallylabel);
    emit_scope_end;
    if is_safecall then
      begin
        current_asmdata.getjumplabel(safecalllabel);
        hreg:=cg.GetIntRegister(current_asmdata.CurrAsmList,OS_INT);
        cg.a_load_const_reg(current_asmdata.CurrAsmList,OS_INT,0,hreg);
        cg.a_jmp_always(current_asmdata.CurrAsmList,safecalllabel);
        { RTL handler will jump here on exception }
        cg.a_label(current_asmdata.CurrAsmList,exceptlabel);
        handle_safecall_exception;
        cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_INT,OS_INT,NR_FUNCTION_RESULT_REG,hreg);
        cg.a_label(current_asmdata.CurrAsmList,safecalllabel);
      end;

    { end cleanup }
    current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));

    { generate finally code as a separate procedure }
    { !!! this resets flowcontrol, how to check flow away? }
    if not implicitframe then
      tcgprocinfo(current_procinfo).generate_exceptfilter(finalizepi);

    flowcontrol:=[fc_inflowcontrol];
    { right is a call to finalizer procedure }
    secondpass(right);

    { goto is allowed if it stays inside the finally block,
      this is checked using the exception block number }
    if (flowcontrol-[fc_gotolabel])<>[fc_inflowcontrol] then
      CGMessage(cg_e_control_flow_outside_finally);
    if codegenerror then
      exit;

    { don't generate line info for internal cleanup }
    current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));

    if not implicitframe then
      begin
        if tryflowcontrol*[fc_exit,fc_break,fc_continue]<>[] then
          cg.a_jmp_always(current_asmdata.CurrAsmList,endfinallylabel);
        { do some magic for exit,break,continue in the try block }
        if fc_exit in tryflowcontrol then
          begin
            cg.a_label(current_asmdata.CurrAsmList,exitfinallylabel);
            cg.g_call(current_asmdata.CurrAsmList,'_FPC_leave');
            cg.a_jmp_always(current_asmdata.CurrAsmList,oldCurrExitLabel);
          end;
        if fc_break in tryflowcontrol then
          begin
            cg.a_label(current_asmdata.CurrAsmList,breakfinallylabel);
            cg.g_call(current_asmdata.CurrAsmList,'_FPC_leave');
            cg.a_jmp_always(current_asmdata.CurrAsmList,oldBreakLabel);
          end;
        if fc_continue in tryflowcontrol then
          begin
            cg.a_label(current_asmdata.CurrAsmList,continuefinallylabel);
            cg.g_call(current_asmdata.CurrAsmList,'_FPC_leave');
            cg.a_jmp_always(current_asmdata.CurrAsmList,oldContinueLabel);
          end;
      end;
    if is_safecall then
      cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_INT,OS_INT,hreg,NR_FUNCTION_RETURN_REG);
    cg.a_label(current_asmdata.CurrAsmList,endfinallylabel);

    { end cleanup }
    current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));

    current_procinfo.CurrExitLabel:=oldCurrExitLabel;
    if assigned(current_procinfo.CurrBreakLabel) then
      begin
        current_procinfo.CurrContinueLabel:=oldContinueLabel;
        current_procinfo.CurrBreakLabel:=oldBreakLabel;
      end;
    flowcontrol:=oldflowcontrol+(tryflowcontrol-[fc_inflowcontrol]);
  end;

{ ti386tryexceptnode }

procedure ti386tryexceptnode.pass_generate_code;
  var
    exceptlabel,oldendexceptlabel,
    lastonlabel,
    exitexceptlabel,
    continueexceptlabel,
    breakexceptlabel,
    exittrylabel,
    continuetrylabel,
    breaktrylabel,
    oldCurrExitLabel,
    oldContinueLabel,
    oldBreakLabel : tasmlabel;
    onlabel,
    filterlabel: tasmlabel;
    oldflowcontrol,tryflowcontrol,
    exceptflowcontrol : tflowcontrol;
    hnode : tnode;
    hlist : tasmlist;
    onnodecount : tai_const;
  label
    errorexit;
  begin
    if (target_info.system<>system_i386_win32) then
      begin
        inherited pass_generate_code;
        exit;
      end;
    location_reset(location,LOC_VOID,OS_NO);

    exceptflowcontrol:=[];
    breakexceptlabel:=nil;
    continueexceptlabel:=nil;
    breaktrylabel:=nil;
    continuetrylabel:=nil;

    oldflowcontrol:=flowcontrol;
    flowcontrol:=[fc_inflowcontrol];
    { this can be called recursivly }
    oldBreakLabel:=nil;
    oldContinueLabel:=nil;
    oldendexceptlabel:=endexceptlabel;

    { Win32 SEH unwinding does not preserve registers. Indicate that they are
      going to be destroyed. }
    cg.alloccpuregisters(current_asmdata.CurrAsmList,R_INTREGISTER,[RS_EAX,RS_EBX,RS_ECX,RS_EDX,RS_ESI,RS_EDI]);
    cg.dealloccpuregisters(current_asmdata.CurrAsmList,R_INTREGISTER,[RS_EAX,RS_EBX,RS_ECX,RS_EDX,RS_ESI,RS_EDI]);

    { save the old labels for control flow statements }
    oldCurrExitLabel:=current_procinfo.CurrExitLabel;
    if assigned(current_procinfo.CurrBreakLabel) then
      begin
        oldContinueLabel:=current_procinfo.CurrContinueLabel;
        oldBreakLabel:=current_procinfo.CurrBreakLabel;
      end;

    { get new labels for the control flow statements }
    current_asmdata.getjumplabel(exittrylabel);
    current_asmdata.getjumplabel(exitexceptlabel);
    if assigned(current_procinfo.CurrBreakLabel) then
      begin
        current_asmdata.getjumplabel(breaktrylabel);
        current_asmdata.getjumplabel(continuetrylabel);
        current_asmdata.getjumplabel(breakexceptlabel);
        current_asmdata.getjumplabel(continueexceptlabel);
      end;

    current_asmdata.getjumplabel(exceptlabel);
    current_asmdata.getjumplabel(endexceptlabel);
    current_asmdata.getjumplabel(lastonlabel);
    filterlabel:=nil;

    { start of scope }
    if assigned(right) then
      begin
        current_asmdata.getaddrlabel(filterlabel);
        emit_scope_start(
          current_asmdata.RefAsmSymbol('__FPC_on_handler',AT_FUNCTION),
          filterlabel);
      end
    else
      emit_scope_start(
        current_asmdata.RefAsmSymbol('__FPC_except_handler',AT_FUNCTION),
        exceptlabel);

    { set control flow labels for the try block }
    current_procinfo.CurrExitLabel:=exittrylabel;
    if assigned(oldBreakLabel) then
      begin
        current_procinfo.CurrContinueLabel:=continuetrylabel;
        current_procinfo.CurrBreakLabel:=breaktrylabel;
      end;

    secondpass(left);
    tryflowcontrol:=flowcontrol;
    if codegenerror then
      goto errorexit;

    emit_scope_end;
    { jump over except handlers }
    cg.a_jmp_always(current_asmdata.CurrAsmList,endexceptlabel);

    if fc_exit in tryflowcontrol then
      begin
        cg.a_label(current_asmdata.CurrAsmList,exittrylabel);
        emit_scope_end;
        cg.a_jmp_always(current_asmdata.CurrAsmList,oldCurrExitLabel);
      end;
    if fc_break in tryflowcontrol then
      begin
        cg.a_label(current_asmdata.CurrAsmList,breaktrylabel);
        emit_scope_end;
        cg.a_jmp_always(current_asmdata.CurrAsmList,oldBreakLabel);
      end;
    if fc_continue in tryflowcontrol then
      begin
        cg.a_label(current_asmdata.CurrAsmList,continuetrylabel);
        emit_scope_end;
        cg.a_jmp_always(current_asmdata.CurrAsmList,oldContinueLabel);
      end;

    { target for catch-all handler }
    cg.a_label(current_asmdata.CurrAsmList,exceptlabel);

    { set control flow labels for the except block }
    { and the on statements                        }
    current_procinfo.CurrExitLabel:=exitexceptlabel;
    if assigned(oldBreakLabel) then
      begin
        current_procinfo.CurrContinueLabel:=continueexceptlabel;
        current_procinfo.CurrBreakLabel:=breakexceptlabel;
      end;

    flowcontrol:=[fc_inflowcontrol];
    { on statements }
    if assigned(right) then
      begin
        { emit filter table to a temporary asmlist }
        hlist:=TAsmList.Create;
        new_section(hlist,sec_rodata,filterlabel.name,4);
        cg.a_label(hlist,filterlabel);
        onnodecount:=tai_const.create_32bit(0);
        hlist.concat(onnodecount);

        hnode:=right;
        while assigned(hnode) do
          begin
            if hnode.nodetype<>onn then
              InternalError(2011103101);
            current_asmdata.getjumplabel(onlabel);
            hlist.concat(tai_const.create_sym(current_asmdata.RefAsmSymbol(tonnode(hnode).excepttype.vmt_mangledname,AT_DATA)));
            hlist.concat(tai_const.create_sym(onlabel));
            cg.a_label(current_asmdata.CurrAsmList,onlabel);
            secondpass(hnode);
            inc(onnodecount.value);
            hnode:=tonnode(hnode).left;
          end;
        { add 'else' node to the filter list, too }
        if assigned(t1) then
          begin
            hlist.concat(tai_const.create_32bit(-1));
            hlist.concat(tai_const.create_sym(lastonlabel));
            inc(onnodecount.value);
          end;
        { now move filter table to permanent list all at once }
        current_procinfo.aktlocaldata.concatlist(hlist);
        hlist.free;
      end;

    cg.a_label(current_asmdata.CurrAsmList,lastonlabel);
    if assigned(t1) then
      begin
        { here we don't have to reset flowcontrol           }
        { the default and on flowcontrols are handled equal }
        secondpass(t1);
        cg.g_call(current_asmdata.CurrAsmList,'FPC_DONEEXCEPTION');
        if (flowcontrol*[fc_exit,fc_break,fc_continue]<>[]) then
          cg.a_jmp_always(current_asmdata.CurrAsmList,endexceptlabel);
      end;
    exceptflowcontrol:=flowcontrol;

    if fc_exit in exceptflowcontrol then
      begin
        { do some magic for exit in the try block }
        cg.a_label(current_asmdata.CurrAsmList,exitexceptlabel);
        cg.g_call(current_asmdata.CurrAsmList,'FPC_DONEEXCEPTION');
        cg.a_jmp_always(current_asmdata.CurrAsmList,oldCurrExitLabel);
      end;

    if fc_break in exceptflowcontrol then
      begin
        cg.a_label(current_asmdata.CurrAsmList,breakexceptlabel);
        cg.g_call(current_asmdata.CurrAsmList,'FPC_DONEEXCEPTION');
        cg.a_jmp_always(current_asmdata.CurrAsmList,oldBreakLabel);
      end;

    if fc_continue in exceptflowcontrol then
      begin
        cg.a_label(current_asmdata.CurrAsmList,continueexceptlabel);
        cg.g_call(current_asmdata.CurrAsmList,'FPC_DONEEXCEPTION');
        cg.a_jmp_always(current_asmdata.CurrAsmList,oldContinueLabel);
      end;

    cg.a_label(current_asmdata.CurrAsmList,endexceptlabel);

errorexit:
    { restore all saved labels }
    endexceptlabel:=oldendexceptlabel;

    { restore the control flow labels }
    current_procinfo.CurrExitLabel:=oldCurrExitLabel;
    if assigned(oldBreakLabel) then
      begin
        current_procinfo.CurrContinueLabel:=oldContinueLabel;
        current_procinfo.CurrBreakLabel:=oldBreakLabel;
      end;

    { return all used control flow statements }
    flowcontrol:=oldflowcontrol+(exceptflowcontrol +
      tryflowcontrol - [fc_inflowcontrol]);
  end;

initialization
  craisenode:=ti386raisenode;
  connode:=ti386onnode;
  ctryexceptnode:=ti386tryexceptnode;
  ctryfinallynode:=ti386tryfinallynode;
end.
