JDK11中增加了一个常量池类型:CONSTANT_Dynamic

有关常量池

有关class file 的内容,这里不再赘述。你可以参阅此文:来自JVM的一封ClassFile介绍信。

大体格式长下面这样:

ClassFile { u4 magic; u2 minor_version; u2 major_version; u2 constant_pool_count; cp_info constant_pool[constant_pool_count-1]; u2 access_flags; u2 this_class; u2 super_class; u2 interfaces_count; u2 interfaces[interfaces_count]; u2 fields_count; field_info fields[fields_count]; u2 methods_count; method_info methods[methods_count]; u2 attributes_count; attribute_info attributes[attributes_count]; }

你可以看到其中一个属性是cp_info。在早前的一些代码中,我们可以发现cp_info是一个数组。这个数组中就是常量池。里边放着各种常量。如下:

cp_info的格式如下:

struct cp_info { u1 tag; u1* info; };

有一个tag,和一个info。其中tag就表示不同的常量类型。info存储了常量的值或者引用。

tag是常量类型。那么在jvm 规范中定了很多的常量类型:

此图是从官方的https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.3.2截取的。

ps:可以看出是截止到jvm规范4.3.2的常量类型。可以发现在java7的时候加入了有关动态语言的常量类型;在java9的时候又加入了有关模块化的两个常量类型。 在java8的时候和在java10的时候并没有更新jvm规范。

上面我们展示了cp_info的基本格式,但具体到每个类型的常量则会转换成具体的常量存储格式,比如如果是

CONSTANT_Integer,则会转成如下格式:

struct CONSTANT_Integer_info { u1 tag; u4 bytes; };

等等,每个具体的tag(常量类型)都会有具体的存储格式。这里就不一一赘述。

有关invokedynamic

我们知道在java7的时候加入了动态语言的支持。上面也说到了,虚拟机规范也添加了支持动态语言的三个常量类型:

这里还是简单的介绍一下invokedynamic吧。

invokedynamic是一个字节码指令,也就是bytecode instruction,通过动态方法的调用来实现动态语言。比如常见的Grovvy。

有关动态语言:动态语言的一个突出特点就是它的类型检查是在运行时才进行,叫做dynamic typing。

这里贴上一段代码你可以简单体验一下java7中新增的有关动态语言的API:

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;

public class MHD
{
   public static void main(String[] args) throws Throwable
   {
      MethodHandles.Lookup lookup = MethodHandles.lookup();
      MethodHandle mh = lookup.findStatic(MHD.class, "hello",
                                          MethodType.methodType(void.class));
      mh.invokeExact();
   }

   static void hello()
   {
      System.out.println("hello");
   }
}

上面的代码中我们通过MethodHandles类获取到Lookup对象,然后通过Lookup查找到MHD类中的静态方法hello(),然后我们设置方法返回类型为void。

查找到这个这个方法以后,返回的是一个MethodHandle对象,此对象封装了hello方法的全部信息,然后我们调用invokeExact方法来执行hello方法,然后打印出hello。

你也发现了,这里我们又看到了MethodHandle和MethodType了。在java7中也对虚拟机规范添加了这两个对应的常量类型。

有关JDK11要新增的CONSTANT_Dynamic

根据JDK11的road map,JDK11将会在2018年9月份就GA了。

其中要发布的新功能中有一项就是要新增一个常量类型:CONSTANT_Dynamic。

为什么要新增这个常量类型?

JEP309 Motivation原文:

Section 4.4 of the Java Virtual Machine Specification describes the format of the constant pool. Adding new constant-pool forms, such as the support for MethodHandle and MethodType introduced in Java 7, is a significant endeavor, and sends ripples through the ecosystem, as it affects all code that parses or interprets class files. This presents a very high bar to creating new constant-pool forms. With invokedynamic, the value of storing complex data in the constant pool is multiplied, since the static argument list for an invokedynamic bootstrap is a sequence of constants. Designers of invokedynamic protocols (such as the LambdaMetafactory added in Java 8) routinely struggle with the need to encode behavior in terms of the existing constant set—which in turn necessitates additional error-prone validation and extraction logic in the bootstrap itself. Richer, more flexible, more highly-typed constants remove friction from the development of invokedynamic protocols, which in turn facilitates the movement of complex logic from run time to linkage time, improving program performance and simplifying compiler logic.

大体上说就是说虚拟机规范在Java7的时候新增了MethodHandle和MethodType两个常量类型。

有了invokedynamic以后,由于invokedynamic bootstrap的静态参数列表是一系列常量,也就是好多个常量。在常量池中存储复杂数据的情况就变得比较普遍。invokedynamic协议的设计者(例如在Java 8中添加的LambdaMetafactory)经常会根据现有的常量集来对行为进行转换,而这又需要在引导(bootstrap)程序中添加一些防止出错的验证。

所以就需要一个更丰富、更高级的常量类型,这样可以解决很多开发invokedynamic协议的麻烦,从而还能改善程序性能和简化编译器逻辑。

为此新增了CONSTANT_Dynamic常量类型。

JVMS也添加了CONSTANT_Dynamic

而且我们注意到了最新的虚拟机规范的草稿已经添加了这一个常量类型。

最新的常量类型表:

新增(修改)的两个常量类型格式如下:

CONSTANT_DynamicCallSite_info { u1 tag; u2 bootstrap_method_attr_index; u2 name_and_type_index; }

CONSTANT_Dynamic_info { u1 tag; u2 bootstrap_method_attr_index; u2 name_and_type_index; }

具体细节你可以翻阅虚拟机规范的最新定义:http://cr.openjdk.java.net/~jrose/jvm/constant-dynamic-jrose.html

本文分享自微信公众号 - ImportSource(importsource)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-04-19

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏别先生

python的学习和使用

20800
来自专栏从零开始学 Web 前端

09 - JavaSE之线程

PS: 如果我们没有 new一个 Thread 对象出来,而是直接使用 MyThread 的 run 方法(mt.run()),这就是方法调用,而不是启动线程了...

15550
来自专栏yl 成长笔记

深刻理解反射(Reflection)

最近公司在搞自动化测试,由于版权问题,无法用 ’录制脚本‘ 进行,也就没法用 VS 自带的 UITest 框架(蛋疼), 所以只能开源的 FlaUI 框架来搞了...

16540
来自专栏java一日一条

50个常见的 Java 错误及避免方法(第一部分)

在开发Java软件时可能会遇到许多类型的错误,但大多数是可以避免的。为此我们罗列了50个最常见的Java编码错误,其中包含代码示例和教程,以帮助大家解决常见的编...

14630
来自专栏IT技术精选文摘

阿里架构师带你深入浅出jvm

28720
来自专栏Spark生态圈

[Spark SQL] 源码解析之Parser

Parser就是将SQL字符串切分成一个个Token,再根据一定语义规则解析为一棵语法树。我们写的sql语句只是一个字符串而已,首先需要将其通过词法解析和语法解...

43420
来自专栏Java大联盟

Java面试手册:核心基础-3

2.数组有没有length()这个方法? String有没有length()这个方法?

21930
来自专栏思考的代码世界

Python基础学习06天

17540
来自专栏菜鸟计划

angularjs promise详解

一、什么是Promise Promise是对象,代表了一个函数最终可能的返回值或抛出的异常,就是用来异步处理值的。 Promise是一个构造函数,自己身上有al...

33550
来自专栏博岩Java大讲堂

Java虚拟机--线程上下文类加载器

38140

扫码关注云+社区

领取腾讯云代金券