GCC-3.4.6源代码学习笔记(68)

来源:互联网 发布:js函数注释规范 编辑:程序博客网 时间:2024/05/16 18:25

4.3.2. 构建异常上下文

cxx_init返回,在下面的lang_dependent_init中,init_asm_output为输出汇编代码准备好了文件。

 

lang_dependent_init (continue)

 

4535   init_asm_output (name);

4536

4537  /* These create various _DECL nodes, so need to be called after the

4538     front end is initialized.  */

4539   init_eh ();

 

在配置gcc时,我们可以使用--enable-sjlj-exceptions,强制编译器使用基于C库函数setjmplongjmp的异常处理机制。这是比较旧的异常处理设施,新的芯片现在会考虑异常处理的需求,比如提供专用的寄存器等。因此,如果不是强制要求使用setjmp/longjmp,编译器会自己判断是否需要setjmp/longjmp

 

146  #ifndef MUST_USE_SJLJ_EXCEPTIONS                                                   in except.h

147  # if !(defined (EH_RETURN_DATA_REGNO)                 /

148         && (defined (IA64_UNWIND_INFO)                 /

149             || (DWARF2_UNWIND_INFO                     /

150              && (defined (EH_RETURN_HANDLER_RTX)       /

151                   || defined (HAVE_eh_return)))))

152  #  define MUST_USE_SJLJ_EXCEPTIONS     1

153  # else

154  #  define MUST_USE_SJLJ_EXCEPTIONS     0

155  # endif

156  #endif

 

上面的EH_RETURN_DATA_REGNO(N)是一个C表达式,其值是第N个可用于异常句柄的寄存器的编号,如果适用寄存器少于N则是INVALID_REGNUM(为~0)。对于x86机器,是0~1编号的寄存器(即AXDX)。而IA64_UNWIND_INFO只为ia64芯片定义。

 

282  #if !defined (DWARF2_UNWIND_INFO) && defined (INCOMING_RETURN_ADDR_RTX)

283  #define DWARF2_UNWIND_INFO 1

284  #endif

 

INCOMING_RETURN_ADDR_RTX是一个C表达式,其值是,表示在任意函数开头,在其序幕(prologue)前,所传入返回值的位置的RTL对象。对于x86,这个位置在栈上,该宏有定义。而EH_RETURN_HANDLER_RTX,如果有定义,则是一个C表达式,其值是表示保存我们应该返回的异常处理句柄(即catch语句)的位置的RTL对象。x86没有定义该宏,但在配置阶段定义了HAVE_eh_return

因而对于x86MUST_USE_SJLJ_EXCEPTIONS0,即可以不使用setjmp/longjmp

 

158  #ifdef CONFIG_SJLJ_EXCEPTIONS                                                          in except.h

159  # if CONFIG_SJLJ_EXCEPTIONS == 1

160  #  define USING_SJLJ_EXCEPTIONS            1

161  # endif

162  # if CONFIG_SJLJ_EXCEPTIONS == 0

163  #  define USING_SJLJ_EXCEPTIONS            0

164  #  ifndef EH_RETURN_DATA_REGNO

165      #error "EH_RETURN_DATA_REGNO required"

166  #  endif

167  #  if !defined(EH_RETURN_HANDLER_RTX) && !defined(HAVE_eh_return)

168      #error "EH_RETURN_HANDLER_RTX or eh_return required"

169  #  endif

170  #  if !defined(DWARF2_UNWIND_INFO) && !defined(IA64_UNWIND_INFO)

171      #error "{DWARF2,IA64}_UNWIND_INFO required"

172  #  endif

173  # endif

174  #else

175  # define USING_SJLJ_EXCEPTIONS        MUST_USE_SJLJ_EXCEPTIONS

176  #endif

 

CONFIG_SJLJ_EXCEPTIONS--enable-sjlj-exceptions(或--disable-sjlj-exceptions)配置选项设置。对于禁止使用setjmp/longjmp,编译器需要检测是否可行。在我们这里, USING_SJLJ_EXCEPTIONSMUST_USE_SJLJ_EXCEPTIONS定义相同,为0!那么下面的init_eh基本无事可做。该函数主要是为使用setjmp/longjmp的异常机制,初始化一个重要的数据结构——SjLj_Function_Context。这个结构在异常处理中,需要在栈上分配。看到,在其定义中,有用于维护的prev域。因而前端必须知道其定义来提供必要的维护。

 

54      struct SjLj_Function_Context                                                             in unwind-sjlj.c

55      {

56        /* This is the chain through all registered contexts. It is

57          filled in by _Unwind_SjLj_Register.  */

58        struct SjLj_Function_Context *prev;

59     

60        /* This is assigned in by the target function before every call

61          to the index of the call site in the lsda. It is assigned by

62          the personality routine to the landing pad index.  */

63        int call_site;

64     

65        /* This is how data is returned from the personality routine to

66          the target function's handler.  */

67        _Unwind_Word data[4];

68     

69        /* These are filled in once by the target function before any

70          exceptions are expected to be handled.  */

71        _Unwind_Personality_Fn personality;

72        void *lsda;

73     

74      #ifdef DONT_USE_BUILTIN_SETJMP

75        /* We don't know what sort of alignment requirements the system

76          jmp_buf has. We over estimated in except.c, and now we have

77          to match that here just in case the system *didn't* have more

78          restrictive requirements.  */

79        jmp_buf jbuf __attribute__((aligned));

80      #else

81        void *jbuf[];

82      #endif

83      };

 

这也情有可原,因为这个上下文是要传给setjmplongjmp的(域jbuf)。而在另一个机制中,每个上下文都是分开,不需要知道彼此,其处理机制由运行时库完整提供,并维护。前端不需要额外的处理。在这里不需要告诉前端。

 

366    void

367    init_eh (void)                                                                                         in except.c

368    {

369      if (! flag_exceptions)

370        return;

371   

372      type_to_runtime_map = htab_create_ggc (31, t2r_hash, t2r_eq, NULL);

373   

374     /* Create the SjLj_Function_Context structure. This should match

375        the definition in unwind-sjlj.c.  */

376      if (USING_SJLJ_EXCEPTIONS)

377      {

          ...

455      }

456    }

 

通常在使用中是定义一族异常类,有基类及若干派生类。而在异常处理处,通常会使用一系列的catch语句对这些类型进行匹配,以选择匹配的句柄。因此编译器自动为异常类构建tinfo对象,但是前面我们看到,如果类没有定义虚函数,类节点没有保存tinfo对象的地方。为此,前端构建了type_to_runtime_map,用于绑定异常类及其tinfo对象。

 

原创粉丝点击