Normand Briere
2018-07-01 89c1ad67bc65d24ceadfa9e95f8c5515283f1e97
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/*
 * JStackAlloc (c) 2008 Martin Dvorak <jezek2@advel.cz>
 *
 * This software is provided 'as-is', without any express or implied warranty.
 * In no event will the authors be held liable for any damages arising from
 * the use of this software.
 * 
 * Permission is granted to anyone to use this software for any purpose, 
 * including commercial applications, and to alter it and redistribute it
 * freely, subject to the following restrictions:
 * 
 * 1. The origin of this software must not be misrepresented; you must not
 *    claim that you wrote the original software. If you use this software
 *    in a product, an acknowledgment in the product documentation would be
 *    appreciated but is not required.
 * 2. Altered source versions must be plainly marked as such, and must not be
 *    misrepresented as being the original software.
 * 3. This notice may not be removed or altered from any source distribution.
 */
 
package cz.advel.stack.instrument;
 
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.objectweb.asm.*;
import org.objectweb.asm.tree.FieldInsnNode;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.InsnNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.TypeInsnNode;
 
/**
 *
 * @author jezek2
 */
class InstrumentClass extends ClassAdapter {
   
   private Instrumenter instr;
   private Set<String> methods;
   private String className;
   
   private boolean disableMethodInstrumentation = false;
   private MethodNode clinitMethod;
   
   private List<String> tempStaticFields = new ArrayList<String>();
 
   public InstrumentClass(ClassVisitor cv, Instrumenter instr, Set<String> methods) {
       super(cv);
       this.instr = instr;
       this.methods = methods;
   }
 
   @Override
   public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
       super.visit(version, access, name, signature, superName, interfaces);
       className = name;
   }
 
   @Override
   public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
       if (disableMethodInstrumentation) {
           return super.visitMethod(access, name, desc, signature, exceptions);
       }
       
       if (methods.contains(name)) {
           InstrumentMethod im = new InstrumentMethod(access, name, desc, signature, exceptions, instr, this, className, cv);
           if (isInitializerInstrumentationNeeded() && name.equals("<clinit>")) {
               im.emitMethod = false;
               clinitMethod = im;
           }
           return im;
       }
       
       if (isInitializerInstrumentationNeeded() && name.equals("<clinit>")) {
           clinitMethod = new MethodNode(access, name, desc, signature, exceptions);
           return clinitMethod;
       }
       
       return super.visitMethod(access, name, desc, signature, exceptions);
   }
 
   @Override
   public void visitEnd() {
       if (isInitializerInstrumentationNeeded()) {
           if (tempStaticFields.size() > 0 && clinitMethod == null) {
               clinitMethod = new MethodNode(Opcodes.ACC_STATIC, "<clinit>", "()V", null, null);
               clinitMethod.instructions.add(new InsnNode(Opcodes.RETURN));
           }
 
           FieldVisitor fv;
           for (int i=0; i<tempStaticFields.size(); i++) {
               fv = visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL | Opcodes.ACC_STATIC, "$stackTemp"+i, "L"+tempStaticFields.get(i)+";", null, null);
               fv.visitEnd();
           }
 
           if (clinitMethod != null) {
               InsnList list = new InsnList();
               for (int i=0; i<tempStaticFields.size(); i++) {
                   list.add(new TypeInsnNode(Opcodes.NEW, tempStaticFields.get(i)));
                   list.add(new InsnNode(Opcodes.DUP));
                   list.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, tempStaticFields.get(i), "<init>", "()V"));
                   list.add(new FieldInsnNode(Opcodes.PUTSTATIC, className, "$stackTemp"+i, "L"+tempStaticFields.get(i)+";"));
               }
               clinitMethod.instructions.insertBefore(clinitMethod.instructions.getFirst(), list);
 
               disableMethodInstrumentation = true;
               clinitMethod.accept(this);
           }
       }
       
       super.visitEnd();
   }
   
   private boolean isInitializerInstrumentationNeeded() {
       return instr.isSingleThread();
   }
   
   public int registerStaticAlloc(String type) {
       tempStaticFields.add(type);
       return tempStaticFields.size() - 1;
   }
 
}