[讨论] 自由讨论帖/建议帖/资料补充帖/马克帖(谢绝纯水)

RednaxelaFX 2013-02-26
HotSpot VM有若干版本。Oracle JDK/OpenJDK里的HotSpot VM的线程栈是混合模式的,不维护一个单独的Java stack,Java栈帧和native栈帧混合在同一个栈上。这栈又叫做native stack,有叫做C stack的,总之说的是一回事。

引用
看JVM规范(最新的第7版规范)中文版(地址:http://icyfenix.iteye.com/blog/1256329)时看到过这样一句:“译者注:请读者注意避免混淆Stack、Heap和Java (VM)Stack、Java Heap的概念,Java虚拟机的实现本身是由其他语言编写的应用程序,在Java语言程序的角度上看分配在Java Stack中的数据,而在实现虚拟机的程序角度上看则可以是分配在Heap之中。”

这句注解呃…实在是多余嗯。确实有JVM实现是在C heap上分配Java stack的,但不是所有JVM都这样;至少HotSpot不是。

然后,如果你的翻译出来的程序里某个方法不够热,那它会由HotSpot VM的解释器执行,此时你的字节码怎么写就比较重要,但其实反正不热的代码也不怎么影响整体性能所以没啥关系;如果足够热就会被被HotSpot VM的动态编译器所编译,此时无论你把循环计数变量放在operand stack上还是local variable里编译出来的native code(这里指机器码)几乎是一样的,所以怎么写都无所谓。

给你看个例子,HotSpot VM在x86上的解释器实现对一个加法+赋值需要执行的机器码对应的汇编:https://gist.github.com/rednaxelafx/759495
evasnowind 2013-03-05
RednaxelaFX,您好,我想问下,当程序中存在本地方法调用时,执行Java方法methodA() --> 调用本地方法funcB()(假定是C函数) --> 继续执行methodA(), 这一切换过程中,是否存在上下文环境的切换?我是指,是否需要methodA()中的局部变量保存到funcB()的上下文环境中,funcB()执行完毕后将结果“恢复”到methodA()的上下文环境中??如果有这种切换的话,切换的策略是什么(比如说是将methodA()方法中的所有局部变量都保存到funcB()的环境中,还是说只将部分与funcB()有关系的局部变量保存到funcB()的环境中)?哪里有相关的技术资料?

之所以提这个问题,主要原因在于我想实现一种函数式语言(简称为A语言),并希望A语言能支持“热点函数”的编译执行(和JVM类似,只不过我们使用Java开发,“热点函数”会编译成java bytecode执行)。但目前碰到的问题是,由于我们打算采用Trace-based的热点检测策略,解释、编译切换时上下文环境的切换(比如解释执行 --> 编译执行,需要将解释执行的运行时环境的相关变量保存到编译执行的运行时环境中)就变得比较复杂。因为“热点”不是以方法为单位,比如说methodA()中一个运行次数很多的循环遍历(编译后的代码块简称forOpe),那forOpe在编译执行时所需要的上下文信息如何获取?是将methodA()中所有局部变量都保存在forOpe的运行时环境中(感觉空间上比较浪费),还是说扫描forOpe(),只将methodA()与forOpe相关的局部变量保存起来呢?

谢谢您的回复。
RednaxelaFX 2013-03-05
evasnowind 写道
当程序中存在本地方法调用时,执行Java方法methodA() --> 调用本地方法funcB()(假定是C函数) --> 继续执行methodA(), 这一切换过程中,是否存在上下文环境的切换?我是指,是否需要methodA()中的局部变量保存到funcB()的上下文环境中,funcB()执行完毕后将结果“恢复”到methodA()的上下文环境中??

如果你准确理解调用栈(call stack)的作用和使用方式,大概就不会感到这么困惑。每个函数/方法每次被调用时的activation record保存在它对应的stack frame里,每个activation record存着自己的局部变量。当一个函数调用另一个函数的时候,被调用函数的stack frame被创建出来并压到call stack的顶上成为当前stack frame。methodA()在被调用的时候会有自己的栈帧,同样funcB()在被methodA()调用的时候也会有自己的栈帧。

methodA()的局部变量是自己的私有信息,只会在methodA()被调用的时候存在这次调用对应的stack frame里,不会存到“别人”的stack frame里。

methodA()调用funcB()如果要传递参数,那么这些参数是需要保存到funcB()这次调用对应的stack frame里;返回值通常有个特殊的地方放,就JVM的抽象规范而言方法返回值会在被调用方法返回后放到调用方法的操作数栈顶上。

HotSpot VM里,Java方法通过JNI来调用本地方法的调用路径比Java方法调用Java方法涉及更多调用开销,主要涉及的是参数编组(argument marshalling);但通常这不叫做“上下文切换”(context switch),因为上下文切换通常指的是与线程切换、系统调用等相关的一个过程,而通过JNI调用本地方法既不涉及线程切换也不需要做系统调用,所以跟上下文切换没啥关系。

evasnowind 写道
如果有这种切换的话,切换的策略是什么(比如说是将methodA()方法中的所有局部变量都保存到funcB()的环境中,还是说只将部分与funcB()有关系的局部变量保存到funcB()的环境中)?哪里有相关的技术资料?

讲编程语言基础的书通常都会介绍调用栈。例如说这本,读读看?http://book.douban.com/subject/10802357/

不过常见的教科书上教的都是传统的基于函数/方法为编译单元的情况下的调用栈。没啥书特别写了基于trace为编译单元的情况下的调用栈的样子,只有些论文有写。例如这篇Trace-based Compilation for the Java HotSpot Virtual Machine(希望你的学校有买ACM library的帐号)

evasnowind 写道
之所以提这个问题,主要原因在于我想实现一种函数式语言(简称为A语言),并希望A语言能支持“热点函数”的编译执行(和JVM类似,只不过我们使用Java开发,“热点函数”会编译成java bytecode执行)。但目前碰到的问题是,由于我们打算采用Trace-based的热点检测策略,解释、编译切换时上下文环境的切换(比如解释执行 --> 编译执行,需要将解释执行的运行时环境的相关变量保存到编译执行的运行时环境中)就变得比较复杂。因为“热点”不是以方法为单位,比如说methodA()中一个运行次数很多的循环遍历(编译后的代码块简称forOpe),那forOpe在编译执行时所需要的上下文信息如何获取?是将methodA()中所有局部变量都保存在forOpe的运行时环境中(感觉空间上比较浪费),还是说扫描forOpe(),只将methodA()与forOpe相关的局部变量保存起来呢?

哈哈,这很简单。你既然想用Java来实现一种混合模式执行的编程语言,而且只有热点才编译为Java bytecode,意味着你还有一个用Java实现的解释器来解释执行这个A语言的某种中间形式(IR)对吧?这个解释器多半有自己的数据结构来维护A语言层面的调用栈,这跟JVM为实现Java线程所用的调用栈不在一个层次上,所以你也不需要担心它们“打架”。

你把热的trace编译为Java bytecode,而Java bytecode一定要以一个Java class里的Java method为容器,这没问题。你可以把A语言层面上的调用栈的当前栈帧(多半是你自己实现的一个Java对象)的引用传递给这个你编译出来的Java方法,让它直接操作/访问那个栈帧对象里的内容,概念上就是:
void forOpe(StackFrame frame) {
  // fetch local variable from parent frame
  int i = frame.getLocalInt(0 /* index */);

  // ... use i in the compiled trace

  // write back before trace exit
  frame.setLocalInt(0 /* index */), i /* value */);
}

这种做法在跳入“热点编译”版的代码时不需要拷贝任何局部变量,只要传一个引用(指针)。接下来拷贝与否可以在trace内决定,它既可以每次都自己访问parent frame里的版本,也可以先从parent frame里把值读到自己的局部变量里,在离开trace的时候再写回到parent frame。
这个做法的合理性依赖于上面关于“A语言有个用Java实现的解释器”的假设。优化编译过后的代码的局部变量+临时变量只会比原始版本少而不会变多,所以原本的stack frame肯定已经有你所需要的局部变量而且你也知道它的位置在哪里(因为trace的入口是非常确定的,不像一般的方法不知道caller是谁)。

如果假设不成立,实际上你的A语言整体都是编译成Java字节码执行,而热点部分会进一步被编译成更优化的字节码,那就得商榷一下怎么做了。这样的话你最好想点别的办法。

话说你的A语言是函数式语言,是纯函数式语言(完全无副作用)么?如果是的话根本就不用担心局部变量从trace返回method时“回传”的问题,反正局部变量也只能赋值一次,然后值就改不了了。我以前还没怎么留意过实现函数式语言的trace-based compiler,有点意思。刚搜了下发现有基于PyPy实现的Haskell,是trace-based的,回头得仔细看看:http://cdn.bitbucket.org/eventh/courses/downloads/Trace-based%20just-in-time%20compiler%20for%20Haskell%20with%20RPython.pdf

要展开讨论请给出更详细的信息,最好有能运行的代码,或者至少是伪代码。我建议专门开一帖来讨论这个问题而不要躲在这个综合帖里。
RednaxelaFX 2013-03-07
evasnowind 写道
我想实现一种函数式语言(简称为A语言),并希望A语言能支持“热点函数”的编译执行(和JVM类似,只不过我们使用Java开发,“热点函数”会编译成java bytecode执行)。

觉得这篇论文里提到的J2VM的结构值得你参考:http://www.ics.uci.edu/~mbebenit/bebenita-dissertation.pdf
evasnowind 2013-03-07
额,楼主好人啊,您也多注意休息啊(看您前两天回复我的帖子是在晚上12点左右回的……话说周一刚刚去参加我的一位老师的葬礼,他因为工作太劳累39岁就去世了 ),我会看看的,这两天有点别的事情需要处理,打算按照您的意见,过两天整理一下思路在论坛里单独开一个帖子跟大家探讨一下
shigangxing 2013-04-30
evasnowind 写道
额,楼主好人啊,您也多注意休息啊(看您前两天回复我的帖子是在晚上12点左右回的……话说周一刚刚去参加我的一位老师的葬礼,他因为工作太劳累39岁就去世了 ),我会看看的,这两天有点别的事情需要处理,打算按照您的意见,过两天整理一下思路在论坛里单独开一个帖子跟大家探讨一下

请问,你老师是干啥的
evasnowind 2013-05-08
shigangxing 写道
evasnowind 写道
额,楼主好人啊,您也多注意休息啊(看您前两天回复我的帖子是在晚上12点左右回的……话说周一刚刚去参加我的一位老师的葬礼,他因为工作太劳累39岁就去世了 ),我会看看的,这两天有点别的事情需要处理,打算按照您的意见,过两天整理一下思路在论坛里单独开一个帖子跟大家探讨一下

请问,你老师是干啥的


这位老师是教计算机的,平时要搞科研,还有教学任务需要完成……
stevenlye 2013-07-16
java类和对象在JVM中都有哪些数据结构,它们之间是个什么关系呢?请各位大牛能够详细的介绍一下呀。另外classFileParser在加载类时是如何操作这些数据结构的呢?
RednaxelaFX 2013-07-16
stevenlye 写道
java类和对象在JVM中都有哪些数据结构,它们之间是个什么关系呢?请各位大牛能够详细的介绍一下呀。另外classFileParser在加载类时是如何操作这些数据结构的呢?

楼上先看看这几个链接:
http://www.valleytalk.org/2011/07/28/java-%E7%A8%8B%E5%BA%8F%E7%9A%84%E7%BC%96%E8%AF%91%EF%BC%8C%E5%8A%A0%E8%BD%BD-%E5%92%8C-%E6%89%A7%E8%A1%8C/
http://rednaxelafx.iteye.com/blog/1847971
http://rednaxelafx.iteye.com/blog/730461
stevenlye 2013-07-17
RednaxelaFX 写道
stevenlye 写道
java类和对象在JVM中都有哪些数据结构,它们之间是个什么关系呢?请各位大牛能够详细的介绍一下呀。另外classFileParser在加载类时是如何操作这些数据结构的呢?

楼上先看看这几个链接:
http://www.valleytalk.org/2011/07/28/java-%E7%A8%8B%E5%BA%8F%E7%9A%84%E7%BC%96%E8%AF%91%EF%BC%8C%E5%8A%A0%E8%BD%BD-%E5%92%8C-%E6%89%A7%E8%A1%8C/
http://rednaxelafx.iteye.com/blog/1847971
http://rednaxelafx.iteye.com/blog/730461



谢谢回复!看了你上面给的链接,对那个pdf做的ppt里面oop与klass的关系还是不太清楚,这两个结构各自都存的是什么信息,它们都在堆上存储吗?这个pdf中的130页到132页讲类加载的部分怎么没有东西呢?还有个instanceKlassHandle结构,这个是干嘛的,没找到它的具体定义
Global site tag (gtag.js) - Google Analytics