Поддержка Java 8 в Excelsior JET -...

Post on 21-Aug-2020

18 views 0 download

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

Вопросыиответы

НикитаЛипский,Excelsior

nlipsky@excelsior-usa.comtwi_er:@pjBooms

83