1 /*
2  * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package jdk.jfr.internal.instrument;
27 
28 import java.util.ArrayList;
29 import java.util.List;
30 
31 import jdk.internal.org.objectweb.asm.Label;
32 import jdk.internal.org.objectweb.asm.MethodVisitor;
33 import jdk.internal.org.objectweb.asm.Opcodes;
34 import jdk.internal.org.objectweb.asm.commons.LocalVariablesSorter;
35 import jdk.internal.org.objectweb.asm.commons.Remapper;
36 import jdk.internal.org.objectweb.asm.commons.SimpleRemapper;
37 import jdk.internal.org.objectweb.asm.tree.MethodNode;
38 import jdk.jfr.internal.LogLevel;
39 import jdk.jfr.internal.LogTag;
40 import jdk.jfr.internal.Logger;
41 
42 /**
43  * Class responsible for finding the call to inline and inlining it.
44  *
45  * This code is heavily influenced by section 3.2.6 "Inline Method" in
46  * "Using ASM framework to implement common bytecode transformation patterns",
47  * E. Kuleshov, AOSD.07, March 2007, Vancouver, Canada.
48  * http://asm.ow2.org/index.html
49  */
50 @Deprecated
51 final class JIMethodCallInliner extends LocalVariablesSorter {
52 
53     private final String oldClass;
54     private final String newClass;
55     private final MethodNode inlineTarget;
56     private final List<CatchBlock> blocks = new ArrayList<>();
57     private boolean inlining;
58 
59     /**
60      * inlineTarget defines the method to inline and also contains the actual
61      * code to inline.
62      *
63      * @param access
64      * @param desc
65      * @param mv
66      * @param inlineTarget
67      * @param oldClass
68      * @param newClass
69      * @param logger
70      */
JIMethodCallInliner(int access, String desc, MethodVisitor mv, MethodNode inlineTarget, String oldClass, String newClass)71     public JIMethodCallInliner(int access, String desc, MethodVisitor mv,
72             MethodNode inlineTarget, String oldClass, String newClass) {
73         super(Opcodes.ASM7, access, desc, mv);
74         this.oldClass = oldClass;
75         this.newClass = newClass;
76         this.inlineTarget = inlineTarget;
77 
78         if (Logger.shouldLog(LogTag.JFR_SYSTEM_BYTECODE, LogLevel.DEBUG)) {
79             Logger.log(LogTag.JFR_SYSTEM_BYTECODE, LogLevel.DEBUG,
80                 "MethodCallInliner: targetMethod=" + newClass + "."
81                 + inlineTarget.name + inlineTarget.desc);
82         }
83     }
84 
85     @Override
visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf)86     public void visitMethodInsn(int opcode, String owner, String name,
87             String desc, boolean itf) {
88         // Now we are looking at method call in the source method
89         if (!shouldBeInlined(owner, name, desc)) {
90             // If this method call should not be inlined, just keep it
91             mv.visitMethodInsn(opcode, owner, name, desc, itf);
92             return;
93         }
94         // If the call should be inlined, we create a MethodInliningAdapter
95         // The MIA will walk the instructions in the inlineTarget and add them
96         // to the current method, doing the necessary name remappings.
97         Logger.log(LogTag.JFR_SYSTEM_BYTECODE, LogLevel.DEBUG, "Inlining call to " + name + desc);
98         Remapper remapper = new SimpleRemapper(oldClass, newClass);
99         Label end = new Label();
100         inlining = true;
101         inlineTarget.instructions.resetLabels();
102         JIMethodInliningAdapter mia = new JIMethodInliningAdapter(this, end,
103                 opcode == Opcodes.INVOKESTATIC ? Opcodes.ACC_STATIC : 0, desc,
104                 remapper);
105         inlineTarget.accept(mia);
106         inlining = false;
107         super.visitLabel(end);
108     }
109 
110     /**
111      * Determine if the method should be inlined or not.
112      */
shouldBeInlined(String owner, String name, String desc)113     private boolean shouldBeInlined(String owner, String name, String desc) {
114         return inlineTarget.desc.equals(desc) && inlineTarget.name.equals(name)
115                 && owner.equals(newClass.replace('.', '/'));
116     }
117 
118     @Override
visitTryCatchBlock(Label start, Label end, Label handler, String type)119     public void visitTryCatchBlock(Label start, Label end, Label handler,
120             String type) {
121         if (!inlining) {
122             // try-catch blocks are saved here and replayed at the end
123             // of the method (in visitMaxs)
124             blocks.add(new CatchBlock(start, end, handler, type));
125         } else {
126             super.visitTryCatchBlock(start, end, handler, type);
127         }
128     }
129 
130     @Override
visitMaxs(int stack, int locals)131     public void visitMaxs(int stack, int locals) {
132         for (CatchBlock b : blocks) {
133             super.visitTryCatchBlock(b.start, b.end, b.handler, b.type);
134         }
135         super.visitMaxs(stack, locals);
136     }
137 
138     static final class CatchBlock {
139 
140         final Label start;
141         final Label end;
142         final Label handler;
143         final String type;
144 
CatchBlock(Label start, Label end, Label handler, String type)145         CatchBlock(Label start, Label end, Label handler, String type) {
146             this.start = start;
147             this.end = end;
148             this.handler = handler;
149             this.type = type;
150         }
151     }
152 }
153