Каля 2 месяцаў назад мы пачалі працу па JägerMonkey, новых "базавых" метад JIT-кампілятар для SpiderMonkey (і Firefox). Таму мы робім гэта, што TraceMonkey працуе вельмі хутка для кода, сляды добра, але для кода, што не след, мы затрымаліся з перакладнікам, які не хутка. JIT JägerMonkey метад забяспечвае значна лепшую прадукцыйнасць базавага, а таксама адсочванні будзе працягваць хуткасці нас на код, у якім яна ўжываецца.
На гэтым тыдні, мы былі бегі, каб адкрыць асноўны кампілятар, і на сённяшні дзень, JägerMonkey рэалізуе досыць JavaScript, каб запусціць усё SunSpider у "рэжыме Ягер" і на 18% хутчэй, чым перакладніка. І мы яшчэ не зрабілі, што шматлікія аптымізацыі яшчэ не Ёсць яшчэ шмат рэчаў, якія мы зробім (гл. вікі-артыкулы).
У астатняй частцы гэтай пасады, я дам трохі больш фону пра тое, чаму мы робім гэта, і рэзюмэ, што мы зрабілі дагэтуль.
Чаму TraceMonkey вышуку JIT JägerMonkey. Вельмі хутка для кода, які ён можа JIT. Напрыклад, гэта 9x хутчэй, чым перакладнік SunSpider па math-cordic тэстаў. Але ён не можа сапраўды след тэсце, як date-format-tofte, у якім утрымоўваецца заклік eval у асноўны цыкл, таму адсочванне толькі дае 5% паскарэнне па гэтай праграме. Як Дэвід Андерсон словам, TraceMonkey мае ракетных паскаральнікаў, таму ён працуе вельмі хутка, калі паскаральнікі, але паскаральнікі не заўсёды можа быць уключаны.
(Гл. таксама артыкул хакі для значна больш фоне пра тое, як адсочванне прац.)
Ёсць шмат фактараў, якія могуць прадухіліць ракет з заваротку, так што насамрэч няма кароткае апісанне праграм, якія не след, але большасць з іх трапляюць у некалькі катэгорый:
eval у іх гарачых завес. TraceMonkey павінен ведаць усе зменныя і іх тыпы ў мэтах стымулявання тыпу спецыялізаваны код. Таму што eval патэнцыйна можа зрабіць што-небудзь, TraceMonkey павінны даць, калі ён бачыць eval. Ёсць некалькі іншых асаблівасцяў мовы і куту выпадках, што TraceMonkey не можам прасачыць па аналагічных чынніках. Гэтыя невядома адсутным праграмы выніку з двух асноўных фактараў дызайн:
eval. JIT, якія не спецыялізуюцца тыпу не маюць гэтых праблем. JIT, што тып спецыялізуецца толькі ледзь-ледзь, і толькі пры неабходнасці, таксама дазваляе пазбегнуць гэтых праблем. Заўважым, што хоць адсочванні JIT можа або тыпу спецыялізуюцца ці няма, і метад JIT Можна таксама ўвесці спецыялізуюцца ці няма, тып спецыялізацыі з'яўляецца натуральным спадарожнікам трасіроўкі. Разгледзім наступны код:
var x;
if (z) {
x = 3;
} else {
x = "hello";
}
var y = x + 77;
След JIT кампіляцыі будзе два следу, якія выглядаюць прыкладна так:
// trace 1 if (!z) exit this trace; x = 3; y = x + 77; // trace 2 if (z) exit this trace x = "hello"; y = x + 77;
Звернеце ўвагу, як тыпу X і Y цалкам вядомыя, так што гэта адносна лёгка цалкам тыпу спецыялізуюцца гэты код. Адпаведна, TraceMonkey прызначаны для заўсёды тыпу спецыялізуюцца ўсё. З іншага боку, метад JIT кампілюе ўвесь метад толькі адзін раз, так што метад JIT сапраўды не можам ведаць тып y, і павінны генераваць неспеціалізірованных кода.
(Але метад JIT можа тыпу спецыялізуюцца, і след JIT не прыйдзецца. Напрыклад, след JIT можа абраць для стварэння неспеціалізірованных кода. Але тады JIT становіцца ўсё больш складаным, ён павінен паняцце "невядомы "Тыпы і запатрабаванняў асобных функцый генерацыі кода для апрацоўкі гэтых выпадках. І метад JIT мог глядзець наперад, каб бачыць, што Ёсць толькі 2 розных тыпаў, і стварыць два тыпу спецыялізаваных выпадках. Ці ж гэта можа нават вырашыць, каб дубляваць заданне y усярэдзіне галін, каб ён мог быць тыпу спецыялізаваных. Але зноў жа, гэта робіць JIT больш складанымі, чым асноўныя, не-якая спецыялізуецца дызайн JIT метад.)
Так, тыпу, якая спецыялізуецца след JIT генеруе вельмі хутка код, але не можа генераваць код для сітуацый, апісаных вышэй. З іншага боку, неабавязкова, якія спецыялізуюцца метад JIT генеруе ўмерана хуткі код, але можа генераваць машынны код для любой праграмы JavaScript. Так два метаду дапаўняюць адзін аднаго, мы жадаем метад JIT для забеспячэння добрага базавага ўзроўня прадукцыйнасці, а затым код, сляды добра, адсочванні будзе пхаць прадукцыйнасць нават вышэй.
JägerMonkey дагэтуль. Зараз я скажу трохі больш пра тое, што мы рабілі дагэтуль на JägerMonkey.
Першае, што нам трэба было хутка асэмблеры для стварэння ўласнага кода. TraceMonkey мае ўласны код кампілятара, nanojit, але мы думалі, nanojit не з'яўляецца ідэальнай для JägerMonkey. Nanojit робіць нямала аптымізацый кампілятара серверная частка, як мёртвыя ліквідацыі крамы і агульных падвыразаў, які дазваляе генераваць хутчэйшы код, але робіць гэта займае больш часу для атрымання гэтага кода. Мы не чакаем, што ці гэтыя аптымізацый дапаможа ў вобласці Ягер, таму мы жадалі штосьці прасцей і хутчэй.
Мы вырашылі імпарту асэмблер ад крыніцы Apple Адкрыць Nitro JavaScript JIT. (Дзякуй, WebKit распрацоўнікаў!) Мы ведаем, што гэта проста і хутка ад гледзячы на яго, перш чым (я вымярэнні, якія паказалі, гэта быў вельмі хуткі ў складанні рэгулярных выразаў), гэта з адкрытым зыходным кодам, і гэта добра прадуманыя C + +, таму было выдатна падыходзіць. Julian Seward змена яго працаваць з нашай сістэмай зборкі і падтрымкі бібліятэк. Гэта ў наша дрэва з адпаведнай ліцэнзіі, і мы ўжо выкарыстоўваюць яго, каб атрымаць, што 18% паскарэнні я ўжо казаў.
Іншым ключавым кампанентам з'яўляецца метад JIT кампілятар сам, што Дэвід Андерсон распрацаваны і запушчаны. Цяпер гэта даволі просты, але працуе добра, таму я не нашмат больш, каб сказаць пра гэта прама цяпер. Адным з цікавых адзначыць, што Дэвід стварыў новую функцыю, якая робіць абстрактныя інтэрпрэтацыі байт-код для вылічэння глыбіні стэка і ўваходных рэбраў галіны. Кампілятар выкарыстоўвае вынікі некаторую аптымізацыю, які даў нам яшчэ 5% паскарэнне ці каля таго.
Нарэшце, у рамках праекта JägerMonkey, мы збіраемся зрабіць кучу змен у перакладніка, каб зрабіць яго больш прыдатным для JIT-аптымізацыі. Першая змена, зроблена Лукі Вагнер, складаецца ў спрашчэнні стэка перакладнік выкарыстоўвае для захоўвання часавых значэнняў і JavaScript кадраў стэка. Раней, кадраў стэка былі закладзены ў злучаны спіс памяці кавалкі, які трымае стэк памяці вельмі нізкая, але абцяжарвае вылучэнне новых кадраў стэка і рашэнні зменных і значэнні, якія захоўваюцца ў стэку. Лука змянілі яго на выкарыстанне "памяці пліты O '" адной, так вылучэнні новага стэка проста праверыць памер і паказальнік прырост, а значэнні і зменныя заўсёды па фіксаваных зрушэннях са стэка загалоўкі. Гэта робіць яго лягчэй пісаць JIT і прасцей для стварэння просты, хуткі код для доступу да стэк значэнняў. Мы былі прыемна здзіўлены тым, што стэк перабудова дала толькі 3-5% прырост хуткасці, як у перакладніка і JägerMonkey.
На дадзены момант усё выглядае добра. Наступны крок складаецца ў інтэграцыі з JägerMonkey трасіроўкі, таму мы можам выкарыстоўваць іх узаемадапаўняльнасць. Мы таксама працягнем з перакладнікам мадэрнізацыі і спрашчэнні. Нарэшце, я збіраюся паспрабаваць навукі, каб пазнаць больш пра існыя JavaScript кода і як лепш дызайн JägerMonkey, каб запусціць яго хутка.