1. Java / Говнокод #15538

    +117

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;
    
            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }

    Из исходника java.lang.String.

    Вопрос: зачем нужна временная переменная val? Это какая-то особая уличная магия с оптимизацией?

    Запостил: someone, 20 Марта 2014

    Комментарии (39) RSS

    • > char val[]
      Да это же сишники писали!
      Не исключено, что оптимизация, связанная с локальностью переменной, но это надо дизассемблировать и измерять.
      Ответить
    • Даже если это оптимизация, то отсутствие комментария, описывающее смысл и эффект - само по себе говно.
      Пример:
      http://golang.org/src/pkg/encoding/json/scanner.go
      строка 77
      Ответить
    • "Вопрос: зачем нужна временная переменная val?"

      Мой реверс-инжиниринг мыслительного процесса говорит что там кто-то думал насчет `byte []`. И в будущем прикручивание лучшей хэш функции. Потому что *31 это относительно слабая хэш функция.

      "Это какая-то особая уличная магия с оптимизацией?"

      Если value это внутрее представление, то эта строка кода скорее всего будет выкинута оптимизатором. Потому что ничего не делает.
      Ответить
    • Главное, что value.length :D
      Ответить
      • давай, дружок, расскажи почему так нельзя делать? это final свойство, доступ к которому осуществляется за константное время. да и даже если это отбросить, то все современные компиляторы это дело очень хорошо оптимизируют.
        Ответить
    • http://habrahabr.ru/company/golovachcourses/blog/221133/
      При вызове метода hashCode() у одного экземпляра java.lang.String из разных потоков будет гонка потоков (data race) по полю hash.
      То же относится и к полю value.
      Ответить
      • Если hash объявлен как volatile, то никаких проблем не будет. value объявлена как final и используется только для чтения, с ней априори никаких гонок быть не может.
        Ответить
        • Да даже если не как volatile, то на 1.5+ худшее что случится - хеш посчитают джважды.
          Ответить
        • Модель памяти жабы 1.5+ гарантирует атомарность (но не видимость, если нет volatile) всех записей/чтений кроме long'ов и double'ов? Или я туплю?
          Ответить
          • гарантирует
            http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.7
            Ответить
            • Да эту фразу я находил... Но она ничего не говорит об int'ах.
              Ответить
              • ну раз 32битные значение всегда пишутся атомарно, то всяко int атомарно пишется.
                Ответить
                • После крестоблядских стандартов я перестал доверять всем недосказанностям в доках... Профдеформация, мать ее ;(
                  Ответить
                  • long пишутся неатомарно атомарными частями по 32 бита... Но 32 битные int пишутся неатормано, потому что ВЫ ДОЛЖНЫ СТРАДАТЬ.
                    Ответить
                    • > атомарными частями по 32 бита
                      Где там об этом написано? :)
                      Ответить
                      • > two separate writes: one to each 32-bit half
                        > This can result in a situation where a thread sees the first 32 bits of a 64-bit value from one write, and the second 32 bits from another write

                        если бы части по 32 бита были не атомарными, возможных комбинаций было бы гораздо больше (например, 0-15 и 32-47 биты от первого, остальные от второго).
                        Но явной фразы не нашлось :(
                        Ответить
                        • > This can result in a situation
                          Ну это же всего лишь пример ситуации, которая может возникнуть, а не полный список вариантов? :)
                          Ответить
                          • мне нравится твоя параноя, кажется, я заразился
                            Ответить
                            • А все помнят, что кроме Sun/Oracle JVM есть ещё всякое говно типа Dalvik и ещё > 9000 реализаций обычной JVM? Интересно, как сделано у них.
                              Ответить
                              • Dalvik с версии 4 достиг тотальной жвм-совместимости в этом вопросе.
                                Ответить
                                • Но мы же не можем рассчитывать, что у всех потребителей ПО будет актуальная версия.
                                  Ответить
                                  • Разумеется. Более того, предыдущие версии работали не совсем правильно (особенно ветка 2). Нужно писать код, использующий только стандартные примитивы синхронизации и атомарные типы.
                                    Ответить
                                    • А как с атомарностью в Blackberry, DoCoMo, IKVM, MSJVM? Мы же не можем ограничивать кроссплатформенность, важен каждый клиент.
                                      Ответить
                                      • > MSJVM
                                        Ее разве не закопали?
                                        Ответить
                                        • IE6 тоже закопали, однако, до сих пор находятся гурманы.
                                          Ответить
                                          • ага
                                            есть гурманы, которых устраивает пользоваться однажды аттестованным по ИБ перечнем версий ПО
                                            Ответить
                                            • > однажды аттестованным по ИБ перечнем версий ПО
                                              И пофиг, что это ПО давным-давно превратилось в дуршлаг ;)
                                              Ответить
                                              • именно
                                                но зато "модель нарушителя" ёпт

                                                а уж как волокита по ИБ тормозит прикрытие 0-day уязвимостей
                                                инициативный дурак хуже вредителя
                                                Ответить
                                            • Жалко, что его атакуют не через однажды серитифицированные дыры.
                                              Ответить
                    • Кстати, надо придумать среду, в которой однобайтовые значения пишутся неатомарно. Например, через побитовые сдвиги и флаг переноса.
                      Ответить
                      • А там об этом, кстати, упоминают. Почитай раздел о word tearing чуть выше того, который скинул Роман.

                        Так что все придумано до нас ;)
                        Ответить
                  • ...сишкобляди предстоит трудная ночь. У нее уже сколько лет каждая ночь была трудной, и ее анус мог без проблем вместить последний стандарт на кресты.
                    Ответить
      • Ты о жабе 1.4 и ниже?
        Ответить
      • И в любом случае копирование ссылки в char val[] = value ну никак не может решить проблемы с многопоточностью.
        Ответить
    • Если бы вы почитали сурсы этого класса еще немного, то обнаружили бы, что эта оптимизация используется и в других методах, и там таки есть комментарий: char[] val = value; /* avoid getfield opcode */. Ну забыли сюда скопипастить этот комментарий.
      Вообще, полезно выносить в локалы что-то, что вы собираетесь использовать в циклах, если это что-то, конечно, не должно быть вдруг не внезапно изменено другим тредом прям посреди цикла, а вы как раз только этого и ждете.
      Ответить

    Добавить комментарий