java接口方法调用源码分析

对于这样的java代码



pubic interface TestInterface {
int foo();
int foo1();
}

pubic interface TestClass implement TestInterface{
public int foo(){
int a = 0;
reurn a;
}

public int foo1(){
int a = 1;
reurn a;
}
}

TestInterface i = new TestClass();

i.foo();



javac之后会生成invoke_interface 的字节码.相关的实现位于templateTable::invokeInterface(int)生成的代码中.


java对象的的内存布局.

首先,变量i指向的内存布局是这样的.

[size=medium][oopDesc][长度与类相关的内存区域][/size]


oopDesc 包含2个成员, markWord和 klass.其中klass在未启用指针压缩时,指向该对象的类信息.
这个"类信息"不是java.lang.Class,而是虚拟机使用的内部数据.


klass指向的内存区域布局,参见(instanceKlass.hpp)

[size=medium][klassOopDesc][instanceKlass][javaVtable][javaItable][静态成员][oop map][/size]


klassOopDesc继承于oopDesc,添加了方法,但是没有新成员变量,所以内存结构一样.instanceKlass包含大量的类信息.其中,这里需要用到的就有 vtable_length, 其值就是javaVtable的长度.


[javaVtable] ==> vtable_length 个 method指针.
对于这里的例子,应该是以这个顺序

(Object类的方法)================
finalize
equals
toString
hashCode
clone
(TestClass类的方法)==
foo
foo1


java Itable内存布局,首先是该类说实现的所有接口类,以及该接口类的方法的偏移位置.最后以0表示接口类信息结束, 然后尾随的就是所有接口类的每个方法

interface0, offset
interface1, offset
.
.
.
interfacen, offset
0 0
========================
interface0_方法0
interface0_方法1
.
.
.
interface1_方法0
interface1_方法1
.
.
.


在上面的额示例代码里.itable就是


指向TestInterface指针, 偏移量[color=red]---[/color]
0, 0 [color=red] |[/color]
指向foo方法的指针[color=red]<--------------[/color]
指向foo1方法的指针



来看看invokeinterface的源码,

首先是和其他方法调用一样.
prepare_invoke()先去缓存找方法, 找不到就解析.连接


重点在这里
lookup_interface_method

movl(scan_temp, Address(recv_klass, instanceKlass::vtable_length_offset() * wordSize));

//scan_temp = (instanceKlass*)(recv_klass+ sizeof(klassOopDesc) )->_vtable_len

lea(scan_temp, Address(recv_klass, scan_temp, times_vte_scale, vtable_base));

//scan_temp = recv_klass + vtable_base + scan_temp * sizeof(vtableEntry); // end of vtable, vtable的后面就是itable了


lea(recv_klass, Address(recv_klass, itable_index, Address::times_ptr, itentry_off));

//recv_klass = recv_klass + itable_index * sizeof(itableMethodEntry) + offset_of(itableMethodEntry, _method) @1


for (int peel = 1; peel >= 0; peel--) {
movptr(method_result, Address(scan_temp, itableOffsetEntry::interface_offset_in_bytes()));
cmpptr(intf_klass, method_result);

if (peel) {
jccb(Assembler::equal, found_method);
} else {
jccb(Assembler::notEqual, search);
// (invert the test to fall through to found_method...)
}

if (!peel) break;

bind(search);

// Check that the previous entry is non-null. A null entry means that
// the receiver class doesn't implement the interface, and wasn't the
// same as when the caller was compiled.
testptr(method_result, method_result);
jcc(Assembler::zero, L_no_such_interface);
addptr(scan_temp, scan_step);


}

bind(found_method);
//上面的代码简直坑爹展开一下


movptr(method_result, Address(scan_temp, itableOffsetEntry::interface_offset_in_bytes()));
//method_result = scan_temp->_interface
cmpptr(intf_klass, method_result);
jccb(Assembler::equal, found_method);

//if(intf_klass == method_result)
// goto found_method;

bind(search);
testptr(method_result, method_result);
jcc(Assembler::zero, L_no_such_interface);
//if(method_result == 0)
// goto L_no_such_interface;

addptr(scan_temp, scan_step);
// scan_temp += sizeof(itableOffsetEntry);
movptr(method_result, Address(scan_temp, itableOffsetEntry::interface_offset_in_bytes()));
//method_result = scan_temp->_interface
cmpptr(intf_klass, method_result);
jccb(Assembler::notEqual, search);
//if(intf_klass != result)
// goto search;


bind(found_method);

// Got a hit.
movl(scan_temp, Address(scan_temp, itableOffsetEntry::offset_offset_in_bytes()));
//scan_temp = ((itableOffsetEntry*)scan_temp)->_offset
movptr(method_result, Address(recv_klass, scan_temp, Address::times_1));
//method_result= recv_klass + scan_temp->_offset @2

//@1+@2 ==>
//method_result = ((itableMethodEntry*)(recv_klass + scan_temp->_offset))[itable_index]._method




for (scan = klass->itable(); scan->interface() != NULL; scan += sizeof(itableOffsetEntry)) {
if (scan->interface() == intf) {
result = (klass + scan->offset() + itable_index);
}
}





最后顺便提一句.vtable里是有接口方法的的.

所以类似
[quote]TestClass t = new TestClass();//或者是TestClass的子类
t.foo();
[/quote]

这种事走vtable的,具体的javap看一下,他生成的是invokeVirtual
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值