模塊一java虛擬機(jī)基本原理12講09丨jvm是怎么實(shí)現(xiàn)invokedynamic下_第1頁
模塊一java虛擬機(jī)基本原理12講09丨jvm是怎么實(shí)現(xiàn)invokedynamic下_第2頁
模塊一java虛擬機(jī)基本原理12講09丨jvm是怎么實(shí)現(xiàn)invokedynamic下_第3頁
模塊一java虛擬機(jī)基本原理12講09丨jvm是怎么實(shí)現(xiàn)invokedynamic下_第4頁
模塊一java虛擬機(jī)基本原理12講09丨jvm是怎么實(shí)現(xiàn)invokedynamic下_第5頁
已閱讀5頁,還剩23頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

及方法給了應(yīng)用程序。在運(yùn)行過程中,每一條invokedynamic指令將一個(gè)調(diào)invokedynamic指令時(shí),Java(BootStrapMethod),invokedynamic指令中。在之后的運(yùn)行過程中,Java虛擬機(jī)則會(huì)直接調(diào)用綁定的調(diào)用點(diǎn)所的方法句p夠的方法句柄的類型。1import2classHorsepublicvoidrace() 78classDeerpublicvoidrace() 13//javac//javapublicclassCircuitpublicstaticvoidstartRace(Objectobj)//aload//invokedynamic publicstaticvoidmain(String[]args)startRace(new//startRace(new 33

publicstaticCallSitebootstrap(MethodHandles.Lookupl,Stringname,MethodTypecallMethodHandlemh=l.findVirtual(Horse.class,name,MethodType.methodType(void.classreturnnewConstantCallSite(mh.asType(callSiteType));}并且返回一個(gè)至Horse.race方法的ConstantCallSite。這里的ConstantCallSite是一種不可以更改對(duì)象的調(diào)用點(diǎn)。除此之外,Java類庫還提供多種可以更改對(duì)象的調(diào)用點(diǎn),比如MutableCallSite和VolatileCallSite。volatile由于Java暫不支持直接生成invokedynamic指令[1] 字節(jié)碼工具ASM來實(shí)現(xiàn)這一目的importjava.io.IOExcepimporjaa.anginokimportjava.no45import6//javac-cp/path/to/asm-all-6.0_BETA.jar:.//java-cp/path/to/asm-all-6.0_BETA.jar:.//javapublicclassASMHelperimplementsOpcodes privatestaticclassMyMethodVisitorextendsMethodVisitorprivatestaticfinalStringBOOTSTRAP_CLASS_NAME=Circuit.class.getName().reprivatestaticfinalStringBOOTSTRAP_METHOD_NAME=bootstrapprivatestaticfinalStringBOOTSTRAP_METHOD_DESC=.methodType(CallSite.class,MethodHandles.Lookup.class,String.class, privatestaticfinalStringTARGET_METHOD_NAME=race privatestaticfinalStringTARGET_METHOD_DESC=(Ljava/lang/Object;)V publicfinalMethodVisitor publicMyMethodVisitor(intapi,MethodVisitormv)this.mv=}publicvoidvisitCode()mv.visitVarInsn(ALOAD,Handleh=newHandle(H_INVOKESTATIC,BOOTSTRAP_CLASS_NAME,mv.visitInvokeDynamicInsn(TARGET_METHOD_NAME,TARGET_METHOD_DESC,mv.visitMaxs(1,}}publicstaticvoidmain(String[]args)throwsIOExceptionClassReadercr=newClassWritercw=new ClassVisitorcv=newClassVisitor(ASM6,cw)publicMethodVisitorvisitMethod(intaccess,Stringname,Stringdescriptor,String[]exceptions)MethodVisitorvisitor=super.visitMethod(access,name,descriptor,if("startRace".equals(name))returnnewMyMethodVisitor(ASM6,}return}cr.accept(cv,Files.write(Paths.get("Circuit.class"),}} 下Circuit類1staticvoid20:31:invokedynamic#80,0//46:如果你足夠細(xì)心的話,你會(huì)發(fā)現(xiàn)該指令所調(diào)用的賽跑方法的描述符,和Horse.ae者ae方法的描述符并不一致。這是因?yàn)閚vonamic指令最終調(diào)用的是方法句柄,而方法句柄會(huì)將調(diào)用者當(dāng)成第一個(gè)參數(shù)。因此,剛剛提到的那兩個(gè)方法恰恰符合這個(gè)描述符所對(duì)應(yīng)的方法句柄類型。到目前為止,我們已經(jīng)可以通過invokedynamic調(diào)用Horse.race方法了。為了支持調(diào)用任意類的race方法,我實(shí)現(xiàn)了一個(gè)簡單的單態(tài)內(nèi)聯(lián)緩存。如果調(diào)用者的類型命中緩存中的1//需要更改ASMHelper.MyMethodVisitor中的2import34publicclassMonomorphicInlineCache5privatefinalMethodHandles.LookupprivatefinalString8publicMonomorphicInlineCache(MethodHandles.Lookuplookup,Stringname)this.lookup== privateClass<?>cachedClass=privateMethodHandlemh=publicvoidinvoke(Objectreceiver)throwsThrowableif(cachedClass!=receiver.getClass())cachedClass=mh=lookup.findVirtual(cachedClass,name, publicstaticCallSitebootstrap(MethodHandles.Lookupl,Stringname,MethodTypeMonomorphicInlineCacheic=newMonomorphicInlineCache(l,MethodHandlemh=l.findVirtual(MonomorphicInlineCache.class,"invoke",returnnew 30不過,這正是mc的目的,也就是將調(diào)用點(diǎn)與目標(biāo)方法的交由應(yīng)用程序來做,并且依賴于應(yīng)用程序?qū)δ繕?biāo)方法進(jìn)行驗(yàn)證。所以,如果應(yīng)用程序?qū)①惻芊椒ㄖ镣米拥乃X方法,那也只能怪應(yīng)用程序自己了。Java8的Lambda在Java8中,Lambdainvokedynamic具體來說,Java編譯器利用invokedynamic的函數(shù)式接口指的是僅包括一個(gè)非default接口方法的接口,一般通過@FunctionalInterface注解。不過就算是沒有使用該注解,Java編譯器也會(huì)將符合條件的intx=IntStream.of(1,2,3).map(i->i*2)ap(i>i* 上面這段代碼會(huì)對(duì)IntStream中的元素進(jìn)行兩次映射。我們知道,映射方法map所接收的參數(shù)是IntUnaryOperator(這是一個(gè)函數(shù)式接口)。也就是說,在運(yùn)行過程中我們需要將i->i2和i->ix這兩個(gè)Lambda表達(dá)式轉(zhuǎn)化成IntUnaryOperator的實(shí)例。這個(gè)轉(zhuǎn)化過程便是由invokedynamic來實(shí)現(xiàn)的。在編譯過程中,Java編譯器會(huì)對(duì)dadr)LambdaLambda數(shù),還包含它所捕獲的變量。(注:方法,如e,則不會(huì)生成生成額外的方在上面那個(gè)例子中,第一個(gè)LambdaLambda(i->i*x)xLambda //i->i*2staticint3456789//i-i*staticintlambda$1(int,第一次執(zhí)行invokedynamic指令時(shí),它所對(duì)應(yīng)的啟動(dòng)方通過ASM來生成一個(gè)適配器IntUnaryOperator。啟動(dòng)方法的返回值是一個(gè)ConstantCallSite,其對(duì)象為一個(gè)返回根據(jù)Lambda表達(dá)式是否捕獲其他變量,啟動(dòng)方法生成的適配器類以及所的方法句柄LambdaLambdainvokedynamic另外,為了保證Lambda表達(dá)式的線程安全,我們無法共享同一個(gè)適配器類的實(shí)例。因此,在每次執(zhí)行invokedynamic指令時(shí),所調(diào)用的方法句柄都需要新建一個(gè)適配器類實(shí)例。你可以通過虛擬機(jī)參數(shù)-Dernal.lambda.dumpClasses=/DUMP/PATH導(dǎo)出這些具體的適配器類。這里我導(dǎo)出了上面這個(gè)例子中兩個(gè)Lambda表達(dá)式對(duì)應(yīng)的適配器//i->i*2finalclassLambdaTest$$Lambda$1implementsIntUnaryOperatorprivate0:1:invokespecial4:8publicint0:1:invokestatic4:14//i->i*xfinalclassLambdaTest$$Lambda$2implementsIntUnaryOperatorprivatefinalintprivate0:1:invokespecial4:5:6:putfield9:privatestaticjava.util.function.IntUnaryOperator0:new3:4:5:invokespecial8:publicint0:1:getfield4:5:invokestatic8:44Lambdaget$Lambdainvokedynamic指令時(shí),都會(huì)調(diào)用至這個(gè)方法中,并構(gòu)造一個(gè)新的適配器類實(shí)例。Lambdav6import34publicclassTest5publicstaticvoidtarget(inti){67publicstaticvoidmain(String[]args)throwsException8longcurrent=9for(inti=1;i<=2_000_000_000;i++)if(i%100_000_000==0)longtemp=System.out.println(temp-current=}((IntConsumer)j->//((IntConsumer)}}}LambdainvokedynamicIntConsumer.acceptLambda另一方面,對(duì)IntConsumer.accept方法的調(diào)用實(shí)則是對(duì)適配器類的accept方法的調(diào)用。如果你查看了accept方法對(duì)應(yīng)的字節(jié)碼的話,你會(huì)發(fā)現(xiàn)它僅包含一個(gè)方法調(diào)用,調(diào)用至JavaLambdaLambdaTest.target。將這幾個(gè)方法調(diào)用內(nèi)聯(lián)進(jìn)來之后,原本對(duì)accept方法的調(diào)用則會(huì)被優(yōu)化為空操作。下面我將之前的代碼更改為帶捕獲變量的v7版本。理論上,每次調(diào)用invokedynamic指令,Javav7import3publicclassTestpublicstaticvoidtarget(inti){6publicstaticvoidmain(String[]args)throwsExceptionintx=9longcurrent=for(inti=1;i<=2_000_000_000;i++) if(i%100_000_000==0)longtemp=System.out.println(temp-current= ((IntConsumer)j->Test.target(x+ 21XX:-DoEscapeysis來關(guān)閉逃逸分析。果然,這時(shí)候測得的值約為直接調(diào)用的2.5倍。兩件事:invokedynamic指令所執(zhí)行的方法句柄能夠內(nèi)聯(lián),和接下來的對(duì)accept方法的適配器類實(shí)例。所以,我們應(yīng)當(dāng)盡量使用非捕獲的Lambda表達(dá)式。invokedynamic指令以及Lambdaymaic指令出調(diào)的概并且用該點(diǎn)所的方柄。一amicJava虛擬機(jī)將執(zhí)行它所對(duì)應(yīng)的啟動(dòng)方法,生成并且綁定一個(gè)調(diào)用點(diǎn)。之后如果再次執(zhí)行該指令,Java虛擬機(jī)則直接調(diào)用已經(jīng)綁定了的調(diào)用點(diǎn)所鏈接的方法。對(duì)于沒有捕獲其他變量的Lambda表達(dá)式,該invokedynamic指令始終返回同一個(gè)適配器類的實(shí)例。對(duì)于捕獲了其他變量的Lambda表達(dá)式,每次執(zhí)行invokedynamic指令將不管是捕獲型的還是未捕獲型的Lambda表達(dá)式,它們的性能上限皆可以達(dá)到直接調(diào)用的性能。其中,捕獲型Lambda表達(dá)式借助了即時(shí)編譯器中的逃逸分析,來避免實(shí)際的新建在上一篇的課后實(shí)踐中,你應(yīng)該測過這一段代碼的性能開銷了。我這邊測得的結(jié)果約為直接5v8importimportimport5publicclassTestpublicstaticvoidtarget(inti){8925

publicstaticvoidmain(String[]args)throws{MethodHandles.Lookupl=MethodHandles.lookup();MethodTypet=MethodType.methodType(void.class,int.class);MethodHandlemh=l.findStatic(Test.class,"target",t);longcurrent=System.currentTimeMillis();for(inti=1;i<=2_000_000_000;i++){if(i%100_000_000==0)longtemp=System.currentTimeMillis();System.out.println(temp-current);current=temp;}}}實(shí)際上,它與使用Lambda表達(dá)式或者方法的差別在于,即時(shí)編譯器無法將該方法句法便是將其賦值給final的靜態(tài)變量,如下面的v9v9importimportimport5publicclassTestpublicstaticvoidtarget(inti){8staticfinalMethodHandlestatictryMethodHandles.Lookupl=MethodTypet=MethodType.methodType(void.class,mh=l.findStatic(Test.class,"target",}catch(Throwablee)thrownew publicstaticvoidmain(String[]args)throwsThrowablelongcurrent=32

for(inti=1;i<=2_000_000_000;{if(i%100_000_000==0)longtemp=System.currentTimeMillis();System.out.println(temp-current);current=temp;}}}v10v11//v10import34publicclassTest publicstaticvoidtarget(inti) 7 publicstaticclassMyCallSite9 publicfinalMethodHandlepublicMyCallSite()mh= privatestaticMethodHandlefindTarget()tryMethodHandles.Lookupl=MethodTypet=MethodType.methodType(void.class,returnl.findStatic(Test.class,"target",}catch(Throwablee)thrownew 41

privatestaticfinalMyCallSitemyCallSite=newpublicstaticvoidmain(String[]args)throws{longcurrent=System.currentTimeMillis();for(inti=1;i<=2_000_000_000;i++){if(i%100_000_000==0)longtemp=System.currentTimeMillis();System.out.println(temp-current);current=temp;}}}//v11importpublicclassTestpublicstaticvoidtarget(inti)} publicstaticclassMyCallSiteextendsConstantCallSitepublicMyCallSite() privatestaticMethodHandlefindTarget()tryMethodHandles.Lookupl=MethodTypet=MethodType.met

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論