[LLVMdev] RFC: Exception Handling Rewrite

Bill Wendling wendling at apple.com
Fri Aug 5 13:43:15 PDT 2011


On Aug 5, 2011, at 10:57 AM, Peter Lawrence wrote:

> Bill,
>       ooops, yes, I described the meaning of "throw(A)" backwards,

I thought that might be the case. :)

> but I still
> think my example shows why you cannot merge LandingpadInst while
> inlining because multiple filter-lists on a LandingpadInst don't make sense.
> 
> Perhaps I'm reading your original spec wrong, perhaps I'm mis-reading
> Duncan's emails, but I read them to mean that your syntax supports
> multiple filter-lists on a single LandingpadInst.
> 
> first off, I think we agree on what I think you're saying below, that if foo calls
> something, and bar calls somethingelse, and that if these have different
> exception-specifications, then we can translate into different DWARF Action
> and Types Tables, each call has it's own (in this case unique) Actions.
> 
> second, do you agree that if one exception-spec says to unexpected()
> if anything other than 'A' is thrown, and another exception-spec says
> to unexpected() if anything other than 'B' is thrown, that these cannot
> be merged --> by that I mean they cannot have the same landingpad <-- ?
> 
Well, the only way they could be merged is through inlining. So I don't agree. One exception spec is encapsulated by the caller's exception spec. And merging them can be done even now. I give an example below.

-bw

Let's look at an example:

extern int printf(const char *, ...);

struct A {
  ~A() { printf("A's d'tor\n"); }
};

struct B {
  ~B() { printf("B's d'tor\n"); }
};

void baz();

void foo() throw (A) __attribute__((always_inline));
void foo() throw (A) {
  baz();
}

void bar() throw (B) {
  try {
    foo();
  } catch (const char *s) {
    printf("%s\n", s);
  }
}


GCC outputs this:

[Irk:llvm] gcc-4.2 -S -o - -dA t.cpp -O3
	.text
	.align 4,0x90
.globl __Z3foov
__Z3foov:
  . . .
LEHB0:
	call	__Z3bazv
LEHE0:
  . . .
GCC_except_table0:
LLSDA8:
	.byte	0xff	# @LPStart format (omit)
	.byte	0x9b	# @TType format (indirect pcrel sdata4)
	.byte	0x25	# uleb128 0x25; @TType base offset
	.byte	0x3	# call-site format (udata4)
	.byte	0x1a	# uleb128 0x1a; Call-site table length
	.set L$set$0,LEHB0-LFB8
	.long L$set$0	# region 0 start
	.set L$set$1,LEHE0-LEHB0
	.long L$set$1	# length
	.set L$set$2,L6-LFB8
	.long L$set$2	# landing pad
	.byte	0x1	# uleb128 0x1; action
	.set L$set$3,LEHB1-LFB8
	.long L$set$3	# region 1 start
	.set L$set$4,LEHE1-LEHB1
	.long L$set$4	# length
	.long	0x0	# landing pad
	.byte	0x0	# uleb128 0x0; action
	.byte	0x7f	# Action record table
	.byte	0x0
	.align 2
	.long	__ZTI1A+4 at GOTPCREL
	.byte	0x1	# Exception specification table
	.byte	0x0

So the call to "foo" is marked as being able to throw an "A" type. (The 0x7f in the action record table is a negative 1-based offset into the exception specification table, which itself is a positive 1-based offset into the type table.) Now look at bar:

	.align 4,0x90
.globl __Z3barv
__Z3barv:
  . . .
LEHB2:
	call	__Z3bazv
LEHE2:
  . . .

GCC_except_table1:
LLSDA9:
	.byte	0xff	# @LPStart format (omit)
	.byte	0x9b	# @TType format (indirect pcrel sdata4)
	.byte	0x59	# uleb128 0x59; @TType base offset
	.byte	0x3	# call-site format (udata4)
	.byte	0x41	# uleb128 0x41; Call-site table length
	.set L$set$5,LEHB2-LFB9
	.long L$set$5	# region 0 start
	.set L$set$6,LEHE2-LEHB2
	.long L$set$6	# length
	.set L$set$7,L20-LFB9
	.long L$set$7	# landing pad
	.byte	0x5	# uleb128 0x5; action
  . . . [ elided for readability ]
	.byte	0x7d	# Action record table
	.byte	0x0
	.byte	0x2
	.byte	0x7d
	.byte	0x7f
	.byte	0x7d
	.byte	0x0
	.byte	0x79
	.align 2
	.long	__ZTI1B+4 at GOTPCREL
	.long	__ZTIPKc+4 at GOTPCREL
	.long	__ZTI1A+4 at GOTPCREL
	.byte	0x1	# Exception specification table
	.byte	0x0
	.byte	0x3
	.byte	0x0


As you can see, foo() has been completely inlined into bar(). The entry for the call to "baz" (from the foo() function) is shown here in the EH table. The action associated with it is the 1-based, positive offset into the action table

	.byte	0x7f
	.byte	0x7d

This means it should look at the filter at offset -1 into the exception spec table. That is "0x1", which corresponds to "__ZTI1A+4 at GOTPCREL". This is saying that the call to "baz" can throw only an "A" type. The "0x7d" means that the next action to apply is:

	.byte	0x2
	.byte	0x7d

This action says it can catch only "__ZTIPKc+4 at GOTPCREL" types. The "0x7d" here means that the next action to apply is:

	.byte	0x7d	# Action record table
	.byte	0x0

The "0x7d" means to look at offset -3 into the exception spec table. This is "0x3", which means that it's "__ZTI1B+4 at GOTPCREL" in the type table. This means that after the catch, it can only throw a type "B". The "0x0" in the action record indicates that there are no more filters or catches to apply here.

So this is the way to merge two landing pads together which have different exception specs. (Apologies for my previous example, which had some errors in it.)

-bw




More information about the llvm-dev mailing list