加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

Groovy中方法的调用实现方式浅析(CallSite)

发布时间:2020-12-14 16:47:33 所属栏目:大数据 来源:网络整理
导读:? 在Groovy中可以很方便的交换两个变量的值,如: def?(a,?b)?=?[1,?2];(a,?b)?=?[b,?a]; ? 这样,a,b变量的值就交换了,那么Groovy是怎样实现的呢? ? 来看看生成的字节码文件,关键的代码如下: ??//?Method?descriptor?#39?()Ljava/lang/Object;??//?Stack:?4,?L

? 在Groovy中可以很方便的交换两个变量的值,如:

def?(a,?b)?=?[1,?2];
(a,?b)?=?[b,?a];


? 这样,a,b变量的值就交换了,那么Groovy是怎样实现的呢?


? 来看看生成的字节码文件,关键的代码如下:

??//?Method?descriptor?#39?()Ljava/lang/Object;
??//?Stack:?4,?Locals:?6
??public?java.lang.Object?run();
??????0??invokestatic?Main.$getCallSiteArray()?:?org.codehaus.groovy.runtime.callsite.CallSite[]?[17]
??????3??astore_1
??????4??iconst_2
??????5??anewarray?java.lang.Object?[41]
??????8??dup
??????9??iconst_0
?????10??iconst_1
?????11??invokestatic?java.lang.Integer.valueOf(int)?:?java.lang.Integer?[47]
?????14??aastore
?????15??dup
?????16??iconst_1
?????17??iconst_2
?????18??invokestatic?java.lang.Integer.valueOf(int)?:?java.lang.Integer?[47]
?????21??aastore
?????22??invokestatic?org.codehaus.groovy.runtime.ScriptBytecodeAdapter.createList(java.lang.Object[])?:?java.util.List?[53]
?????25??astore_2
?????26??aload_1
?????27??ldc?<Integer?1>?[54]
?????29??aaload
?????30??aload_2
?????31??iconst_0
?????32??invokestatic?java.lang.Integer.valueOf(int)?:?java.lang.Integer?[47]
?????35??invokeinterface?org.codehaus.groovy.runtime.callsite.CallSite.call(java.lang.Object,?java.lang.Object)?:?java.lang.Object?[57]?[nargs:?3]
?????40??astore_3?[a]
?????41??aload_1
?????42??ldc?<Integer?2>?[58]
?????44??aaload
?????45??aload_2
?????46??iconst_1
?????47??invokestatic?java.lang.Integer.valueOf(int)?:?java.lang.Integer?[47]
?????50??invokeinterface?org.codehaus.groovy.runtime.callsite.CallSite.call(java.lang.Object,?java.lang.Object)?:?java.lang.Object?[57]?[nargs:?3]
?????55??astore?4?[b]
?????57??aload_2
?????58??pop
?????59??iconst_2
?????60??anewarray?java.lang.Object?[41]
?????63??dup
?????64??iconst_0
?????65??aload?4?[b]
?????67??aastore
?????68??dup
?????69??iconst_1
?????70??aload_3?[a]
?????71??aastore
?????72??invokestatic?org.codehaus.groovy.runtime.ScriptBytecodeAdapter.createList(java.lang.Object[])?:?java.util.List?[53]
?????75??astore?5
?????77??aload_1
?????78??ldc?<Integer?3>?[59]
?????80??aaload
?????81??aload?5
?????83??iconst_0
?????84??invokestatic?java.lang.Integer.valueOf(int)?:?java.lang.Integer?[47]
?????87??invokeinterface?org.codehaus.groovy.runtime.callsite.CallSite.call(java.lang.Object,?java.lang.Object)?:?java.lang.Object?[57]?[nargs:?3]
?????92??astore_3?[a]
?????93??aload_1
?????94??ldc?<Integer?4>?[60]
?????96??aaload
?????97??aload?5
?????99??iconst_1
????100??invokestatic?java.lang.Integer.valueOf(int)?:?java.lang.Integer?[47]
????103??invokeinterface?org.codehaus.groovy.runtime.callsite.CallSite.call(java.lang.Object,?java.lang.Object)?:?java.lang.Object?[57]?[nargs:?3]
????108??astore?4?[b]
????110??aload?5
????112??areturn
????113??aconst_null
????114??areturn

??

? 反编译过来,类似于这样的代码:

public?Object?main(){
	org.codehaus.groovy.runtime.callsite.CallSite[]?callsite?=?Main.$getCallSiteArray();
	
	List?alist?=?org.codehaus.groovy.runtime.ScriptBytecodeAdapter.createList(new?Object[]{1,2});
	
	Object?a?=?callsite[1].call(alist,?0);//等价于?alist.getAt(0)?等价于alist.get(0);
	Object?b?=?callsite[2].call(alist,?1);//等价于?alist.getAt(1)?等价于alist.get(1);
	
	List?blist?=?org.codehaus.groovy.runtime.ScriptBytecodeAdapter.createList(new?Object[]{b,a});
	
	a?=?callsite[3].call(blist,?0);//等价于?blist.getAt(0)?等价于blist.get(0);
	b?=?callsite[4].call(blist,?1);//等价于?blist.getAt(1)?等价于blist.get(1);
}

private?static?synthetic?SoftReference<CallSiteArray>?$callSiteArray;

private?static?synthetic?org.codehaus.groovy.runtime.callsite.CallSite[]?$getCallSiteArray(){
	org.codehaus.groovy.runtime.callsite.CallSiteArray?rtrun?=?null;
	
	if(Main.$callSiteArray?==?null){
		rtrun?=?Main.$createCallSiteArray();
		Main.$callSiteArray?=?new?SoftReference<CallSiteArray>(temp);
	}else{
		rtrun?=?Main.$callSiteArray.get();
	}
	return?rturn.array;
}

private?static?synthetic?org.codehaus.groovy.runtime.callsite.CallSiteArray?$createCallSiteArray(){
	String[]?sarry?=?new?String[5];
	Main.$createCallSiteArray_1(sarry)
	
	return?new?CallSiteArray(Main.class,?sarry);
}

private?static?synthetic?void?$createCallSiteArray_1(java.lang.String[]?sarry){
	sarry[0]?=?"runScript";
	sarry[1]?=?"getAt";
	sarry[2]?=?"getAt";
	sarry[3]?=?"getAt";
	sarry[4]?=?"getAt";
}


? 可以很清楚的看到Groovy编译器所做的事情.


? 很简单,但是可以看出,Groovy的执行方式,编译器会根据方法的调用来创建对应的CallSiteArray对象,

? Groovy将很多方法的调用都改为CallSite.call方式的调用,利用这种方式来支持很多的动态特性.

??

? 比如上面的例子,Groovy通过创建CallSite,然后通过CallSite来调用 getAt 方法.

? Groovy将调用委托到CallSite后,开始时,CallSite的具体实现为CallSiteArray,?

??CallSiteArray通过将调用委托到org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSite,Object,Object[])方法

? 该方法负责创建具体的调用点对象,并执行对应方法.

? 这里最终创建的调用点对象为?org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.PojoMetaMethodSiteNoUnwrapNoCoerce,具体代码如下:

????public?static?class?PojoMetaMethodSiteNoUnwrapNoCoerce?extends?PojoMetaMethodSite?{

????????public?PojoMetaMethodSiteNoUnwrapNoCoerce(CallSite?site,?MetaClassImpl?metaClass,?MetaMethod?metaMethod,?Class?params[])?{
????????????super(site,?metaClass,?metaMethod,?params);
????????}

????????public?final?Object?invoke(Object?receiver,?Object[]?args)?throws?Throwable?{
????????????try?{
????????????????return?metaMethod.invoke(receiver,??args);
????????????}?catch?(GroovyRuntimeException?gre)?{
????????????????throw?ScriptBytecodeAdapter.unwrap(gre);
????????????}
????????}
????}

??

? 真实的调用会委托到这个类的invoke方法:

? 这里metaMethod具体的类型为:

? org.codehaus.groovy.runtime.dgm$243@527e5409[name: getAt params: [int] returns: class java.lang.Object owner: interface java.util.List]

?这个类没有源码,只有class文件,反编译如下:

import?java.util.List;
import?org.codehaus.groovy.reflection.CachedClass;
import?org.codehaus.groovy.reflection.GeneratedMetaMethod;
import?org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;

public?class?dgm$243?extends?GeneratedMetaMethod?{
	public?dgm$243(String?paramString,?CachedClass?paramCachedClass,?Class?paramClass,?Class[]?paramArrayOfClass)?{
		super(paramString,?paramCachedClass,?paramClass,?paramArrayOfClass);
	}

	public?Object?invoke(Object?paramObject,?Object[]?paramArrayOfObject)?{
		return?DefaultGroovyMethods
				.getAt((List)?paramObject,?DefaultTypeTransformation.intUnbox(paramArrayOfObject[0]));
	}

	public?final?Object?doMethodInvoke(Object?paramObject,?Object[]?paramArrayOfObject)?{
		paramArrayOfObject?=?coerceArgumentsToClasses(paramArrayOfObject);
		return?DefaultGroovyMethods
				.getAt((List)?paramObject,?DefaultTypeTransformation.intUnbox(paramArrayOfObject[0]));
	}
}


? 可以看到,具体的调用又是:org.codehaus.groovy.runtime.DefaultGroovyMethods.getAt(List<T>,int)

????/**
?????*?Support?the?subscript?operator?for?a?List.
?????*?<pre?class="groovyTestCase">def?list?=?[2,?"a",?5.3]
?????*?assert?list[1]?==?"a"</pre>
?????*
?????*?@param?self?a?List
?????*?@param?idx??an?index
?????*?@return?the?value?at?the?given?index
?????*?@since?1.0
?????*/
????public?static?<T>?T?getAt(List<T>?self,?int?idx)?{
????????int?size?=?self.size();
????????int?i?=?normaliseIndex(idx,?size);
????????if?(i?<?size)?{
????????????return?self.get(i);
????????}?else?{
????????????return?null;
????????}
????}


? 终于,一个方法的调用完成了,可以看到,虽然提供了很高的灵活性,但是也牺牲了一部分性能.


? PS: Groovy会将上面创建的CallSite对象缓存,且为SoftReference类型.


? 说了个大概,具体的细节还有很多~~~

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读