Пришлось копаться с внутренностями стандартного gzip компрессора, и он под капотом flate использует (что логично, ведь gzip - это просто надстройка в виде пары заголовков для flate-потока). Там, в декомпрессоре, было одно интересное поле -
step func(*decompressor) . Читай - указатель на функцию. Туда подставлялся метод декомпрессора, который должен быть использован для следующего шага (и делал он это довольно странным образом). Собственно, почему это странно? Потому что вызов функции по указателю (а не по идентификатору) - это indirect call, и тут уже дело конкретно в железе. Потому что для совершения такого вызова, процессору сначала придется обратиться по адресу в памяти, на который указывает наш func ptr. В С, например, компилятор может соптимизировать это так, чтобы разницы в производительности не было (предварительно положив адрес в регистр).
Да вот только мы не в С :). Я даже попробовать сделать бенчмарк - и правда, обычный вызов справляется за 0.2нс. В то время, как indirect-вариант - за 1.1нс. Стоит сделать помарку: 0.2нс - это всегда подозрительно, и, скорее всего, так и есть, потому что в измеряемой мною функции сразу производился возврат, и результат никуда не присваивался - компилятор мог просто-напросто вырезать такой вызов. Поэтому я повторил с флагом -N (дабы отключить оптимизации), и результат стал 1.1нс и 1.9нс соответственно. То есть, разница все еще присутствует.
Так какой из этого можно сделать вывод? Вызов по func ptr дороже. В пределах пикосекунд, но есть. И именно это и сыграло роль (хоть и минимальную, особенно смотря на коэффициент).
Вот ссылка на мой PR, если интересно. Можете посмотреть там сравнения до и после патча. А еще, там есть интересный момент, связанный с занулением статического массива:)