1 package serp.bytecode;
2
3 import java.util.*;
4
5 import serp.bytecode.lowlevel.*;
6
7
8
9
10
11
12
13
14
15
16
17 public class ClassConstantInstruction {
18 private static final Class[] _params = new Class[] { String.class };
19 private static final Map _wrappers = new HashMap();
20 static {
21 _wrappers.put(byte.class.getName(), Byte.class);
22 _wrappers.put(boolean.class.getName(), Boolean.class);
23 _wrappers.put(char.class.getName(), Character.class);
24 _wrappers.put(double.class.getName(), Double.class);
25 _wrappers.put(float.class.getName(), Float.class);
26 _wrappers.put(int.class.getName(), Integer.class);
27 _wrappers.put(long.class.getName(), Long.class);
28 _wrappers.put(short.class.getName(), Short.class);
29 }
30
31 private Instruction _ins = null;
32 private Code _code = null;
33 private BCClass _class = null;
34 private boolean _invalid = false;
35
36 ClassConstantInstruction(BCClass bc, Code code, Instruction nop) {
37 _class = bc;
38 _code = code;
39 _ins = nop;
40 }
41
42
43
44
45
46
47
48 public Instruction setClass(String name) {
49 name = _class.getProject().getNameCache().getExternalForm(name, false);
50 setClassName(name, getWrapperClass(name));
51 return _ins;
52 }
53
54
55
56
57
58
59
60 public Instruction setClass(Class type) {
61 return setClass(type.getName());
62 }
63
64
65
66
67
68
69
70 public Instruction setClass(BCClass type) {
71 return setClass(type.getName());
72 }
73
74
75
76
77 private void setClassName(String name, Class wrapper) {
78 if (_invalid)
79 throw new IllegalStateException();
80
81
82 Instruction before = (_code.hasNext()) ? _code.next() : null;
83 _code.before(_ins);
84 _code.next();
85 if (wrapper != null)
86 _code.getstatic().setField(wrapper, "TYPE", Class.class);
87 else
88 setObject(name);
89
90
91 if (before != null)
92 _code.before(before);
93 else
94 _code.afterLast();
95 _invalid = true;
96 }
97
98
99
100
101
102 private void setObject(String name) {
103 BCField field = addClassField(name);
104 BCMethod method = addClassLoadMethod();
105
106
107 _code.getstatic().setField(field);
108 JumpInstruction ifnull = _code.ifnull();
109 _code.getstatic().setField(field);
110 JumpInstruction go2 = _code.go2();
111 ifnull.setTarget(_code.constant().setValue(name));
112 _code.invokestatic().setMethod(method);
113 _code.dup();
114 _code.putstatic().setField(field);
115 go2.setTarget(_code.nop());
116 }
117
118
119
120
121 private BCField addClassField(String name) {
122 String fieldName = "class$L"
123 + name.replace('.', '$').replace('[', '$').replace(';', '$');
124 BCField field = _class.getDeclaredField(fieldName);
125 if (field == null) {
126 field = _class.declareField(fieldName, Class.class);
127 field.makePackage();
128 field.setStatic(true);
129 field.setSynthetic(true);
130 }
131 return field;
132 }
133
134
135
136
137
138 private BCMethod addClassLoadMethod() {
139 BCMethod method = _class.getDeclaredMethod("class$", _params);
140 if (method != null)
141 return method;
142
143
144 method = _class.declareMethod("class$", Class.class, _params);
145 method.setStatic(true);
146 method.makePackage();
147 method.setSynthetic(true);
148
149
150 Code code = method.getCode(true);
151 code.setMaxStack(3);
152 code.setMaxLocals(2);
153
154 Instruction tryStart = code.aload().setLocal(0);
155 code.invokestatic().setMethod(Class.class, "forName", Class.class,
156 _params);
157 Instruction tryEnd = code.areturn();
158 Instruction handlerStart = code.astore().setLocal(1);
159 code.anew().setType(NoClassDefFoundError.class);
160 code.dup();
161 code.aload().setLocal(1);
162 code.invokevirtual().setMethod(Throwable.class, "getMessage",
163 String.class, null);
164 code.invokespecial().setMethod(NoClassDefFoundError.class, "<init>",
165 void.class, _params);
166 code.athrow();
167 code.addExceptionHandler(tryStart, tryEnd, handlerStart,
168 ClassNotFoundException.class);
169 return method;
170 }
171
172
173
174
175
176
177 private static Class getWrapperClass(String name) {
178 if (name == null)
179 return null;
180 return (Class) _wrappers.get(name);
181 }
182 }