Open Bug 516046 Opened 15 years ago Updated 2 years ago

Gratuitous use of ObjC exceptions

Categories

(Firefox :: General, defect)

x86
macOS
defect

Tracking

()

People

(Reporter: joelr, Unassigned)

References

(Blocks 1 open bug)

Details

(Whiteboard: [ts])

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.
Whiteboard: [ts]
See bug 417560. As for why those handlers are covering Carbon calls, our understanding is that Carbon calls can raise Obj-C exceptions.
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?
(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.
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.
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.
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
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
Severity: normal → S3
You need to log in before you can comment on or make changes to this bug.