`
weigang.gao
  • 浏览: 486224 次
  • 性别: Icon_minigender_1
  • 来自: 上海
文章分类
社区版块
存档分类
最新评论

invokedynamic指令

 
阅读更多

1.http://blogs.oracle.com/jrose/entry/a_modest_tool_for_writing 翻译

a modest tool for writing JSR 292 code

By John.Rose-Oracle on Nov 15, 2010

由John.Rose在2010年11月15日编写了一个用于开发满足JSR 292规范代码的简单工具

 

 

An earlier version of JSR 292 included some syntax support in the Java language for issuing invokedynamic instructions. This is no longer the case in JDK 7. Such support, if it shows up at all, will be dependent on Project Lambda, and that is after JDK 7.

JSR 292规范早期版本包括一些对java语言中invokeDynamic指令语法支持。在JDK7中不再这样,它究竟是否应该支持invokeDynamic指令,完全依赖于Lambda项目,然而

在JDK7中并没有实现对Lambda表达式的支持。

 

(By the way, for a larger example of the syntax support in action, check out this hand-transformed benchmark code for Rhino. This was part of the exploratory work described in my JavaOne talk.)

顺便说一下,对于一个正在进行中的语法支持更大的示例,查看手动转换的基准代码,这是我的JavaOne演讲中描述的探索性工作

 

Well, that’s the bad news. But here’s a bit of good news: I have hacked together a classfile transformer, named “indify”, which is able to pattern-match some byte-compiled Java programs, and transform them into equivalent programs which use JSR 292 bytecode features. It can be used to generate invokedynamic instructions, including those with the new bootstrap method argument format. The transformer can also generate “ldc” instructions for MethodHandle and MethodType constants. (Such constants are a little-known feature of JSR 292.)

好吧!那是一个坏消息。但是这里也有一些好消息:我已经设计了一个类文件转换器,命名为“indify”,“indify”能够模式匹配一些已经编译的java字节码程序,并且

能够将他们转换成等价的满足JSR 292规范二进制特征的程序。它能够被用于生成invokedynamic指令,包含哪些使用新的引导方法参数格式。这个转换器也能够

为MethodHandle和MethodType常量生成“ldc”指令。(MethodHandle和MethodType常量是JSR 292规范中鲜为人知的特性)

 

 

The code for “indify” is in a Mercurial repository on Kenai.com. It is all in a single file of less than 1500 lines. (Update: More recent versions are slightly larger.)

“indify”代码在Kenai.com上的 Mercurial版本库中。这一切都在一个不超过1500行的文件中。

 

Of course, the creation of semantics-preserving program transformations is often difficult. And in this case, the transformation is slightly uphill, more like a decompiler than a compiler. Lower-level expressions are turned into simpler, higher-level JSR 292 operations.

当然,创建一个保持语义性的程序是困难的。在这种情况下,转换有点艰难,,更像一个反编译器的编译器。低层表达式变成更简单、更高级的JSR 292的操作

 

To make the project workable and small, I cut corners. The tool transforms only a limited set of Java programs. In order to make it work for you, you have to prepare stylized, stereotyped Java programs, which make it very clear where you are expecting to perform the transformations.

为了使项目切实可行和小,我偷工减料。这个工具仅仅转换一组有限的java程序。为了使它为你工作,你需要准备按固定格式编写的Java程序,这使得

你期望在什么地方执行转换非常清楚

 

The javadoc in the source code gives some rules for preparing your code. There is also a small example file. The basic trick works like this. Suppose you have a method that you want to create a method handle constant on, like this one:

在源码中java帮助文档为你编写代码提供一些规则。也有一些小的示例文件。

假如你你想在一个方法上面创建一个方法句柄常量,像这样:

 

public static Integer adder(Integer x, Integer y) { return x + y; }

Getting the method handle requires an expression that looks like this: 

获取一个方法句柄需要像这样的表达式:

lookup().findStatic(Example.class, "adder",

  fromMethodDescriptorString("(Ljava/lang/Integer;Ljava/lang/Integer;)Ljava/lang/Integer;", null));

 

Suppose you want to transform that expression into a simple method handle constant. Perhaps in Java with closures you'll be able to write #adder but for now, put the noxious expression into a small private method like this one:

假如你想将这个表达式转换成一个简单的方法句柄常量。或许在java里面使用包庇你将能够写#addr。但是现在,把恶意性表达式放入小的私有方法里面,像这样:

 

private static MethodHandle MH_adder() throws NoAccessException {

  return lookup().findStatic(Example.class, "adder",

    fromMethodDescriptorString("(Ljava/lang/Integer;Ljava/lang/Integer;)Ljava/lang/Integer;", null));

}

 

The name must begin with the string MH_; the rest of the name is arbitrary. Call the function whereever you like (within the same file). Compile the Java code, and run “indify” on the resulting class file. The constant implied by MH_adder will be appended to the class file constant pool, and all such calls to the method will be transformed into ldc instructions.

The pattern for invokedynamic is more complex, and builds on top of simpler method handle and method type constant expressions. Here is an example:

名字必须以字符串MH_为前缀;名字的剩余部分可以随便写。无论你想在(同一个文件中)哪里调用这个功能。编译Java代码,在生成class文件上运行“indify”。

这个常量将被附加到class文件常量池。所有这个方法的调用将被转换成“ldc”指令。

invokedynamic模式更加复杂,建立在简单方法句柄和方法类型常量表达式之上。这里有个例子

 

private static MethodHandle INDY_tester() throws Throwable {

  CallSite cs = (CallSite) MH_mybsm().invokeWithArguments(lookup(), "myindyname",

    fromMethodDescriptorString("(Ljava/lang/Integer;Ljava/lang/Integer;)Ljava/lang/Integer;", null));

  return cs.dynamicInvoker();

}

 

This code assumes that your bootstrap method is provided by a private constant method MH_mybsm. The factored method INDY_tester calls the bootstrap method on the standard arguments (class scope, name, and type), obtains the call site, and returns the site’s invoker method handle. (This is a late-bound alias for the target, which follows the call site target as it changes.) The caller of INDY_tester is required to immediately invoke the result, like this:

这段代码假定你的启动类方法被私有的常量方法MH_mybsm提供。INDY_tester方法使用标准的参数(class scope, name, and type)调用启动方法,获取调用点,并且返回

点的调用者方法句柄。

 

System.out.println((Integer) INDY_tester().invokeExact((Integer)40,(Integer)2));

 

That invokeExact call is part of the built-in semantics of invokedynamic. The “indify” tool tranforms the two calls INDY_tester and invokeExact into a single invokedynamic instruction. The static linkage information for this instruction (which is obtained by inspecting the contents of INDY_tester) is appended to the class file constant pool, as in the previous example.

invokeExact调用是invokedynamic内嵌语义的部分。“indify”工具将2个方法(INDY_tester和invokeExact)调用转换成单一的invokedynamic指令。invokedynamic指令(

这个指令是通过检查INDY_tester的内容获取)的静态链接信息被附加到class文件的常量池,正如先前的示例。

 

Here is a pre-built distribution. For now, you should throw the switch “--transitionalJSR292”, to make it emit the older format (tag 17) of CONSTANT_InvokeDynamic. (The newer format, tag 18, is not widely available yet.) [12/23 Update: Build b123 of OpenJDK 7 supports tag 18, and contains a version of indify.] To find out about the bytecode instructions, you can always look here.

 

 

For large scale use, this tool is a non-starter. For medium sized projects, it is at best a dead end. Real language implementations will need to use a real bytecode backend, like ASM. A small tool like “indify&rdquo is not robust or user-friendly enough for medium to large jobs. And, I’m not planning on supporting it, or developing it much further. Actually, I would be sad to see it get much bigger or more complex.

 

But “indify” may be useful for small inputs, in cases where the result of the transformation is easy to verify. For example, if you are experimenting with small bytecode examples, or writing or teaching about them, this is a way to make your work be readable as Java code, instead of pseudocode or bytecode assembly language.

 

2.INDY工具的使用:如何生成invokedynamic指令

1.项目的目录结构如下:


 
2.编写Example

/*
 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package indify;

import java.lang.invoke.*;
import java.util.*;
import static java.lang.invoke.MethodType.*;
import static java.lang.invoke.MethodHandles.*;

/* example class file to transform with indify */
class Example {
    private static final boolean VERBOSE
        = Boolean.getBoolean("indify.Example.VERBOSE");
    private static final boolean ALLOW_UNTRANSFORMED
        = Boolean.getBoolean("indify.Example.ALLOW_UNTRANSFORMED");
    private static void verbose(Object x) {
        if (!VERBOSE)  return;
        System.out.println(x);
    }
    private static void verboseUntransformed(Object x) {
        // calls to this guy should be transformed away
        if (x == null && ALLOW_UNTRANSFORMED)  return;
        x = "[UNTRANSFORMED] " + (x == null ? "call to indified method": x);
        if (!ALLOW_UNTRANSFORMED)  throw new RuntimeException(x.toString());
        verbose(x);
    }

    public static Integer adder(Integer x, Integer y) { return x + y; }
    public static Object mybsm(Object x, Object y, Object z) throws Throwable {
        verbose("mybsm"+Arrays.asList(x,y,z));
        MethodHandle mh = MH_adder();
        if (!z.equals(mh.type())) {
            verbose("spreading "+mh+" to "+z);
            mh = MH_adder().asSpreader(Object[].class, 2).asType(methodType(Object.class, Object[].class));
        }
        verbose("mh="+mh);
        return new ConstantCallSite(mh);
    }

    // exercise:
    public static void main(String... av) throws Throwable {
        System.out.println("MT = "+MT_gen1());
        System.out.println("MH = "+MH_adder());
        System.out.println("adder(1,2) = "+MH_adder().invokeWithArguments(1, 2));
        System.out.print("calling indy: ");
        if (true)
            System.out.println((Integer) INDY_tester().invokeExact((Integer)40,(Integer)2));
        else
            System.out.println(INDY_tester().invokeExact(new Object[]{40,2}));
    }

    // declarations:
    private static MethodType MT_gen1() {
        verboseUntransformed(null);
        return methodType(Object.class, Object.class);
    }
    private static MethodType MT_gen3() {
        // fromMethodDescriptorString("(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", null);
        verboseUntransformed(null);
        return methodType(Object.class, Object.class, Object.class, Object.class);
    }
    private static MethodHandle MH_adder() throws ReflectiveOperationException {
        verboseUntransformed(null);
        return lookup().findStatic(Example.class, "adder", methodType(Integer.class, Integer.class, Integer.class));
    }
    private static MethodHandle MH_mybsm() throws ReflectiveOperationException {
        verboseUntransformed(null);
        return lookup().findStatic(Example.class, "mybsm", MT_gen3());
    }
    private static MethodHandle INDY_tester;
    private static MethodHandle INDY_tester() throws Throwable {
        if (INDY_tester != null)  return INDY_tester;
        CallSite cs = (CallSite) MH_mybsm().invokeWithArguments(lookup(), "myindyname",
                fromMethodDescriptorString("(Ljava/lang/Integer;Ljava/lang/Integer;)Ljava/lang/Integer;", null));
        verboseUntransformed("BSM produces CS: "+cs);
        return cs.dynamicInvoker();
    }
}
 3.从网站上下载的ExmapleTest需要稍作修改,修改后的内容如下;
package indify;

import org.junit.Test;

/**
 *
 * @author John Rose <john.rose at sun.com>
 */
public class ExampleTest {
    @Test 
    public void testMain() throws Throwable {
        System.out.println("main");
        Indify.main("--verify-specifier-count=1",
        		/*INDY工具将Example.class转换成等效的class文件存放路径*/
        		"--dest=E:/", 
                "--verbose",
                "--expand-properties", "--classpath", "${java.class.path}",
                 /*输入class文件Example.class的全路径,然后使用javap打开该文件*/
                 "E:\\workspaces\\JVMDemo\\bin\\indify\\Example.class");
        //Example.main();
    }

}
 4.使用junit进行单元测试,输出内容如下:


 

  • 大小: 9.1 KB
  • 大小: 27.7 KB
分享到:
评论

相关推荐

    09JVM是怎么实现invokedynamic的?(下)1

    《深入解析Java虚拟机:invokedynamic指令的实现机制》 Java 7引入了一项革命性的新特性,即invokedynamic指令,它极大地提升了Java对动态语言的支持能力。invokedynamic指令的核心在于允许程序在运行时动态决定...

    Java中invokedynamic字节码指令问题

    Java中invokedynamic字节码指令问题是Java中一个相对复杂的字节码指令,invokedynamic指令是Java 7中引入的新特性,主要用于实现方法引用(Method Reference)和动态方法调用。invokedynamic指令可以将方法调用延迟...

    InvokeDynamic

    InvokeDynamic指令允许在运行时动态地绑定方法调用,这极大地支持了脚本语言和其他动态类型语言的实现。在Java虚拟机(JVM)层面,它是一个字节码指令,与`invokestatic`, `invokevirtual`, `invokespecial`等其他...

    08JVM是怎么实现invokedynamic的?(上)1

    Java 中的 invokedynamic 指令 在 Java 7 中,引入了一条新的指令 invokedynamic,该指令的调用机制抽象出调用点这一个概念,并允许应用程序将调用点链接至任意符合条件的方法上。这种机制允许 Java 应用程序使用...

    执行篇:解析JDK 7的动态类型语言支持

    invokedynamic指令的出现改变了这一局面,它允许在运行时动态地解析出方法调用的目标,从而提供了更灵活和高效的调用机制。 INDY(Indirect dynamic method invocation)是invokedynamic在Java社区中的昵称。这个...

    提高Java程序动态性的一个新途径.pdf

    为了突破这种限制,JDK1.7版本开始引入了新的动态调用指令,也就是invokedynamic指令,它原本是为了支持Groovy、JRuby等动态类型语言在Java虚拟机上的运行而设计的。这种动态调用指令通过使用方法句柄(MethodHandle)...

    Java面试题大全.docx

    2. invokedynamic指令:invokedynamic指令是Java 7开始引入的字节码指令,可以实现一些动态类型语言的功能。Java 8的Lambda表达式就是通过invokedynamic指令实现的,使用方法句柄实现。 3. synchronized、volatile...

    jdk1.8_131.rar

    总的来说,JDK 1.8_131为Windows用户提供了一个强大且稳定的Java开发环境,其特性包括Lambda表达式、Stream API、G1垃圾收集器优化、invokedynamic指令、Nashorn JavaScript引擎以及增强的安全性和日期时间API。...

    openjdk8-master.zip

    总而言之,OpenJDK8是Java 8的重要实现,它带来了许多创新特性,如Lambda表达式、Stream API、新日期时间API、Optional类和invokedynamic指令等。对于任何Java开发者来说,熟练掌握OpenJDK8的知识不仅能够提高开发...

    JDK 1.8 Windows x86

    1. invokedynamic指令:JDK 1.8开始支持invokedynamic指令,提升了动态语言的运行效率,尤其是对于使用大量反射和动态类型的语言。 2. 并行GC(G1垃圾收集器):G1是一款新生代和老年代都适用的垃圾收集器,它采用...

    java虚拟机规范(java+se+7)中文版

    invokedynamic指令使得方法调用更加灵活,提高了运行时的性能。 2. **CMS(Concurrent Mark Sweep)垃圾收集器改进**:CMS收集器在Java 7中进行了优化,减少了Stop-The-World暂停时间,提高了用户体验。 3. **堆...

    Java虚拟机规范(中文 翻译版 Java_SE_7).rar

    6. **动态类型与invokedynamic指令**:Java SE 7引入了新的invokedynamic指令,支持更高效的动态语言实现,如Groovy、JRuby等。 7. **并发与多线程**:JVM提供线程创建、同步和通信的API,Java SE 7中的Fork/Join...

    java动态性.rar

    总结起来,Java的动态性包括但不限于动态类型检查、运行时类加载、动态代理、注解处理、泛型、Lambda表达式、对动态语言的支持、invokedynamic指令、反射以及类的重定义。这些特性让Java能够适应各种复杂的编程需求...

    Java 8 Nashorn 脚本引擎

    JSR 223使得在Java平台上支持多种脚本语言成为可能,而JSR 292则引入了invokedynamic指令,提高了动态语言在Java中的性能。 Nashorn的主要特点包括: 1. **高性能**:Nashorn引擎优化了JavaScript的执行速度,使其...

    classfile_constants_java_

    7. **常量方法句柄(Constant Method Handles)**:Java 7 引入的新类型,用于支持invokedynamic指令,可以理解为指向方法的引用。 8. **动态常量(Constant Dynamic)**:同样是在Java 7中引入,与invokedynamic...

    JDK SE8 Java语言规范与虚拟机规范 官方文档

    6. **Lambda实现**:JVM通过字节码层面的优化来实现lambda表达式,如方法句柄和invokedynamic指令。 了解和掌握JDK SE8的Java语言规范和虚拟机规范是提升Java开发技能的关键。官方文档提供了详细的信息,包括各个...

    jdk1.6window64位稳定版本

    6. **动态代理**:JSR 292引入的invokedynamic指令,使得动态语言在Java中运行更加高效,对Java代理提供了更灵活的支持。 尽管JDK1.6已经是一个较老的版本,但它的稳定性和与旧系统及应用的兼容性使其在某些场景下...

    Java虚拟机规范(Java SE 7).7z

    2. 动态类型语言支持:通过 invokedynamic 指令,JVM更好地支持了动态语言,如Groovy和JRuby。 3. 多语言支持:Java SE 7引入了 invokedynamic 指令,使得JVM能更高效地执行多种编程语言。 4. 字符串常量池提升:...

    jvm8虚拟机规范

    同时,还引入了 invokedynamic 指令,支持动态语言的高效运行。 6. 类加载机制: 类加载分为加载、验证、准备、解析和初始化五个阶段。这个过程确保了类的正确性和安全性,同时也允许类的动态加载和替换,提高了...

    Java Magazine NovDec 2017.pdf

    在技术细节方面,文章"Understanding Java Method Invocation with Invokedynamic"讨论了Java 7中引入的invokedynamic指令。这条指令使得Java在运行时可以动态地解决方法调用,为Java虚拟机带来了动态类型语言支持。...

Global site tag (gtag.js) - Google Analytics