Path: blob/master/test/hotspot/jtreg/compiler/calls/common/InvokeDynamicPatcher.java
41153 views
/*1* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223package compiler.calls.common;2425import jdk.internal.org.objectweb.asm.ClassReader;26import jdk.internal.org.objectweb.asm.ClassVisitor;27import jdk.internal.org.objectweb.asm.ClassWriter;28import jdk.internal.org.objectweb.asm.Handle;29import jdk.internal.org.objectweb.asm.Label;30import jdk.internal.org.objectweb.asm.MethodVisitor;31import jdk.internal.org.objectweb.asm.Opcodes;3233import java.io.FileInputStream;34import java.io.IOException;35import java.lang.invoke.CallSite;36import java.lang.invoke.MethodHandles;37import java.lang.invoke.MethodType;38import java.net.URISyntaxException;39import java.nio.file.Files;40import java.nio.file.Path;41import java.nio.file.Paths;42import java.nio.file.StandardOpenOption;4344/**45* A class which patch InvokeDynamic class bytecode with invokydynamic46instruction, rewriting "caller" method to call "callee" method using47invokedynamic48*/49public class InvokeDynamicPatcher extends ClassVisitor {5051private static final String CLASS = InvokeDynamic.class.getName()52.replace('.', '/');53private static final String CALLER_METHOD_NAME = "caller";54private static final String CALLEE_METHOD_NAME = "callee";55private static final String NATIVE_CALLEE_METHOD_NAME = "calleeNative";56private static final String BOOTSTRAP_METHOD_NAME = "bootstrapMethod";57private static final String CALL_NATIVE_FIELD = "nativeCallee";58private static final String CALL_NATIVE_FIELD_DESC = "Z";59private static final String CALLEE_METHOD_DESC60= "(L" + CLASS + ";IJFDLjava/lang/String;)Z";61private static final String ASSERTTRUE_METHOD_DESC62= "(ZLjava/lang/String;)V";63private static final String ASSERTS_CLASS = "jdk/test/lib/Asserts";64private static final String ASSERTTRUE_METHOD_NAME = "assertTrue";6566public static void main(String args[]) {67ClassReader cr;68Path filePath;69try {70filePath = Paths.get(InvokeDynamic.class.getProtectionDomain().getCodeSource()71.getLocation().toURI()).resolve(CLASS + ".class");72} catch (URISyntaxException ex) {73throw new Error("TESTBUG: Can't get code source" + ex, ex);74}75try (FileInputStream fis = new FileInputStream(filePath.toFile())) {76cr = new ClassReader(fis);77} catch (IOException e) {78throw new Error("Error reading file", e);79}80ClassWriter cw = new ClassWriter(cr,81ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);82cr.accept(new InvokeDynamicPatcher(Opcodes.ASM5, cw), 0);83try {84Files.write(filePath, cw.toByteArray(),85StandardOpenOption.WRITE);86} catch (IOException e) {87throw new Error(e);88}89}9091public InvokeDynamicPatcher(int api, ClassWriter cw) {92super(api, cw);93}9495@Override96public MethodVisitor visitMethod(final int access, final String name,97final String desc, final String signature,98final String[] exceptions) {99/* a code generate looks like100* 0: aload_0101* 1: ldc #125 // int 1102* 3: ldc2_w #126 // long 2l103* 6: ldc #128 // float 3.0f104* 8: ldc2_w #129 // double 4.0d105* 11: ldc #132 // String 5106* 13: aload_0107* 14: getfield #135 // Field nativeCallee:Z108* 17: ifeq 28109* 20: invokedynamic #181, 0 // InvokeDynamic #1:calleeNative:(Lcompiler/calls/common/InvokeDynamic;IJFDLjava/lang/String;)Z110* 25: goto 33111* 28: invokedynamic #183, 0 // InvokeDynamic #1:callee:(Lcompiler/calls/common/InvokeDynamic;IJFDLjava/lang/String;)Z112* 33: ldc #185 // String Call insuccessfull113* 35: invokestatic #191 // Method jdk/test/lib/Asserts.assertTrue:(ZLjava/lang/String;)V114* 38: return115*116* or, using java-like pseudo-code117* if (this.nativeCallee == false) {118* invokedynamic-call-return-value = invokedynamic-of-callee119* } else {120* invokedynamic-call-return-value = invokedynamic-of-nativeCallee121* }122* Asserts.assertTrue(invokedynamic-call-return-value, error-message);123* return;124*/125if (name.equals(CALLER_METHOD_NAME)) {126MethodVisitor mv = cv.visitMethod(access, name, desc,127signature, exceptions);128Label nonNativeLabel = new Label();129Label checkLabel = new Label();130MethodType mtype = MethodType.methodType(CallSite.class,131MethodHandles.Lookup.class, String.class, MethodType.class);132Handle bootstrap = new Handle(Opcodes.H_INVOKESTATIC, CLASS,133BOOTSTRAP_METHOD_NAME, mtype.toMethodDescriptorString());134mv.visitCode();135// push callee parameters onto stack136mv.visitVarInsn(Opcodes.ALOAD, 0);//push "this"137mv.visitLdcInsn(1);138mv.visitLdcInsn(2L);139mv.visitLdcInsn(3.0f);140mv.visitLdcInsn(4.0d);141mv.visitLdcInsn("5");142// params loaded. let's decide what method to call143mv.visitVarInsn(Opcodes.ALOAD, 0); // push "this"144// get nativeCallee field145mv.visitFieldInsn(Opcodes.GETFIELD, CLASS, CALL_NATIVE_FIELD,146CALL_NATIVE_FIELD_DESC);147// if nativeCallee == false goto nonNativeLabel148mv.visitJumpInsn(Opcodes.IFEQ, nonNativeLabel);149// invokedynamic nativeCalleeMethod using bootstrap method150mv.visitInvokeDynamicInsn(NATIVE_CALLEE_METHOD_NAME,151CALLEE_METHOD_DESC, bootstrap);152// goto checkLabel153mv.visitJumpInsn(Opcodes.GOTO, checkLabel);154// label: nonNativeLabel155mv.visitLabel(nonNativeLabel);156// invokedynamic calleeMethod using bootstrap method157mv.visitInvokeDynamicInsn(CALLEE_METHOD_NAME, CALLEE_METHOD_DESC,158bootstrap);159mv.visitLabel(checkLabel);160mv.visitLdcInsn(CallsBase.CALL_ERR_MSG);161mv.visitMethodInsn(Opcodes.INVOKESTATIC, ASSERTS_CLASS,162ASSERTTRUE_METHOD_NAME, ASSERTTRUE_METHOD_DESC, false);163// label: return164mv.visitInsn(Opcodes.RETURN);165mv.visitMaxs(0, 0);166mv.visitEnd();167return null;168}169return super.visitMethod(access, name, desc, signature, exceptions);170}171}172173174