Рассмотрим следующие простые функции:
void simple_throw(id object) {
@throw object;
}
void extra_throw(id object) {
id tmp0 = object;
id tmp1 = tmp0;
id tmp2 = tmp1;
@throw tmp2;
}
Сначала я подумал, что обе эти функции должны компилироваться в одну и ту же сборку, и обе должны быть эквивалентны простому вызову objc_exception_throw(object)
(поскольку функция аргументы autorelease
по умолчанию в ARC ), возможно, с одним добавленным objc_retain(object)
(поскольку ARC не является безопасным для исключения и по умолчанию имеет утечку).
Но этоне тот случайВот сборка (удаление некоторых из лишних пухов и директив .cfi_*
; аргументы лязга: -fobjc-arc -Ofast -fomit-frame-pointer -S
):
_simple_throw:
pushq %rax
callq *_objc_retain@GOTPCREL(%rip)
movq %rax, %rdi
callq _objc_retainAutorelease
movq %rax, %rdi
callq _objc_exception_throw
_extra_throw:
pushq %rbx
movq _objc_retain@GOTPCREL(%rip), %rbx
callq *%rbx
movq %rax, %rdi
callq *%rbx
movq %rax, %rdi
callq *%rbx
movq %rax, %rdi
callq *%rbx
movq %rax, %rdi
callq _objc_retainAutorelease
movq %rax, %rdi
callq _objc_exception_throw
simple_throw
сохраняет object
дважды , иextra_throw
сохраняет object
5 раз!
Это приводит к двум вопросам:
- Какова оптимальная сборка (с точки зрения удержания и авто-выпусков) для
simple_throw
, чтокомпилятор должен генерировать (при условии, что мы хотим, чтобы сгенерированный код был ARC-совместимым)? - Почему присвоения локальным переменным в
extra_throw
приводят к дополнительному сохранению?Я склонен думать, что это ошибка компилятора.