性能文章>难怪我看不懂!call_stub竟然这么玄乎!>

难怪我看不懂!call_stub竟然这么玄乎!原创

1583134

哈喽,我是子牙。十余年技术生涯,一路披荆斩棘从技术小白到技术总监到JVM专家到创业。技术栈如汇编、C语言、C++、Windows内核、Linux内核。特别喜欢研究虚拟机底层实现,对JVM有深入研究。分享的文章偏硬核,很硬的那种。

 

手撸过JVM、内存池、垃圾回收算法、synchronized、线程池、NIO…

 

 

最近正在写三色标记算法 ^_^

01

这次聊这个

 

这篇文章想跟大家聊聊Hotspot源码的call_stub,如图

 

 

这啥?这篇文章目前还不适合你,默默关掉吧,我理解的!

 

为什么要聊这个?我又看不懂!(白眼)给我硬看!

 

这个问题是卷Hotspot的小伙伴问得比较多的,每次回答就像顺藤摸瓜一样,小伙伴们顺着我的回答抛出一堆问题,我怕了,写篇文章把讲透吧,后面谁来问,这篇文章丢过去。看不懂?多看几遍!

 

坦白讲,就这么一段代码,涉及到的知识点还真不少:

  1. 函数指针

  2. 变量定义花招

02

铺垫知识

 

先说宏,比较简单,就两个知识点:

  1. 宏定义,通过#define定义

  2. 宏展开,预处理阶段直接替换

 

打个比方

 

 

这是比较简单的,有的宏定义就像函数一样,还传参,把人搞疯了!万变不离其宗,无脑替换就可以了。


接下来谈谈函数指针,这个一两句话讲不清,我就举个例子了

 

 

总结一下:函数指针的强大就在于它可以用来定义函数,这个函数你给它什么地址,它就把那块内存当成函数执行

 

如果这样说你还是不懂,百度一下吧


好,最后一个铺垫知识:花样定义变量

 

 

OK,万事具备,开始卷。

 

顺便提一嘴,我在做手写JVM小班,就是以手写JVM为契机教大家底层如:汇编、C、C++、操作系统…底层最重要的不是视频,而是老师本人在你遇到问题的时候能指点你。如果你想学习底层,想成为技术大牛,来找我。

03

开始卷

 

点开call_stub,是一个函数,长这样,函数体是一个宏

 

static CallStub call_stub() { return CAST_TO_FN_PTR(CallStub, _call_stub_entry); }

 

找到宏定义

 

#define CAST_TO_FN_PTR(func_type, value) ((func_type)(castable_address(value)))

 

手动展开

 

static CallStub call_stub() { 
// return CAST_TO_FN_PTR(CallStub, _call_stub_entry);
    return (CallStub)(castable_address(_call_stub_entry));
}

 

继续展开

 

inline address_word  castable_address(address x)              { return address_word(x) ; }

typedef uintptr_t address_word;

static CallStub call_stub() {
// return CAST_TO_FN_PTR(CallStub, _call_stub_entry);
    // return (CallStub)(castable_address(_call_stub_entry));
return (CallStub)address_word(_call_stub_entry);
}

 

还有一个碍事的CallStub,继续展开

 

// Calls to Java
typedef void (*CallStub)(
address link,
intptr_t* result,
BasicType result_type,
Method* method,
address entry_point,
intptr_t* parameters,
int size_of_parameters,
TRAPS
);

 

最终结果

 

_call_stub_entry(
    (address)&link,
// (intptr_t*)&(result->_value), // see NOTE above (compiler problem)
result_val_address, // see NOTE above (compiler problem)
result_type,
method(),
entry_point,
args->parameters(),
args->size_of_parameters(),
CHECK
);

 

_call_stub_entry是什么?是JVM调用Java函数的那座桥。指向一段内存,这段内存代码在这生成的

 

 

这个函数,加上另外一个:entry_point,是看懂Hotspot运行时的关键。然,这两座大山将99%的人拒之门外。

 

当然,不包括我,我用内联汇编模拟写了一遍

 

 

OK,就到这里,清晰明了。

 

 

 

你好,我是子牙。十余年技术生涯,一路披荆斩棘从小白到技术总监到大厂中间件到创业。技术栈如汇编、C语言、C++、Windows内核、Linux内核及特别喜欢研究虚拟机底层实现,对JVM有深入研究。分享的文章偏硬核,很硬的那种。不考虑交个朋友吗?关注硬核子牙

 

分类:
标签:
请先登录,再评论

👍👍👍

4月前
回复 张浩:

💪

4月前回复

为你推荐

不起眼,但是足以让你有收获的JVM内存分析案例
分析 这个问题说白了,就是说有些int[]对象不知道是哪里来的,于是我拿他的例子跑了跑,好像还真有这么回事。点该 dump 文件详情,查看相关的 int[] 数组,点该对象的“被引用对象”,发现所
从一起GC血案谈到反射原理
前言 首先回答一下提问者的问题。这主要是由于存在大量反射而产生的临时类加载器和 ASM 临时生成的类,这些类会被保留在 Metaspace,一旦 Metaspace 即将满的时候,就会触发 Fu
关于内存溢出,咱再聊点有意思的?
概述 上篇文章讲了JVM在GC上的一个设计缺陷,揪出一个导致GC慢慢变长的JVM设计缺陷,可能有不少人还是没怎么看明白的,今天准备讲的大家应该都很容易看明白 本文其实很犹豫写不写,因为感觉没有
协助美团kafka团队定位到的一个JVM Crash问题
概述 有挺长一段时间没写技术文章了,正好这两天美团kafka团队有位小伙伴加了我微信,然后咨询了一个JVM crash的问题,大家对crash的问题都比较无奈,因为没有现场,信息量不多,碰到这类问题我
又发现一个导致JVM物理内存消耗大的Bug(已提交Patch)
概述 最近我们公司在帮一个客户查一个JVM的问题(JDK1.8.0_191-b12),发现一个系统老是被OS Kill掉,是内存泄露导致的。在查的过程中,阴差阳错地发现了JVM另外的一个Bug。这个B
JVM实战:优化我的IDEA GC
IDEA是个好东西,可以说是地球上最好的Java开发工具,但是偶尔也会卡顿,仔细想想IDEA也是Java开发的,会不会和GC有关,于是就有了接下来对IDEA的GC进行调优 IDEA默认JVM参数: -
不起眼,但是足以让你收获的JVM内存案例
今天的这个案例我觉得应该会让你涨姿势吧,不管你对JVM有多熟悉,看到这篇文章,应该还是会有点小惊讶的,不过我觉得这个案例我分享出来,是想表达不管多么奇怪的现象请一定要追究下去,会让你慢慢变得强大起来,
如何通过反射获得方法的真实参数名(以及扩展研究)
前段时间,在做一个小的工程时,遇到了需要通过反射获得方法真实参数名的场景,在这里我遇到了一些小小的问题,后来在部门老大的指导下,我解决了这个问题。通过解决这个问题,附带着我了解到了很多新的知识,我觉得