博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Groovy中方法的调用实现方式浅析(CallSite)
阅读量:6287 次
发布时间:2019-06-22

本文共 7010 字,大约阅读时间需要 23 分钟。

hot3.png

  在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 
 [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 
 [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 
 [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 
 [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;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
(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.     * 
def list = [2, "a", 5.3]     * assert list[1] == "a"     *     * @param self a List     * @param idx  an index     * @return the value at the given index     * @since 1.0     */    public static 
 T getAt(List
 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类型.

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

转载于:https://my.oschina.net/haogrgr/blog/410569

你可能感兴趣的文章
数据库
查看>>
Vue------第二天(计算属性、侦听器、绑定Class、绑定Style)
查看>>
dojo.mixin(混合进)、dojo.extend、dojo.declare
查看>>
Python 数据类型
查看>>
iOS--环信集成并修改头像和昵称(需要自己的服务器)
查看>>
PHP版微信权限验证配置,音频文件下载,FFmpeg转码,上传OSS和删除转存服务器本地文件...
查看>>
教程前言 - 回归宣言
查看>>
PHP 7.1是否支持操作符重载?
查看>>
Vue.js 中v-for和v-if一起使用,来判断select中的option为选中项
查看>>
Java中AES加密解密以及签名校验
查看>>
定义内部类 继承 AsyncTask 来实现异步网络请求
查看>>
VC中怎么读取.txt文件
查看>>
如何清理mac系统垃圾
查看>>
企业中最佳虚拟机软件应用程序—Parallels Deskto
查看>>
送给“正在纠结”、“准备纠结”的前端开发们
查看>>
Nginx配置文件详细说明
查看>>
怎么用Navicat Premium图标编辑器创建表
查看>>
Spring配置文件(2)配置方式
查看>>
MariaDB/Mysql 批量插入 批量更新
查看>>
ItelliJ IDEA开发工具使用—创建一个web项目
查看>>