forked from sgodbillon/BytecodeParser
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathLocalVariable.java
More file actions
146 lines (135 loc) · 5.43 KB
/
Copy pathLocalVariable.java
File metadata and controls
146 lines (135 loc) · 5.43 KB
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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/*
* Copyright (C) 2011 Stephane Godbillon
*
* This file is part of BytecodeParser. See the README file in the root
* directory of this project.
*
* BytecodeParser is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* BytecodeParser 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 Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public License
* along with BytecodeParser. If not, see <http://www.gnu.org/licenses/>.
*/
package bytecodeparser.analysis;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import org.apache.log4j.Logger;
import javassist.CtBehavior;
import javassist.Modifier;
import javassist.NotFoundException;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.LocalVariableAttribute;
import bytecodeparser.utils.Utils;
/**
* A local variable.
* @author Stephane Godbillon
*
*/
public class LocalVariable {
private static final Logger LOGGER = Logger.getLogger(LocalVariable.class);
/**
* The declaring behavior of this variable.
*/
public final CtBehavior behavior;
/**
* The name of this variable.
*/
public final String name;
/**
* The index of this local variable in the LocalVariableTable attribute.
*/
public final int index;
/**
* The type of this variable.
*/
public final LocalVariableType type;
/**
* Is this local variable a parameter of this behavior?
*/
public final boolean isParameter;
/**
* Gives the range the local variable is valid within.
*/
public int[] getValidityRange() {
int[] result = new int[2];
LocalVariableAttribute localVariableAttribute = Utils.getLocalVariableAttribute(behavior);
result[0] = localVariableAttribute.startPc(index);
result[1] = result[0] + localVariableAttribute.codeLength(index);
return result;
}
/**
* The slot the local variable is put into.
* @return
*/
public int getSlot() {
return Utils.getLocalVariableAttribute(behavior).index(index);
}
public LocalVariable(int index, String name, LocalVariableType type, boolean isParameter, CtBehavior behavior) {
this.index = index;
this.name = name;
this.type = type;
this.behavior = behavior;
this.isParameter = isParameter;
}
@Override
public String toString() {
return name + " (" + type.typeName + ") " + "[" + index + " -> " + getSlot() + "] between [" + getValidityRange()[0] + "," + getValidityRange()[1] + "]";
}
/**
* Gets all the local variables of the given behavior, indexed by their index in the LocalVariableTable attribute.
* @param behavior
* @return the local variables of the given behavior, indexed by their index in the LocalVariableTable attribute.
* @throws NotFoundException
*/
public static Map<Integer, LocalVariable> findVariables(CtBehavior behavior) throws NotFoundException {
int nbParameters = behavior.getParameterTypes().length;
boolean isStatic = Modifier.isStatic(behavior.getModifiers());
Map<Integer, LocalVariable> variables = new HashMap<Integer, LocalVariable>();
CodeAttribute codeAttribute = behavior.getMethodInfo().getCodeAttribute();
LocalVariableAttribute localVariableAttribute = (LocalVariableAttribute) codeAttribute.getAttribute("LocalVariableTable");
LOGGER.debug("search vars : " + localVariableAttribute + " > " + (localVariableAttribute != null ? localVariableAttribute.tableLength() : 0));
if(localVariableAttribute != null) {
for(int i = 0; i < localVariableAttribute.tableLength(); i++) {
boolean isParameter = isStatic ? i < nbParameters : (i > 0 && i <= nbParameters);
LocalVariable localVariable = new LocalVariable(i, localVariableAttribute.variableName(i), LocalVariableType.parse(localVariableAttribute.signature(i)), isParameter, behavior);
variables.put(i, localVariable);
LOGGER.debug(String.format("findLocalVariables: foud var %s is '%s' (slot %s)", i, localVariable.name, localVariable.getSlot()));
}
} else LOGGER.debug("no local vars found");
return variables;
}
/**
* Get the local variable in the given slot at the given index in the given map of local variables.
* @param slot
* @param index
* @param variables
* @return the local variable in the given slot at the given index.
*/
public static LocalVariable getLocalVariable(int slot, int index, Map<Integer, LocalVariable> variables) {
TreeMap<Integer, LocalVariable> variablesByDistance = new TreeMap<Integer, LocalVariable>();
for(LocalVariable lv : variables.values()) {
if(lv.getSlot() == slot) {
int[] validityRange = lv.getValidityRange();
if(validityRange[1] >= index) {
if(validityRange[0] <= index) {
LOGGER.debug("getLocalVariable in slot " + slot + " at index " + index + ": found " + lv);
return lv;
} else
variablesByDistance.put(validityRange[0] - index, lv);
}
}
}
if(variablesByDistance.size() > 0) {
LOGGER.debug("getLocalVariable in slot " + slot + " at index " + index + ": found by shorter distance " + variablesByDistance.firstEntry().getValue());
return variablesByDistance.firstEntry().getValue();
}
LOGGER.debug("getLocalVariable in slot " + slot + " at index " + index + ": NOT FOUND");
return null;
}
}