Pull to refresh

Избавление от «мертвого» кода в Javascript в IE9

Browsers
Translation
Original author: Dean Hachamovitch
[От переводчика: данный перевод является частью этого официального поста из блога команды IE и призван разъяснить недавнее недоразумение: IE9 — Обман при прохождении SunSpider JS? ]

Одним из изменений в нашем новом JavaScript движке, под кодовым названием Chakra, является уничтожение мертвого кода, с целью повышения производительности работы реальных сайтов. Вчера после полудня кто-то запостил вопрос у нас на коннекте — «What sorts of code does the analysis work on, other than the exact [math-cordic test] function included in SunSpider». Так как многих заинтересовал этот вопрос, то этот блог пост призван ответить на него.


Если говорить вкратце, то JavaScript движок IE9 претерпел огромное количество разнообразных изменений с целью повышения производительности реальных веб-приложений. Вы можете попробовать некоторые примеры приложений нашем сайте ietestdrive.com, а затем сравнить результаты в разных браузерах. Поведение нашего JS движка это не «специально подкрученная» оптимизация и это не баг.

В Chakra мы применили некоторых оптимизации, хорошо известные в мире компиляторов, в частности исключение «мертвого» кода. Данный вид оптимизации просматривает код программы в поисках кода, который не меняет состояние программы, затем удаляет этот код. Это приносит сразу две выгоды: уменьшение размера занимаемой программой памяти и увеличение скорости выполнения программы.

Вот очень простой примера Javascript-кода, который является хорошим кандидатом для удаления, потому что условие всегда будет ложным и движок js вполне может его удалить


function func() {
    var x = 1;
    var y = 3;
    var w = x + y;

    if (w != 4) {
        // dead code 
    }
}


Уничтожение «мертвого» кода особенно эффективно, когда код выполняется много раз, например в цикле. В следующем примере, код в цикле перезаписывает значение одной и той же переменной (в computer science это называется «мертвым» сохранением), поэтому он может сведен к одному вызову


function func(a, b) {
    var x;
    var i = 300;
    while (i--) {
        x = a + b; // dead store
    }
}


В примере ниже, код, выполняющийся в цикле, не используется нигде за пределами это цикла, следовательно этот цикл может безопасно удален.


function sum() {
    var a = [1, 2, 3, 4, 5];
    var sum = 0.0;
    
    // dead loop elimination
    for (var i = 0; i < 5; i++) {
        sum += a[i];
    }
}


Разработчики довольно часто пишут «мертвый» код, не подозревая об этом, и могут полагаться, что компиляторы оптимизируют код. Большинство современных компиляторов сегодня производят большое количество оптимизаций по вычислению и удалению неиспользуемого кода.

Что ж, почему этот эффект проявляется в тесте math-cordic из Webkit SunSpider suite? Давайте посмотрим на внутренний код теста.


function cordicsincos() { 
     var X;  
     var Y;  
     var TargetAngle; 
     var CurrAngle;  
     var Step;   
     X = FIXED(AG_CONST);         /* AG_CONST * cos(0) */ 
     Y = 0;                       /* AG_CONST * sin(0) */ 
   
    TargetAngle = FIXED(28.027);  
    CurrAngle = 0;  
    for (Step = 0; Step < 12; Step++) { 
        var NewX; 
            if (TargetAngle > CurrAngle) { 
               NewX = X - (Y >> Step);  
               Y = (X >> Step) + Y; 
               X = NewX; 
               CurrAngle += Angles[Step];  
            } else { 
               NewX = X + (Y >> Step); 
               Y = -(X >> Step) + Y; 
               X = NewX; 
               CurrAngle -= Angles[Step]; 
            } 
    } 
} 


Тест выполняет дорогостоящий с точки зрения вычислений цикл, и затем ничего не делает с его результатом. Тест написан таким образом, что в нем срабатывают общие оптимизации.

Конечно, тест может быть переписан во избежание возникновения данной оптимизации, что приведет к результату, сопоставимому с результатами других браузеров.

Данная проблема еще показательна тем, что микротесты не отображают реальный веб. Sunspider использует дорогостоящий цикл для вычисления синуса и косинуса. Реальные же приложения используют более быстрые встроенные функции, доступные в движках JavaScript.

Данные оптимизации относительно новы в мире исполняющих сред JavaScript, хотя в реальных приложениях достаточно много «мертвого» кода. Данные оптимизации часто требуют значительного анализа потока выполнения кода, и если в реальных веб-приложениях тратить большое количество времени на анализ кода, то может получиться что мы снизим отзывчивость веб-страницы. Наш движок Chakra балансирует между качеством кода и временем на анализ и производит лишь наименее затратные и очевидные оптимизации «мертвого» кода. И баги, отрапортованные через Connect являются примерами того, где код не до конца оптимизирован. Мы продолжим «допиливать» наш движок до финальной версии.

Удаление данного типа «мертвого» кода одна из немногих оптимизаций, производимых Chakra для избегания выполнения бесполезной работы. В течение последующих нескольких дней мы напишем о некоторых других техниках применяемых в нашем JavaScript движке для достижения более высокой производительности.

— Dean Hachamovitch

От переводчика: вышедшую совсем недавно обновленную предварительную версию IE9 можно скачать здесь ietestdrive.com
И собственно обновленные результаты теста:image
UPD: Добавил к графикам табличку, для большей наглядности. На гарфике не видно разницы между быстрыми браузерами.
Detailed Results Average (ms)
IE8 3746
Firefox 3.6.12 753
Safari 5.0.2 328
Firefox 4.0 Pre-Release Beta7 277
Chrome 7.0 262
Opera 10.63 246
Opera 11 Alpha 242
Chrome 8.0 Beta 233
IE9 Platform Preview #7 216
Tags:
Hubs:
Total votes 71: ↑52 and ↓19 +33
Views 1.5K
Comments Comments 167