Gratuitous use of ObjC exceptions

NEW
Unassigned

Status

()

Firefox
General
9 years ago
8 years ago

People

(Reporter: joelr, Unassigned)

Tracking

(Blocks: 1 bug)

Trunk
x86
Mac OS X
Points:
---

Firefox Tracking Flags

(Not tracked)

Details

(Whiteboard: [ts])

(Reporter)

Description

9 years ago
Consider CFStringRefToUTF8 [1]. This function uses Carbon APIs but no Cocoa. Still the whole function is bracketed in NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT and NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT, i.e. 

@try {
  ... 
} @catch(NSException *_exn) {
  nsObjCExceptionLog(_exn);
}                                \
return NS_ERROR_FAILURE;

It looks harmless but take a look at the assembler dump below. 2/3 or 3/4 of this function (more?) are taken by the exception setup and cleanup. ObjC exceptions are zero-cost on x86-64 but very expensive on x86-32 [2]. I think we should analyze our code for gratuitous use of ObjC exceptions and, perhaps, eliminate their use altogether where possible. 

For example, the .mm extension is for C++ files that call into ObjC. I skimmed through half of nsLocalFileOSX.mm but I didn't see any calls into ObjC, just calls to Carbon which is a C/C++ API. Why are we using ObjC exception here?

[1] http://mxr.mozilla.org/mozilla-central/source/xpcom/io/nsLocalFileOSX.mm#2225 
[2] http://developer.apple.com/mac/library/releasenotes/Cocoa/RN-ObjectiveC/index.html

Breakpoint 1, CFStringReftoUTF8 (aInStrRef=0x2614fc0, aOutStr=@0xbfffec58) at ../../../mozilla-central/xpcom/io/nsLocalFileOSX.mm:2187
2187	  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
(gdb) disas
Dump of assembler code for function CFStringRefToUTF8:
0x00bf8ff0 <CFStringRefToUTF8+0>:	push   %ebp
0x00bf8ff1 <CFStringRefToUTF8+1>:	mov    %esp,%ebp
0x00bf8ff3 <CFStringRefToUTF8+3>:	push   %esi
0x00bf8ff4 <CFStringRefToUTF8+4>:	push   %ebx
0x00bf8ff5 <CFStringRefToUTF8+5>:	sub    $0xb0,%esp
0x00bf8ffb <CFStringRefToUTF8+11>:	call   0xbf9000 <CFStringRefToUTF8+16>
0x00bf9000 <CFStringRefToUTF8+16>:	pop    %ebx
0x00bf9001 <CFStringRefToUTF8+17>:	mov    %eax,-0x6c(%ebp)
0x00bf9004 <CFStringRefToUTF8+20>:	mov    %edx,-0x70(%ebp)
0x00bf9007 <CFStringRefToUTF8+23>:	lea    -0x64(%ebp),%esia
0x00bf900a <CFStringRefToUTF8+26>:	mov    %esi,(%esp)
0x00bf900d <CFStringRefToUTF8+29>:	call   0xd1b0f4 <dyld_stub_objc_exception_try_enter>
0x00bf9012 <CFStringRefToUTF8+34>:	mov    %esi,(%esp)
0x00bf9015 <CFStringRefToUTF8+37>:	call   0xd1aecc <dyld_stub__setjmp>
0x00bf901a <CFStringRefToUTF8+42>:	test   %eax,%eax
0x00bf901c <CFStringRefToUTF8+44>:	je     0xbf9080 <CFStringRefToUTF8+144>
0x00bf901e <CFStringRefToUTF8+46>:	lea    -0x64(%ebp),%esi
0x00bf9021 <CFStringRefToUTF8+49>:	mov    %esi,(%esp)
0x00bf9024 <CFStringRefToUTF8+52>:	call   0xd1b0e2 <dyld_stub_objc_exception_extract>
0x00bf9029 <CFStringRefToUTF8+57>:	mov    %eax,-0x74(%ebp)
0x00bf902c <CFStringRefToUTF8+60>:	mov    %esi,(%esp)
0x00bf902f <CFStringRefToUTF8+63>:	call   0xd1b0f4 <dyld_stub_objc_exception_try_enter>
0x00bf9034 <CFStringRefToUTF8+68>:	mov    %esi,(%esp)
0x00bf9037 <CFStringRefToUTF8+71>:	call   0xd1aecc <dyld_stub__setjmp>
0x00bf903c <CFStringRefToUTF8+76>:	test   %eax,%eax
0x00bf903e <CFStringRefToUTF8+78>:	je     0xbf9110 <CFStringRefToUTF8+288>
0x00bf9044 <CFStringRefToUTF8+84>:	lea    -0x64(%ebp),%eax
0x00bf9047 <CFStringRefToUTF8+87>:	mov    %eax,(%esp)
0x00bf904a <CFStringRefToUTF8+90>:	call   0xd1b0e2 <dyld_stub_objc_exception_extract>
0x00bf904f <CFStringRefToUTF8+95>:	mov    %eax,-0x74(%ebp)
0x00bf9052 <CFStringRefToUTF8+98>:	mov    -0x74(%ebp),%edx
0x00bf9055 <CFStringRefToUTF8+101>:	test   %edx,%edx
0x00bf9057 <CFStringRefToUTF8+103>:	jne    0xbf920a <CFStringRefToUTF8+538>
0x00bf905d <CFStringRefToUTF8+109>:	lea    -0x64(%ebp),%eax
0x00bf9060 <CFStringRefToUTF8+112>:	mov    %eax,(%esp)
0x00bf9063 <CFStringRefToUTF8+115>:	call   0xd1b0fa <dyld_stub_objc_exception_try_exit>
0x00bf9068 <CFStringRefToUTF8+120>:	mov    $0x80004005,%ebx
0x00bf906d <CFStringRefToUTF8+125>:	mov    %ebx,%eax
0x00bf906f <CFStringRefToUTF8+127>:	add    $0xb0,%esp
0x00bf9075 <CFStringRefToUTF8+133>:	pop    %ebx
0x00bf9076 <CFStringRefToUTF8+134>:	pop    %esi
0x00bf9077 <CFStringRefToUTF8+135>:	leave  
0x00bf9078 <CFStringRefToUTF8+136>:	ret    
0x00bf9079 <CFStringRefToUTF8+137>:	nopl   0x0(%eax)
0x00bf9080 <CFStringRefToUTF8+144>:	mov    -0x6c(%ebp),%eax
0x00bf9083 <CFStringRefToUTF8+147>:	mov    %eax,(%esp)
0x00bf9086 <CFStringRefToUTF8+150>:	call   0xd19336 <dyld_stub_CFStringGetLength>
0x00bf908b <CFStringRefToUTF8+155>:	mov    %eax,%esi
0x00bf908d <CFStringRefToUTF8+157>:	mov    %eax,-0x84(%ebp)
0x00bf9093 <CFStringRefToUTF8+163>:	movl   $0x0,-0x88(%ebp)
0x00bf909d <CFStringRefToUTF8+173>:	mov    -0x6c(%ebp),%ecx
0x00bf90a0 <CFStringRefToUTF8+176>:	lea    -0xc(%ebp),%eax
0x00bf90a3 <CFStringRefToUTF8+179>:	mov    %eax,0x20(%esp)
0x00bf90a7 <CFStringRefToUTF8+183>:	movl   $0x0,0x1c(%esp)
0x00bf90af <CFStringRefToUTF8+191>:	movl   $0x0,0x18(%esp)
0x00bf90b7 <CFStringRefToUTF8+199>:	movl   $0x0,0x14(%esp)
0x00bf90bf <CFStringRefToUTF8+207>:	movl   $0x0,0x10(%esp)
0x00bf90c7 <CFStringRefToUTF8+215>:	movl   $0x8000100,0xc(%esp)
0x00bf90cf <CFStringRefToUTF8+223>:	mov    -0x88(%ebp),%eax
0x00bf90d5 <CFStringRefToUTF8+229>:	mov    -0x84(%ebp),%edx
0x00bf90db <CFStringRefToUTF8+235>:	mov    %eax,0x4(%esp)
0x00bf90df <CFStringRefToUTF8+239>:	mov    %edx,0x8(%esp)
0x00bf90e3 <CFStringRefToUTF8+243>:	mov    %ecx,(%esp)
0x00bf90e6 <CFStringRefToUTF8+246>:	call   0xd19318 <dyld_stub_CFStringGetBytes>
0x00bf90eb <CFStringRefToUTF8+251>:	mov    $0x80004005,%ebx
0x00bf90f0 <CFStringRefToUTF8+256>:	cmp    %eax,%esi
0x00bf90f2 <CFStringRefToUTF8+258>:	je     0xbf9180 <CFStringRefToUTF8+400>
0x00bf90f8 <CFStringRefToUTF8+264>:	lea    -0x64(%ebp),%eax
0x00bf90fb <CFStringRefToUTF8+267>:	mov    %eax,(%esp)
0x00bf90fe <CFStringRefToUTF8+270>:	call   0xd1b0fa <dyld_stub_objc_exception_try_exit>
0x00bf9103 <CFStringRefToUTF8+275>:	mov    %ebx,%eax
0x00bf9105 <CFStringRefToUTF8+277>:	add    $0xb0,%esp
0x00bf910b <CFStringRefToUTF8+283>:	pop    %ebx
0x00bf910c <CFStringRefToUTF8+284>:	pop    %esi
0x00bf910d <CFStringRefToUTF8+285>:	leave  
0x00bf910e <CFStringRefToUTF8+286>:	ret    
0x00bf910f <CFStringRefToUTF8+287>:	nop    
0x00bf9110 <CFStringRefToUTF8+288>:	mov    -0x74(%ebp),%eax
0x00bf9113 <CFStringRefToUTF8+291>:	mov    %eax,0x4(%esp)
0x00bf9117 <CFStringRefToUTF8+295>:	mov    0x38b944(%ebx),%eax
0x00bf911d <CFStringRefToUTF8+301>:	mov    %eax,(%esp)
0x00bf9120 <CFStringRefToUTF8+304>:	call   0xd1b0e8 <dyld_stub_objc_exception_match>
0x00bf9125 <CFStringRefToUTF8+309>:	test   %eax,%eax
0x00bf9127 <CFStringRefToUTF8+311>:	je     0xbf9170 <CFStringRefToUTF8+384>
0x00bf9129 <nsObjCExceptionLog+0>:	mov    0x38b008(%ebx),%eax
0x00bf912f <nsObjCExceptionLog+6>:	mov    %eax,0x4(%esp)
0x00bf9133 <nsObjCExceptionLog+10>:	mov    -0x74(%ebp),%edx
0x00bf9136 <nsObjCExceptionLog+13>:	mov    %edx,(%esp)
0x00bf9139 <nsObjCExceptionLog+16>:	call   0xd1b100 <dyld_stub_objc_msgSend>
0x00bf913e <nsObjCExceptionLog+21>:	mov    %eax,%esi
0x00bf9140 <nsObjCExceptionLog+23>:	mov    0x38b00c(%ebx),%eax
0x00bf9146 <nsObjCExceptionLog+29>:	mov    %eax,0x4(%esp)
0x00bf914a <nsObjCExceptionLog+33>:	mov    -0x74(%ebp),%ecx
0x00bf914d <nsObjCExceptionLog+36>:	mov    %ecx,(%esp)
0x00bf9150 <nsObjCExceptionLog+39>:	call   0xd1b100 <dyld_stub_objc_msgSend>
0x00bf9155 <nsObjCExceptionLog+44>:	mov    %esi,0x8(%esp)
0x00bf9159 <nsObjCExceptionLog+48>:	mov    %eax,0x4(%esp)
0x00bf915d <nsObjCExceptionLog+52>:	lea    0x36ad48(%ebx),%eax
0x00bf9163 <nsObjCExceptionLog+58>:	mov    %eax,(%esp)
0x00bf9166 <nsObjCExceptionLog+61>:	call   0xd1a0ce <dyld_stub_NSLog>
0x00bf916b <nsObjCExceptionLog+66>:	jmp    0xbf905d <CFStringRefToUTF8+109>
0x00bf9170 <CFStringRefToUTF8+384>:	lea    -0x64(%ebp),%eax
0x00bf9173 <CFStringRefToUTF8+387>:	mov    %eax,(%esp)
0x00bf9176 <CFStringRefToUTF8+390>:	call   0xd1b0fa <dyld_stub_objc_exception_try_exit>
0x00bf917b <CFStringRefToUTF8+395>:	jmp    0xbf9052 <CFStringRefToUTF8+98>
0x00bf9180 <CFStringRefToUTF8+400>:	mov    -0x70(%ebp),%eax
0x00bf9183 <CFStringRefToUTF8+403>:	mov    -0xc(%ebp),%edx
0x00bf9186 <CFStringRefToUTF8+406>:	call   0xc34010 <_ZN19nsACString_internal9SetLengthEj>
0x00bf918b <CFStringRefToUTF8+411>:	mov    -0x70(%ebp),%eax
0x00bf918e <CFStringRefToUTF8+414>:	mov    0x4(%eax),%eax
0x00bf9191 <CFStringRefToUTF8+417>:	mov    $0x8007000e,%ebx
0x00bf9196 <CFStringRefToUTF8+422>:	cmp    -0xc(%ebp),%eax
0x00bf9199 <CFStringRefToUTF8+425>:	jne    0xbf90f8 <CFStringRefToUTF8+264>
0x00bf919f <CFStringRefToUTF8+431>:	mov    -0x70(%ebp),%ebx
0x00bf91a2 <_ZN19nsACString_internal12BeginWritingEv+0>:	mov    $0xffffffff,%edx
0x00bf91a7 <_ZN19nsACString_internal12BeginWritingEv+5>:	mov    %ebx,%eax
0x00bf91a9 <_ZN19nsACString_internal12BeginWritingEv+7>:	call   0xc35490 <_ZN19nsACString_internal13EnsureMutableEj>
0x00bf91ae <_ZN19nsACString_internal12BeginWritingEv+12>:	xor    %ecx,%ecx
0x00bf91b0 <_ZN19nsACString_internal12BeginWritingEv+14>:	test   %eax,%eax
0x00bf91b2 <_ZN19nsACString_internal12BeginWritingEv+16>:	je     0xbf91b6 <CFStringRefToUTF8+454>
0x00bf91b4 <_ZN19nsACString_internal12BeginWritingEv+18>:	mov    (%ebx),%ecx
0x00bf91b6 <CFStringRefToUTF8+454>:	mov    %esi,-0x7c(%ebp)
0x00bf91b9 <CFStringRefToUTF8+457>:	movl   $0x0,-0x80(%ebp)
0x00bf91c0 <CFStringRefToUTF8+464>:	mov    -0x6c(%ebp),%eax
0x00bf91c3 <CFStringRefToUTF8+467>:	lea    -0xc(%ebp),%edx
0x00bf91c6 <CFStringRefToUTF8+470>:	mov    %edx,0x20(%esp)
0x00bf91ca <CFStringRefToUTF8+474>:	mov    -0xc(%ebp),%edx
0x00bf91cd <CFStringRefToUTF8+477>:	mov    %edx,0x1c(%esp)
0x00bf91d1 <CFStringRefToUTF8+481>:	mov    %ecx,0x18(%esp)
0x00bf91d5 <CFStringRefToUTF8+485>:	movl   $0x0,0x14(%esp)
0x00bf91dd <CFStringRefToUTF8+493>:	movl   $0x0,0x10(%esp)
0x00bf91e5 <CFStringRefToUTF8+501>:	movl   $0x8000100,0xc(%esp)
0x00bf91ed <CFStringRefToUTF8+509>:	mov    -0x80(%ebp),%edx
0x00bf91f0 <CFStringRefToUTF8+512>:	mov    -0x7c(%ebp),%ecx
0x00bf91f3 <CFStringRefToUTF8+515>:	mov    %edx,0x4(%esp)
0x00bf91f7 <CFStringRefToUTF8+519>:	mov    %ecx,0x8(%esp)
0x00bf91fb <CFStringRefToUTF8+523>:	mov    %eax,(%esp)
0x00bf91fe <CFStringRefToUTF8+526>:	call   0xd19318 <dyld_stub_CFStringGetBytes>
0x00bf9203 <CFStringRefToUTF8+531>:	xor    %ebx,%ebx
0x00bf9205 <CFStringRefToUTF8+533>:	jmp    0xbf90f8 <CFStringRefToUTF8+264>
0x00bf920a <CFStringRefToUTF8+538>:	mov    -0x74(%ebp),%ecx
0x00bf920d <CFStringRefToUTF8+541>:	mov    %ecx,(%esp)
0x00bf9210 <CFStringRefToUTF8+544>:	call   0xd1b0ee <dyld_stub_objc_exception_throw>
End of assembler dump.
(Reporter)

Updated

9 years ago
Whiteboard: [ts]

Comment 1

9 years ago
See bug 417560. As for why those handlers are covering Carbon calls, our understanding is that Carbon calls can raise Obj-C exceptions.
(Reporter)

Comment 2

9 years ago
Josh,

1) How can Carbon calls raise ObjC exceptions, these are two completely different worlds. Carbon has absolutely nothing to do with the ObjC runtime (and thus exceptions) as far as I know.

2) I looked at bugs 417560 and 163260 but I maintain that we should not be this ham-handed. CFStringRefToUTF8 and other functions from nsLocalFileOSX are all over the place in the startup path. I want to streamline this path and I really don't want to see a disassembly like the above!

3) Carbon is 32-bit only and there's no 64-bit Carbon at all. None, zilch, none whatsoever. Will you be replacing these Carbon calls as part of the 64-bit port?

Comment 3

9 years ago
(In reply to comment #2)
> 1) How can Carbon calls raise ObjC exceptions, these are two completely
> different worlds. Carbon has absolutely nothing to do with the ObjC runtime
> (and thus exceptions) as far as I know.

At an implementation level they are not different worlds. Many Obj-C objects are backed by Carbon implementations, and in some cases the situation is reversed. According to the research we did, Carbon APIs can call into Obj-C code and frameworks and thus raise Obj-C exceptions.

> 2) I looked at bugs 417560 and 163260 but I maintain that we should not be this
> ham-handed. CFStringRefToUTF8 and other functions from nsLocalFileOSX are all
> over the place in the startup path. I want to streamline this path and I really
> don't want to see a disassembly like the above!

See my answer to question #1 :) I don't like it either, but we have not come up with a better plan.

> 3) Carbon is 32-bit only and there's no 64-bit Carbon at all. None, zilch, none
> whatsoever. Will you be replacing these Carbon calls as part of the 64-bit
> port?

This isn't really true, "Carbon" is a somewhat wishy washy term these days. Most of Carbon disappeared, not all of it. For example, there is FSRef functionality in 64-bit, though some FSRef-based APIs are not available. In any case, most of our Carbon usage will go away in 64-bit. We've removed huge amounts of it already.
(Reporter)

Comment 4

9 years ago
FSRef lives in the CoreServices framework, particularly in CarbonCore.

nm
/System/Library/Frameworks/CoreServices.framework/Frameworks/CarbonCore.framework/CarbonCore
| grep objc
         U _objc_collectingEnabled
         U _objc_registerThreadWithCollector
         U _objc_unregisterThreadWithCollector

I do not see how this can throw ObjC exceptions.

I'm still waiting for the "official" word.
(Reporter)

Comment 5

9 years ago
I meant that I'm waiting for the semi-official word from Apple folks on whether Carbon can raise ObjC exceptions and how to best handle them on x86-32.
(Reporter)

Comment 6

9 years ago
Via Eric Schlegel at Apple:

Generally, exceptions should be caught at the level of the callback, rather than around the lower-level functions that you're calling in CoreFoundation.

As to whether the CF function you're calling could actually throw an exception, I can't say for sure, although it would be surprising. I don't think CoreFoundation throws exceptions in general. However, the source is public; you could download it and determine the answer yourself.

-eric
(Reporter)

Comment 7

9 years ago
The CoreFoundation sources are available for perusal here:

http://www.opensource.apple.com/source/CF/CF-476.19/

We can easily check to see what throws exceptions and what doesn't. The Core Foundation bits we use (CFRunLoop, etc.) do not throw ObjC exceptions.
Blocks: 447581
You need to log in before you can comment on or make changes to this bug.