Поддержка Java 8 в Excelsior JET -...
Transcript of Поддержка Java 8 в Excelsior JET -...
ПоддержкаJava8вExcelsiorJETНикитаЛипскийExcelsiorLLC
1
Ктознаетпросебя?• Более20летпрофессиональнойкарьеры• ИнициаторпроектаExcelsiorJET
– работалнадпроектомболее16лет– какидейныйвдохновитель– компиляторныйинженер– руководитель– имноговкакихещеролях
• OpensourceпроектыWebFXиJavaReStart– всвободноеотработывремя
• twi_er:@pjBooms
2
КтознаетпроExcelsiorJET?• ПолнаяреализацияJavaSE
– c2005годаcертифицированакакJavaCompahble
• AOTcompiler+JavaRunhme– смешаннаякомпиляция:AOT+JIT– поддержканестандартныхзагрузчиковклассоввAOTрежиме(для
EclipseRCP,Tomcat)
• Toolkit– StartupOphmizer– Deployment
3
КтознаетпроExcelsiorJET?
КтознаетпроExcelsiorJET?КтознаетпроExcelsiorJET?
4
ЧтодобавленовJava8• Lambda-expressions• DefaultMethods• StreamAPI,TimeAPI• Typeannotahons,Parameternames• JavaFX8• Nashorn• CompactProfiles
5
Defaultmethods
6
DefaultMethods• Методыстеламивинтерфейсах– Мотивация:расширениеJavaAPI,неломаяобратнуюсовместимость
List<Person> list = ... list.forEach(System.out::println)
forEach нетвJava7
7
DefaultMethodsПовлиялинаспецификациюJVM:• Измениласьсемантикаинструкций:
– Invokespecial– invokevirtual– invokeinterface– invokestahc
• Измениласьпроцедурастатическойинициализациикласса
8
Resolveметода• Всеinvokeинструкции(кромеinvokedynamic)ссылаютсянавызываемыйметодcимвольно
• Передтемкакinvokeинструкцияисполнится,должнапройтипроцедураразрешениясимвольнойссылкинаметод
9
ResolveметодаПустьестьссылкаC.foo():• ИщемfooвC:• Еслиненашли,ищемfooвсуперклассахC• Еслиненашли,ищемfooвсуперинтерфейсахC• NewinJava8:– припоискеметодавсуперинтерфейсах,вначалеищетсямаксимальноспецифичныйdefaultметод
10
ResolveметодаМаксимальноспецифичныйdefaultметод:• defaultметод,которыйнепереопределяетсявпотомкахданногоинтерфейса,которыеимплементируетсяклассомC
• Еслиесть,тодолженбытьодин– ИначепроцедурарезолвабросаетIncompahbleClassChangeError
11
Resolveметодаinterface I { default void foo(){…}}
class A { void foo(){…}}
class C extends A implements I{}
C.foo() - ?
12
Resolveметодаinterface I { default void foo(){…}}
interface J extends I { default void foo(){…}}
class C implements J,I { }
C.foo() - ?
13
Resolveметодаinterface I { default void foo(){…}}
interface J { default void foo(){…}}
class C implements J,I { }
C.foo() - ?
14
invokespecial• Используетсядлявызоваконструкторовисуперметодов
• Целевойметодвызовастатическивычислим– можетвызыватьсянапрямую– можетинлайнитьсясразуввызывающийметод
• Вызываетметод(чащевсего),которыйвозвращаетсяпроцедуройresolveметода– т.o.можетвызыватьdefaultметодывJava8
15
invokespecial• ПоддержкавAOTкомпиляторе:– Resolveметодовпроисходитдоисполненияпрограммы(нопоJVMспецификации)
– Каждыйметод,каждогокомпилируемогоклассакомпилируетсявмашинныйкодиимеетадрес
– invokespecial<MethofRef>транслируетсяв:call<MethodAddress>
16
invokevirtual• Вызываемыйметодзависитотобъектаполучателя(this)
• Транслируетсявкосвенныйвызовчерезтаблицувиртуальныхметодов
invokevirtual<MethofRef>->call[<VMTAddress>+MethodSlotInVMT*C]
17
invokevirtual• Схемапредставленияобъектавпамяти
18
19
abstract class A implements I { { void meth1(){…} abstract void meth2();}interface I { void meth3();}
class C extends A { void meth2(){…} void meth3(){…} void meth4(){…} }
AbstractMethodError
20
abstract class A implements I { { void meth1(){…} abstract void meth2();}interface I { void meth3();}
class C extends A { implements J { void meth2(){…}}interface J { default void meth3(){…} default void meth4(){…}}
AbstractMethodError
NewinJava8
ПоддержкаdefaultметодоввExcelsiorJET
• Компиляцияметодовинтерфейсов• Изменениепроцедурырезолваметодов• ИзменениепроцедурызаполненияVMT
21
НайденныебагиприподдержкиJava8вExcelsiorJET
• ВJVMспецификации– overrideметода
(h_ps://bugs.openjdk.java.net/browse/JDK-8098577)• ВHotSpot
– статическаяинициализацияклассоввприсутствииdefaultметодовинициализируетбольшеклассовчемнужно(h_ps://bugs.openjdk.java.net/browse/JDK-8098557)
– вresolveметодов:“InterfaceMethodCPentrypoinhngtoaclassshouldcauseICCE”(h_ps://bugs.openjdk.java.net/browse/JDK-8087223)
22
Lambdaвыражения
23
ЛямбдавыраженияБыло
new Thread(new Runnable() { public void run() {
System.out.println(“Hi,I’m Thread”); }}).start();
24
ЛямбдавыраженияСтало…
new Thread(new Runnable() { public void run() {
System.out.println(“Hi,I’m Thread”); }}).start();
25
ЛямбдавыраженияСталоnew Thread(()->
System.out.println(“Hi,I’m Thread”)).start();
26
Лямбдавыражения
Каклямбда-выраженияповлиялинаспецификациюJVM?
27
Лямбдавыражения
Каклямбда-выраженияповлиялинаспецификациюJVM?Никак!
28
ТрансляциялямбдавыраженийвJavaбайткод
class B { public void foo() { List<Person> list = ... final int bottom = ..., top = ...; list.removeIf( p ->
(p.size >= bottom && p.size <= top) ); }}
29
ТрансляциялямбдавыраженийвJavaбайткод
class B { public void foo() { List<Person> list = ... final int bottom = ..., top = ...; list.removeIf(new Predicate() { public boolean apply(Person p) { (p.size >= bottom && p.size <= top); } ); }}
30
ТрансляциялямбдавыраженийвJavaбайткод
class B { public void foo() { List<Person> list = ... final int bottom = ..., top = ...; list.removeIf(new Predicate() { public boolean apply(Object o) { (p.size >= bottom && p.size <= top); } ); }}
31
ТрансляциялямбдавыраженийвJavaбайткод
class B { public void foo() { List<Person> list = ... final int bottom = ..., top = ...; list.removeIf(
[lambda for lambda$1 as Predicate capturing (bottom, top) ] }
static boolean lambda$1(int bottom, int top, Person p) { return p.size >= bottom && p.size <= top; }}
32
ТрансляциялямбдавыраженийвJavaбайткод
class B { public void foo() { List<Person> list = ... final int bottom = ..., top = ...; list.removeIf( indy((MH(metaFactory), //bootstrap MH(invokeVirtual Predicate.apply), MH(invokeStatic B.lambda$1))(bottom, top)) }
static boolean lambda$1(int bottom, int top, Person p) { return p.size >= bottom && p.size <= top; }}
33
Лямбда-выражения
АIndy–этофичаJava7!
34
IndyIndy–сокращениеотinvokedynamic• Впервыйразindyзоветbootstrapметод,
которыйвозвращаетобъектCallSite• Далееиприпоследующихвызовахотобъекта
callsiteберетсяМethodHandleизоветсяinvokeExact
35
MethodHandleMethodHandle–целевойобъектindy:• можетбытьдоступомкполю,методу• адаптеромдругихMethodHandle
– адаптерыаргументов– частичноеприменениеаргументов(binding)– условныйпереход(guardWithTest)
Должныработатьбыстро– ВсечтоможновыразитьчерезMethodHandle,можновыразить
черезReflechon,ноэтонеэффективно
36
MethodHandleMethodHandlescJava7Update40реализованычерезlambda-forms:– Внутреннеепредставлениеметодхэндлов– ПоэтомувнутреннемупредставлениюдинамическипорождаетсяJavaбайткод(Runhmeанонимныеклассы)
– Реализациясостоитна90%изpureJavaкодаипереиспользуетсявExcelsiorJET
37
Runfmeанонимныеклассы• Настолькоанонимные,чтоихдаженетвJVMспецификации– полнуюсемантикувозможновычислитьтолькоизисходныхтекстовHotSpot
38
Runfmeанонимныеклассы• ИзJavaсоздаютсячерез
Unsafe.defineAnonymousClass
• Непринадлежаткакому-либокласслоадеру,ихнельзянайти,нетreflechon
• ВJava8ихсемантикапоменялась– онимогутдоступатьсядоprivateчленовклассовихпородивших(дотеллямбд)
39
ВернемсяклямбдамЗадача:ПустьестьJavaкодRunnable r = ()->System.out.println(“Hi”);r.run();Требуется:вместоэтогокодапородить:System.out.println(“Hi”);
40
РешениеHotSpot• Исполняемкодметода,покаоннестанетгорячим– порождаяизагружаяанонимныйкласс-заверткудлялямбдавыражения
• Инлайнимвкодцелевогометодасначалакодединственногометодаанонимногокласса,азатемисамотелолямбды
• АнонимныйкласссобираемGC
41
РешениеJET*• Восстанавливаемизбайткодавстатическом
компиляторелямбда-выражениевисходномвиде
• Вычисляем,чтоединственноеиспользованиелямбды–этоеенепосредственныйвызов
• Инлайнимтелолямбдавыражения*Поканереализовано
42
РешениеJET*Аеслинамнеудалосьзаинлайнитьметодкудапередаетсялямбда-выражение?
43
РешениеJET*
44
(p -> (p.size >= bottom && p.size <= top))
lambda$1:кодтелалямбды
захваченныйконтекст
РешениеJET*
45
(p -> (p.size >= bottom && p.size <= top))
j.l.Objectmethods
привызовеgetClass(),создаетсяклассналету
lambda$1:кодтелалямбды
захваченныйконтекст
Ненужносоздаватьклассдлябольшинстваслучаев
ЛямбдывJET:текущийстатус• покаработаютчерезindy,нотелалямбдстатическикомпилируются
• динамическаякомпиляцияклассов-завертокдлялямбдоченьбыстрая(<1ms)
• настандартныхбенчмарках,иреальныхприложенияхпоканебылозамеченоуменьшенияпроизводительностииз-залямбд
46
Типовыеаннотации
47
ТиповыеаннотацииМогутбытьвездегдеестьтип:
class TypeAnnotationsExample { @Encrypted String data; List<@NonNull String> strings; HashSet names = (@Immutable HashSet) set;
}
48
Типовыеаннотации• КодируютсявJavaбайткодеатрибутомтипаRunhme(In)VisibleTypeAnnotahon–новыеатрибутыJava8байткода
• ДоступныврантаймчерезReflechonAPI:– getTypeAnnotahons
КакпредставляютсявExcelsiorJET?
49
ReflecfonвHotSpot• HotSpotJVMхранитвMetaSpaceрантаймпредставлениеJavaкласс-файла
• Вкласс-файлеестьвсянужнаяинформациядляreflechon
• РеализацияReflechonAPIвHotSpotработаетнепосредственноскласс-файлами
50
ReflecfonвExcelsiorJET• Послестатическойкомпиляцииотклассовнеостаетсякласс-файлов– ПослерезолвассылоквAOTкомпилятореитрансляциибайткодавмашинныйкод,большаячастькласс-файластановитсяненужнавсвоемпервоначальномвиде.
• Мета-информацияоклассахпишетсявисполняемыйфайлвсекциюданных
• Пишетсятолькото,чтонеобходимоReflechon– именаполей,методов,аннотации
51
ReflecfonвExcelsiorJET• АннотациипишутсявформатеоченьпохожемнаформатаннотацийвJavaбайткоде– можнопереиспользоватьJavaкод,которыйихразбирает
ДляJava8AOTкомпиляторпришлосьнаучитьсохранятьтиповыеаннотации
52
Именапараметров• Еслиjavac задатьключ–parameters,то– вкласс-файлбудутписатьсяименапараметров– именапараметровбудутдоступнычерезreflechon
КакпредставляютсявExcelsiorJET?
Легко!53
NewJava8APIs
54
NewJava8APIs• StreamAPI• TimeAPI• JavaFX8• Nashorn
КакподдерживаютсявJET?ТакжекакивсеостальныеJavaAPI!
55
NewJava8APIs• StreamAPI• TimeAPI• JavaFX8• Nashorn
КакподдерживаютсявJET?ТакжекакивсеостальныеJavaAPI!
56
NewJava8APIs• Excelsior–официальныйJavaSElicensee– лицензируемвсеисходныетекстыJavaSEуOracle– можемпоступатьснимикакхотим,напримеркомпилироватьJavaбайт-кодплатформывмашинныйкодииспользоватьсвоюреализациюJVM
– обязаныпроходитьтестынасовместимость(JCK)
57
NewJava8APIsНевсеJava8APIsодинаковостандартны:• StreamAPI,TimeAPIвходятвстандарт
Java8
• Nashorn,JavaFXНЕвходятвстандартJavaSE– вчастностинеттестовJCK
58
СтруктураOracleJRE
59
СтруктураOracleJRE• КлассыNashornиJavaFXнаходятсявпапкеext– грузятсяExtensionкласслоадером
• ВсечтонаходитсявпапкеextможноофициальноневключатьвPrivateJREдистрибутивасвоегоприложения
60
РаспространениеприложенийскомпилированныхExcelsiorJET
• СкомпилированныеспомощьюExcelsiorJETприложениявсегдараспространяютсясприватнойкопиейJETRunhme:– вашипользователинедолжныставить“ExcelsiorJRE”
61
РаспространениеприложенийскомпилированныхExcelsiorJET
• СтруктураJETRunhmeнадискеоченьпохожанаOracleJRE:– ресурсы(шрифты,картинки)ибиблиотекисnahveметодаминаходятсянатехжеместах
– классыизrt.jarидругих.jarкомпилируютсявнаборDLL
62
JetPackII
Подготавливаетвашеприложениедлядальнейшегораспространения
63
JetPackII• JET-скомпилированныеисполняемыефайлысвязываютсясприватнойкопиейJETRunhme
• ПозволяетвыбиратьнужныечастиJETRunhmeдлявашегоприложения
• NewinJava8:позволяетНЕвключатьJavaFXиNashorn,еслионинеиспользуютсявашимприложением
64
CompactProfiles
65
CompactProfiles Compact1 Compact2 Compact3
java.lang java.rmi java.lang.instrument
java.io java.sql java.lang.management
java.math javax.transachon javax.management
java.nio javax.xml javax.naming
java.uhl org.w3c.dom javax.script
java.net org.xml.sax javax.security
java.security javax.sql
javax.crypto javax.xml.crypto
java.text org.ie¥.jgss
66
CompactProfiles• ЕстьвJavaSEEmbedded(Linuxbuilds)• ВOpenJDK(несобираютсянаWindowsиMacOSX)
67
ИсториякомпонентизацииJavaSEотExcelsior
• РазбиениеJavaSEнаAPIs(2000год)– компиляцияихвDLL
• JetPerfect(2001год)– компиляцияприложенийснужнымичастямиJavaSEводинEXEфайл
– SWTExample:1.4MB• JavaRunhmeSlim-Down(2007год)
– совместимоесJavaSEспецификациейрешение• CompactProfiles(2016год)
68
ИсториякомпонентизацииJavaSEотSun/Oracle
• KernelJRE(2006год)
• ProjectJigsaw2007–2017(?)
• CompactProfiles(2014год)
69
CompactProfiles• ПервыйрабочийилегальныйспособуменьшенияPrivateJRE
• ЕстьJCK(тестысовместимости)
70
CompactProfiles• ПервыйрабочийилегальныйспособуменьшенияPrivateJRE
• ЕстьJCK(тестысовместимости)
• ЕстьвExcelsiorJETдлявсехдесктопныхплатформ(Windows,Linux,MacOSX)
71
CompactProfiles• ПоддержкавExcelsiorJET:– ПереразбивкаJETRTDLLsпограницамCompactProfiles
– ПоддержкавJetPackII:паковкаприложенияскомпактнымпрофилем,накоторомможетбытьзапущеноприложение
– ПроходитJCKдлясоответствующихкомпактныхпрофилей
72
JavaFXonCompactProfiles
73
JavaFX8onCompactProfiles• JavaFXусловносостоитизтрехлогическихчастей:– CoreJavaFX– JavaFXWeb(WebKitbased)– JavaFXbridgestoSwingиSWT
74
JavaFX8onCompactProfiles• CoreJavaFXможетработатьнаCompact2– FXMLзависитотXML
• JavaFXSwingBridgeтребуетFullJavaSE– ТаккакочевиднозависитотSwing
75
JavaFX8onCompactProfiles• JavaFXWebтожеимеетзависимостиотAWT…
76
JavaFX8onCompactProfiles• JavaFXWebтожеимеетзависимостиотAWT,которыенеразрешаютсявовремяисполненияJ!
77
JavaFX8onCompactProfiles• JavaFXWebтожеимеетзависимостиотAWT,которыенеразрешаютсявовремяисполнения,кромеоднойL…
78
JavaFX8onCompactProfiles• JavaFXWebтожеимеетзависимостиотAWT,которыенеразрешаютсявовремяисполнения,кромеодной,котораятоженеразрешаетсяврежиме-Xverify:none
79
JavaFX8onCompactProfilesПоддержкаJavaFXWebвExcelsiorJET:• зависимостиотAWTоткладываютсядоразрешениявовремяисполнения– неразрешаютсявстатическомкомпиляторе
• ВсеклассыJavaFXверифицируютсядоисполнения– нетребуетсяверификациявовремяисполненияизагрузка“лишних”классов
• ВрезультатеJavaFXWebработаетнаCompact2!
80
JavaPackager(OracleJDK)vs.JetPackII(ExcelsiorJET)
JavaPackager
JetPackIIwithCompactProfiles
EnsembleDemo
(withWebViewsample)
46MB 21MB
BrickBreaker 42MB 10MB
81
Примечание:замерыпроизводилисьнаWindows32-bitдляJava8Update72,представленыразмерыдистрибутивовбеззависимостей
Заключение• Java8–лучшийрелизJavaсовременJava5– лямбдыповышаютпроизводительностьтруда
• ЛямбдынеповлиялинаспецификациюJVM– ножелательнаспециальнаяподдержкавJVM
• CompactProfilesуменьшаютразмерPrivateJRE– важнодлямагазиновприложенийивembedded
• Java!=HotSpot82