6
|
1 |
/*
|
|
2 |
* reserved comment block
|
|
3 |
* DO NOT REMOVE OR ALTER!
|
|
4 |
*/
|
|
5 |
package com.sun.org.apache.bcel.internal.generic;
|
|
6 |
|
|
7 |
/* ====================================================================
|
|
8 |
* The Apache Software License, Version 1.1
|
|
9 |
*
|
|
10 |
* Copyright (c) 2001 The Apache Software Foundation. All rights
|
|
11 |
* reserved.
|
|
12 |
*
|
|
13 |
* Redistribution and use in source and binary forms, with or without
|
|
14 |
* modification, are permitted provided that the following conditions
|
|
15 |
* are met:
|
|
16 |
*
|
|
17 |
* 1. Redistributions of source code must retain the above copyright
|
|
18 |
* notice, this list of conditions and the following disclaimer.
|
|
19 |
*
|
|
20 |
* 2. Redistributions in binary form must reproduce the above copyright
|
|
21 |
* notice, this list of conditions and the following disclaimer in
|
|
22 |
* the documentation and/or other materials provided with the
|
|
23 |
* distribution.
|
|
24 |
*
|
|
25 |
* 3. The end-user documentation included with the redistribution,
|
|
26 |
* if any, must include the following acknowledgment:
|
|
27 |
* "This product includes software developed by the
|
|
28 |
* Apache Software Foundation (http://www.apache.org/)."
|
|
29 |
* Alternately, this acknowledgment may appear in the software itself,
|
|
30 |
* if and wherever such third-party acknowledgments normally appear.
|
|
31 |
*
|
|
32 |
* 4. The names "Apache" and "Apache Software Foundation" and
|
|
33 |
* "Apache BCEL" must not be used to endorse or promote products
|
|
34 |
* derived from this software without prior written permission. For
|
|
35 |
* written permission, please contact apache@apache.org.
|
|
36 |
*
|
|
37 |
* 5. Products derived from this software may not be called "Apache",
|
|
38 |
* "Apache BCEL", nor may "Apache" appear in their name, without
|
|
39 |
* prior written permission of the Apache Software Foundation.
|
|
40 |
*
|
|
41 |
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
|
|
42 |
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
43 |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
44 |
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
|
|
45 |
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
46 |
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
47 |
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
|
48 |
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
49 |
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
50 |
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
|
51 |
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
52 |
* SUCH DAMAGE.
|
|
53 |
* ====================================================================
|
|
54 |
*
|
|
55 |
* This software consists of voluntary contributions made by many
|
|
56 |
* individuals on behalf of the Apache Software Foundation. For more
|
|
57 |
* information on the Apache Software Foundation, please see
|
|
58 |
* <http://www.apache.org/>.
|
|
59 |
*/
|
|
60 |
import com.sun.org.apache.bcel.internal.Constants;
|
|
61 |
|
|
62 |
/**
|
|
63 |
* Instances of this class may be used, e.g., to generate typed
|
|
64 |
* versions of instructions. Its main purpose is to be used as the
|
|
65 |
* byte code generating backend of a compiler. You can subclass it to
|
|
66 |
* add your own create methods.
|
|
67 |
*
|
|
68 |
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
|
|
69 |
* @see Constants
|
|
70 |
*/
|
|
71 |
public class InstructionFactory
|
|
72 |
implements InstructionConstants, java.io.Serializable
|
|
73 |
{
|
|
74 |
protected ClassGen cg;
|
|
75 |
protected ConstantPoolGen cp;
|
|
76 |
|
|
77 |
public InstructionFactory(ClassGen cg, ConstantPoolGen cp) {
|
|
78 |
this.cg = cg;
|
|
79 |
this.cp = cp;
|
|
80 |
}
|
|
81 |
|
|
82 |
/** Initialize with ClassGen object
|
|
83 |
*/
|
|
84 |
public InstructionFactory(ClassGen cg) {
|
|
85 |
this(cg, cg.getConstantPool());
|
|
86 |
}
|
|
87 |
|
|
88 |
/** Initialize just with ConstantPoolGen object
|
|
89 |
*/
|
|
90 |
public InstructionFactory(ConstantPoolGen cp) {
|
|
91 |
this(null, cp);
|
|
92 |
}
|
|
93 |
|
|
94 |
/** Create an invoke instruction.
|
|
95 |
*
|
|
96 |
* @param class_name name of the called class
|
|
97 |
* @param name name of the called method
|
|
98 |
* @param ret_type return type of method
|
|
99 |
* @param arg_types argument types of method
|
|
100 |
* @param kind how to invoke, i.e., INVOKEINTERFACE, INVOKESTATIC, INVOKEVIRTUAL,
|
|
101 |
* or INVOKESPECIAL
|
|
102 |
* @see Constants
|
|
103 |
*/
|
|
104 |
public InvokeInstruction createInvoke(String class_name, String name, Type ret_type,
|
|
105 |
Type[] arg_types, short kind) {
|
|
106 |
int index;
|
|
107 |
int nargs = 0;
|
|
108 |
String signature = Type.getMethodSignature(ret_type, arg_types);
|
|
109 |
|
|
110 |
for(int i=0; i < arg_types.length; i++) // Count size of arguments
|
|
111 |
nargs += arg_types[i].getSize();
|
|
112 |
|
|
113 |
if(kind == Constants.INVOKEINTERFACE)
|
|
114 |
index = cp.addInterfaceMethodref(class_name, name, signature);
|
|
115 |
else
|
|
116 |
index = cp.addMethodref(class_name, name, signature);
|
|
117 |
|
|
118 |
switch(kind) {
|
|
119 |
case Constants.INVOKESPECIAL: return new INVOKESPECIAL(index);
|
|
120 |
case Constants.INVOKEVIRTUAL: return new INVOKEVIRTUAL(index);
|
|
121 |
case Constants.INVOKESTATIC: return new INVOKESTATIC(index);
|
|
122 |
case Constants.INVOKEINTERFACE: return new INVOKEINTERFACE(index, nargs + 1);
|
|
123 |
default:
|
|
124 |
throw new RuntimeException("Oops: Unknown invoke kind:" + kind);
|
|
125 |
}
|
|
126 |
}
|
|
127 |
|
|
128 |
/** Create a call to the most popular System.out.println() method.
|
|
129 |
*
|
|
130 |
* @param s the string to print
|
|
131 |
*/
|
|
132 |
public InstructionList createPrintln(String s) {
|
|
133 |
InstructionList il = new InstructionList();
|
|
134 |
int out = cp.addFieldref("java.lang.System", "out",
|
|
135 |
"Ljava/io/PrintStream;");
|
|
136 |
int println = cp.addMethodref("java.io.PrintStream", "println",
|
|
137 |
"(Ljava/lang/String;)V");
|
|
138 |
|
|
139 |
il.append(new GETSTATIC(out));
|
|
140 |
il.append(new PUSH(cp, s));
|
|
141 |
il.append(new INVOKEVIRTUAL(println));
|
|
142 |
|
|
143 |
return il;
|
|
144 |
}
|
|
145 |
|
|
146 |
/** Uses PUSH to push a constant value onto the stack.
|
|
147 |
* @param value must be of type Number, Boolean, Character or String
|
|
148 |
*/
|
|
149 |
public Instruction createConstant(Object value) {
|
|
150 |
PUSH push;
|
|
151 |
|
|
152 |
if(value instanceof Number)
|
|
153 |
push = new PUSH(cp, (Number)value);
|
|
154 |
else if(value instanceof String)
|
|
155 |
push = new PUSH(cp, (String)value);
|
|
156 |
else if(value instanceof Boolean)
|
|
157 |
push = new PUSH(cp, (Boolean)value);
|
|
158 |
else if(value instanceof Character)
|
|
159 |
push = new PUSH(cp, (Character)value);
|
|
160 |
else
|
|
161 |
throw new ClassGenException("Illegal type: " + value.getClass());
|
|
162 |
|
|
163 |
return push.getInstruction();
|
|
164 |
}
|
|
165 |
|
|
166 |
private static class MethodObject {
|
|
167 |
Type[] arg_types;
|
|
168 |
Type result_type;
|
|
169 |
String[] arg_names;
|
|
170 |
String class_name;
|
|
171 |
String name;
|
|
172 |
int access;
|
|
173 |
|
|
174 |
MethodObject(String c, String n, Type r, Type[] a, int acc) {
|
|
175 |
class_name = c;
|
|
176 |
name = n;
|
|
177 |
result_type = r;
|
|
178 |
arg_types = a;
|
|
179 |
access = acc;
|
|
180 |
}
|
|
181 |
}
|
|
182 |
|
|
183 |
private InvokeInstruction createInvoke(MethodObject m, short kind) {
|
|
184 |
return createInvoke(m.class_name, m.name, m.result_type, m.arg_types, kind);
|
|
185 |
}
|
|
186 |
|
|
187 |
private static MethodObject[] append_mos = {
|
|
188 |
new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER,
|
|
189 |
new Type[] { Type.STRING }, Constants.ACC_PUBLIC),
|
|
190 |
new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER,
|
|
191 |
new Type[] { Type.OBJECT }, Constants.ACC_PUBLIC),
|
|
192 |
null, null, // indices 2, 3
|
|
193 |
new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER,
|
|
194 |
new Type[] { Type.BOOLEAN }, Constants.ACC_PUBLIC),
|
|
195 |
new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER,
|
|
196 |
new Type[] { Type.CHAR }, Constants.ACC_PUBLIC),
|
|
197 |
new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER,
|
|
198 |
new Type[] { Type.FLOAT }, Constants.ACC_PUBLIC),
|
|
199 |
new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER,
|
|
200 |
new Type[] { Type.DOUBLE }, Constants.ACC_PUBLIC),
|
|
201 |
new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER,
|
|
202 |
new Type[] { Type.INT }, Constants.ACC_PUBLIC),
|
|
203 |
new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, // No append(byte)
|
|
204 |
new Type[] { Type.INT }, Constants.ACC_PUBLIC),
|
|
205 |
new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, // No append(short)
|
|
206 |
new Type[] { Type.INT }, Constants.ACC_PUBLIC),
|
|
207 |
new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER,
|
|
208 |
new Type[] { Type.LONG }, Constants.ACC_PUBLIC)
|
|
209 |
};
|
|
210 |
|
|
211 |
private static final boolean isString(Type type) {
|
|
212 |
return ((type instanceof ObjectType) &&
|
|
213 |
((ObjectType)type).getClassName().equals("java.lang.String"));
|
|
214 |
}
|
|
215 |
|
|
216 |
public Instruction createAppend(Type type) {
|
|
217 |
byte t = type.getType();
|
|
218 |
|
|
219 |
if(isString(type))
|
|
220 |
return createInvoke(append_mos[0], Constants.INVOKEVIRTUAL);
|
|
221 |
|
|
222 |
switch(t) {
|
|
223 |
case Constants.T_BOOLEAN:
|
|
224 |
case Constants.T_CHAR:
|
|
225 |
case Constants.T_FLOAT:
|
|
226 |
case Constants.T_DOUBLE:
|
|
227 |
case Constants.T_BYTE:
|
|
228 |
case Constants.T_SHORT:
|
|
229 |
case Constants.T_INT:
|
|
230 |
case Constants.T_LONG
|
|
231 |
: return createInvoke(append_mos[t], Constants.INVOKEVIRTUAL);
|
|
232 |
case Constants.T_ARRAY:
|
|
233 |
case Constants.T_OBJECT:
|
|
234 |
return createInvoke(append_mos[1], Constants.INVOKEVIRTUAL);
|
|
235 |
default:
|
|
236 |
throw new RuntimeException("Oops: No append for this type? " + type);
|
|
237 |
}
|
|
238 |
}
|
|
239 |
|
|
240 |
/** Create a field instruction.
|
|
241 |
*
|
|
242 |
* @param class_name name of the accessed class
|
|
243 |
* @param name name of the referenced field
|
|
244 |
* @param type type of field
|
|
245 |
* @param kind how to access, i.e., GETFIELD, PUTFIELD, GETSTATIC, PUTSTATIC
|
|
246 |
* @see Constants
|
|
247 |
*/
|
|
248 |
public FieldInstruction createFieldAccess(String class_name, String name, Type type, short kind) {
|
|
249 |
int index;
|
|
250 |
String signature = type.getSignature();
|
|
251 |
|
|
252 |
index = cp.addFieldref(class_name, name, signature);
|
|
253 |
|
|
254 |
switch(kind) {
|
|
255 |
case Constants.GETFIELD: return new GETFIELD(index);
|
|
256 |
case Constants.PUTFIELD: return new PUTFIELD(index);
|
|
257 |
case Constants.GETSTATIC: return new GETSTATIC(index);
|
|
258 |
case Constants.PUTSTATIC: return new PUTSTATIC(index);
|
|
259 |
|
|
260 |
default:
|
|
261 |
throw new RuntimeException("Oops: Unknown getfield kind:" + kind);
|
|
262 |
}
|
|
263 |
}
|
|
264 |
|
|
265 |
/** Create reference to `this'
|
|
266 |
*/
|
|
267 |
public static Instruction createThis() {
|
|
268 |
return new ALOAD(0);
|
|
269 |
}
|
|
270 |
|
|
271 |
/** Create typed return
|
|
272 |
*/
|
|
273 |
public static ReturnInstruction createReturn(Type type) {
|
|
274 |
switch(type.getType()) {
|
|
275 |
case Constants.T_ARRAY:
|
|
276 |
case Constants.T_OBJECT: return ARETURN;
|
|
277 |
case Constants.T_INT:
|
|
278 |
case Constants.T_SHORT:
|
|
279 |
case Constants.T_BOOLEAN:
|
|
280 |
case Constants.T_CHAR:
|
|
281 |
case Constants.T_BYTE: return IRETURN;
|
|
282 |
case Constants.T_FLOAT: return FRETURN;
|
|
283 |
case Constants.T_DOUBLE: return DRETURN;
|
|
284 |
case Constants.T_LONG: return LRETURN;
|
|
285 |
case Constants.T_VOID: return RETURN;
|
|
286 |
|
|
287 |
default:
|
|
288 |
throw new RuntimeException("Invalid type: " + type);
|
|
289 |
}
|
|
290 |
}
|
|
291 |
|
|
292 |
private static final ArithmeticInstruction createBinaryIntOp(char first, String op) {
|
|
293 |
switch(first) {
|
|
294 |
case '-' : return ISUB;
|
|
295 |
case '+' : return IADD;
|
|
296 |
case '%' : return IREM;
|
|
297 |
case '*' : return IMUL;
|
|
298 |
case '/' : return IDIV;
|
|
299 |
case '&' : return IAND;
|
|
300 |
case '|' : return IOR;
|
|
301 |
case '^' : return IXOR;
|
|
302 |
case '<' : return ISHL;
|
|
303 |
case '>' : return op.equals(">>>")? (ArithmeticInstruction)IUSHR :
|
|
304 |
(ArithmeticInstruction)ISHR;
|
|
305 |
default: throw new RuntimeException("Invalid operand " + op);
|
|
306 |
}
|
|
307 |
}
|
|
308 |
|
|
309 |
private static final ArithmeticInstruction createBinaryLongOp(char first, String op) {
|
|
310 |
switch(first) {
|
|
311 |
case '-' : return LSUB;
|
|
312 |
case '+' : return LADD;
|
|
313 |
case '%' : return LREM;
|
|
314 |
case '*' : return LMUL;
|
|
315 |
case '/' : return LDIV;
|
|
316 |
case '&' : return LAND;
|
|
317 |
case '|' : return LOR;
|
|
318 |
case '^' : return LXOR;
|
|
319 |
case '<' : return LSHL;
|
|
320 |
case '>' : return op.equals(">>>")? (ArithmeticInstruction)LUSHR :
|
|
321 |
(ArithmeticInstruction)LSHR;
|
|
322 |
default: throw new RuntimeException("Invalid operand " + op);
|
|
323 |
}
|
|
324 |
}
|
|
325 |
|
|
326 |
private static final ArithmeticInstruction createBinaryFloatOp(char op) {
|
|
327 |
switch(op) {
|
|
328 |
case '-' : return FSUB;
|
|
329 |
case '+' : return FADD;
|
|
330 |
case '*' : return FMUL;
|
|
331 |
case '/' : return FDIV;
|
|
332 |
default: throw new RuntimeException("Invalid operand " + op);
|
|
333 |
}
|
|
334 |
}
|
|
335 |
|
|
336 |
private static final ArithmeticInstruction createBinaryDoubleOp(char op) {
|
|
337 |
switch(op) {
|
|
338 |
case '-' : return DSUB;
|
|
339 |
case '+' : return DADD;
|
|
340 |
case '*' : return DMUL;
|
|
341 |
case '/' : return DDIV;
|
|
342 |
default: throw new RuntimeException("Invalid operand " + op);
|
|
343 |
}
|
|
344 |
}
|
|
345 |
|
|
346 |
/**
|
|
347 |
* Create binary operation for simple basic types, such as int and float.
|
|
348 |
*
|
|
349 |
* @param op operation, such as "+", "*", "<<", etc.
|
|
350 |
*/
|
|
351 |
public static ArithmeticInstruction createBinaryOperation(String op, Type type) {
|
|
352 |
char first = op.toCharArray()[0];
|
|
353 |
|
|
354 |
switch(type.getType()) {
|
|
355 |
case Constants.T_BYTE:
|
|
356 |
case Constants.T_SHORT:
|
|
357 |
case Constants.T_INT:
|
|
358 |
case Constants.T_CHAR: return createBinaryIntOp(first, op);
|
|
359 |
case Constants.T_LONG: return createBinaryLongOp(first, op);
|
|
360 |
case Constants.T_FLOAT: return createBinaryFloatOp(first);
|
|
361 |
case Constants.T_DOUBLE: return createBinaryDoubleOp(first);
|
|
362 |
default: throw new RuntimeException("Invalid type " + type);
|
|
363 |
}
|
|
364 |
}
|
|
365 |
|
|
366 |
/**
|
|
367 |
* @param size size of operand, either 1 (int, e.g.) or 2 (double)
|
|
368 |
*/
|
|
369 |
public static StackInstruction createPop(int size) {
|
|
370 |
return (size == 2)? (StackInstruction)POP2 :
|
|
371 |
(StackInstruction)POP;
|
|
372 |
}
|
|
373 |
|
|
374 |
/**
|
|
375 |
* @param size size of operand, either 1 (int, e.g.) or 2 (double)
|
|
376 |
*/
|
|
377 |
public static StackInstruction createDup(int size) {
|
|
378 |
return (size == 2)? (StackInstruction)DUP2 :
|
|
379 |
(StackInstruction)DUP;
|
|
380 |
}
|
|
381 |
|
|
382 |
/**
|
|
383 |
* @param size size of operand, either 1 (int, e.g.) or 2 (double)
|
|
384 |
*/
|
|
385 |
public static StackInstruction createDup_2(int size) {
|
|
386 |
return (size == 2)? (StackInstruction)DUP2_X2 :
|
|
387 |
(StackInstruction)DUP_X2;
|
|
388 |
}
|
|
389 |
|
|
390 |
/**
|
|
391 |
* @param size size of operand, either 1 (int, e.g.) or 2 (double)
|
|
392 |
*/
|
|
393 |
public static StackInstruction createDup_1(int size) {
|
|
394 |
return (size == 2)? (StackInstruction)DUP2_X1 :
|
|
395 |
(StackInstruction)DUP_X1;
|
|
396 |
}
|
|
397 |
|
|
398 |
/**
|
|
399 |
* @param index index of local variable
|
|
400 |
*/
|
|
401 |
public static LocalVariableInstruction createStore(Type type, int index) {
|
|
402 |
switch(type.getType()) {
|
|
403 |
case Constants.T_BOOLEAN:
|
|
404 |
case Constants.T_CHAR:
|
|
405 |
case Constants.T_BYTE:
|
|
406 |
case Constants.T_SHORT:
|
|
407 |
case Constants.T_INT: return new ISTORE(index);
|
|
408 |
case Constants.T_FLOAT: return new FSTORE(index);
|
|
409 |
case Constants.T_DOUBLE: return new DSTORE(index);
|
|
410 |
case Constants.T_LONG: return new LSTORE(index);
|
|
411 |
case Constants.T_ARRAY:
|
|
412 |
case Constants.T_OBJECT: return new ASTORE(index);
|
|
413 |
default: throw new RuntimeException("Invalid type " + type);
|
|
414 |
}
|
|
415 |
}
|
|
416 |
|
|
417 |
/**
|
|
418 |
* @param index index of local variable
|
|
419 |
*/
|
|
420 |
public static LocalVariableInstruction createLoad(Type type, int index) {
|
|
421 |
switch(type.getType()) {
|
|
422 |
case Constants.T_BOOLEAN:
|
|
423 |
case Constants.T_CHAR:
|
|
424 |
case Constants.T_BYTE:
|
|
425 |
case Constants.T_SHORT:
|
|
426 |
case Constants.T_INT: return new ILOAD(index);
|
|
427 |
case Constants.T_FLOAT: return new FLOAD(index);
|
|
428 |
case Constants.T_DOUBLE: return new DLOAD(index);
|
|
429 |
case Constants.T_LONG: return new LLOAD(index);
|
|
430 |
case Constants.T_ARRAY:
|
|
431 |
case Constants.T_OBJECT: return new ALOAD(index);
|
|
432 |
default: throw new RuntimeException("Invalid type " + type);
|
|
433 |
}
|
|
434 |
}
|
|
435 |
|
|
436 |
/**
|
|
437 |
* @param type type of elements of array, i.e., array.getElementType()
|
|
438 |
*/
|
|
439 |
public static ArrayInstruction createArrayLoad(Type type) {
|
|
440 |
switch(type.getType()) {
|
|
441 |
case Constants.T_BOOLEAN:
|
|
442 |
case Constants.T_BYTE: return BALOAD;
|
|
443 |
case Constants.T_CHAR: return CALOAD;
|
|
444 |
case Constants.T_SHORT: return SALOAD;
|
|
445 |
case Constants.T_INT: return IALOAD;
|
|
446 |
case Constants.T_FLOAT: return FALOAD;
|
|
447 |
case Constants.T_DOUBLE: return DALOAD;
|
|
448 |
case Constants.T_LONG: return LALOAD;
|
|
449 |
case Constants.T_ARRAY:
|
|
450 |
case Constants.T_OBJECT: return AALOAD;
|
|
451 |
default: throw new RuntimeException("Invalid type " + type);
|
|
452 |
}
|
|
453 |
}
|
|
454 |
|
|
455 |
/**
|
|
456 |
* @param type type of elements of array, i.e., array.getElementType()
|
|
457 |
*/
|
|
458 |
public static ArrayInstruction createArrayStore(Type type) {
|
|
459 |
switch(type.getType()) {
|
|
460 |
case Constants.T_BOOLEAN:
|
|
461 |
case Constants.T_BYTE: return BASTORE;
|
|
462 |
case Constants.T_CHAR: return CASTORE;
|
|
463 |
case Constants.T_SHORT: return SASTORE;
|
|
464 |
case Constants.T_INT: return IASTORE;
|
|
465 |
case Constants.T_FLOAT: return FASTORE;
|
|
466 |
case Constants.T_DOUBLE: return DASTORE;
|
|
467 |
case Constants.T_LONG: return LASTORE;
|
|
468 |
case Constants.T_ARRAY:
|
|
469 |
case Constants.T_OBJECT: return AASTORE;
|
|
470 |
default: throw new RuntimeException("Invalid type " + type);
|
|
471 |
}
|
|
472 |
}
|
|
473 |
|
|
474 |
|
|
475 |
/** Create conversion operation for two stack operands, this may be an I2C, instruction, e.g.,
|
|
476 |
* if the operands are basic types and CHECKCAST if they are reference types.
|
|
477 |
*/
|
|
478 |
public Instruction createCast(Type src_type, Type dest_type) {
|
|
479 |
if((src_type instanceof BasicType) && (dest_type instanceof BasicType)) {
|
|
480 |
byte dest = dest_type.getType();
|
|
481 |
byte src = src_type.getType();
|
|
482 |
|
|
483 |
if(dest == Constants.T_LONG && (src == Constants.T_CHAR || src == Constants.T_BYTE ||
|
|
484 |
src == Constants.T_SHORT))
|
|
485 |
src = Constants.T_INT;
|
|
486 |
|
|
487 |
String[] short_names = { "C", "F", "D", "B", "S", "I", "L" };
|
|
488 |
|
|
489 |
String name = "com.sun.org.apache.bcel.internal.generic." + short_names[src - Constants.T_CHAR] +
|
|
490 |
"2" + short_names[dest - Constants.T_CHAR];
|
|
491 |
|
|
492 |
Instruction i = null;
|
|
493 |
try {
|
|
494 |
i = (Instruction)java.lang.Class.forName(name).newInstance();
|
|
495 |
} catch(Exception e) {
|
|
496 |
throw new RuntimeException("Could not find instruction: " + name);
|
|
497 |
}
|
|
498 |
|
|
499 |
return i;
|
|
500 |
} else if((src_type instanceof ReferenceType) && (dest_type instanceof ReferenceType)) {
|
|
501 |
if(dest_type instanceof ArrayType)
|
|
502 |
return new CHECKCAST(cp.addArrayClass((ArrayType)dest_type));
|
|
503 |
else
|
|
504 |
return new CHECKCAST(cp.addClass(((ObjectType)dest_type).getClassName()));
|
|
505 |
}
|
|
506 |
else
|
|
507 |
throw new RuntimeException("Can not cast " + src_type + " to " + dest_type);
|
|
508 |
}
|
|
509 |
|
|
510 |
public GETFIELD createGetField(String class_name, String name, Type t) {
|
|
511 |
return new GETFIELD(cp.addFieldref(class_name, name, t.getSignature()));
|
|
512 |
}
|
|
513 |
|
|
514 |
public GETSTATIC createGetStatic(String class_name, String name, Type t) {
|
|
515 |
return new GETSTATIC(cp.addFieldref(class_name, name, t.getSignature()));
|
|
516 |
}
|
|
517 |
|
|
518 |
public PUTFIELD createPutField(String class_name, String name, Type t) {
|
|
519 |
return new PUTFIELD(cp.addFieldref(class_name, name, t.getSignature()));
|
|
520 |
}
|
|
521 |
|
|
522 |
public PUTSTATIC createPutStatic(String class_name, String name, Type t) {
|
|
523 |
return new PUTSTATIC(cp.addFieldref(class_name, name, t.getSignature()));
|
|
524 |
}
|
|
525 |
|
|
526 |
public CHECKCAST createCheckCast(ReferenceType t) {
|
|
527 |
if(t instanceof ArrayType)
|
|
528 |
return new CHECKCAST(cp.addArrayClass((ArrayType)t));
|
|
529 |
else
|
|
530 |
return new CHECKCAST(cp.addClass((ObjectType)t));
|
|
531 |
}
|
|
532 |
|
|
533 |
public INSTANCEOF createInstanceOf(ReferenceType t) {
|
|
534 |
if(t instanceof ArrayType)
|
|
535 |
return new INSTANCEOF(cp.addArrayClass((ArrayType)t));
|
|
536 |
else
|
|
537 |
return new INSTANCEOF(cp.addClass((ObjectType)t));
|
|
538 |
}
|
|
539 |
|
|
540 |
public NEW createNew(ObjectType t) {
|
|
541 |
return new NEW(cp.addClass(t));
|
|
542 |
}
|
|
543 |
|
|
544 |
public NEW createNew(String s) {
|
|
545 |
return createNew(new ObjectType(s));
|
|
546 |
}
|
|
547 |
|
|
548 |
/** Create new array of given size and type.
|
|
549 |
* @return an instruction that creates the corresponding array at runtime, i.e. is an AllocationInstruction
|
|
550 |
*/
|
|
551 |
public Instruction createNewArray(Type t, short dim) {
|
|
552 |
if(dim == 1) {
|
|
553 |
if(t instanceof ObjectType)
|
|
554 |
return new ANEWARRAY(cp.addClass((ObjectType)t));
|
|
555 |
else if(t instanceof ArrayType)
|
|
556 |
return new ANEWARRAY(cp.addArrayClass((ArrayType)t));
|
|
557 |
else
|
|
558 |
return new NEWARRAY(((BasicType)t).getType());
|
|
559 |
} else {
|
|
560 |
ArrayType at;
|
|
561 |
|
|
562 |
if(t instanceof ArrayType)
|
|
563 |
at = (ArrayType)t;
|
|
564 |
else
|
|
565 |
at = new ArrayType(t, dim);
|
|
566 |
|
|
567 |
return new MULTIANEWARRAY(cp.addArrayClass(at), dim);
|
|
568 |
}
|
|
569 |
}
|
|
570 |
|
|
571 |
/** Create "null" value for reference types, 0 for basic types like int
|
|
572 |
*/
|
|
573 |
public static Instruction createNull(Type type) {
|
|
574 |
switch(type.getType()) {
|
|
575 |
case Constants.T_ARRAY:
|
|
576 |
case Constants.T_OBJECT: return ACONST_NULL;
|
|
577 |
case Constants.T_INT:
|
|
578 |
case Constants.T_SHORT:
|
|
579 |
case Constants.T_BOOLEAN:
|
|
580 |
case Constants.T_CHAR:
|
|
581 |
case Constants.T_BYTE: return ICONST_0;
|
|
582 |
case Constants.T_FLOAT: return FCONST_0;
|
|
583 |
case Constants.T_DOUBLE: return DCONST_0;
|
|
584 |
case Constants.T_LONG: return LCONST_0;
|
|
585 |
case Constants.T_VOID: return NOP;
|
|
586 |
|
|
587 |
default:
|
|
588 |
throw new RuntimeException("Invalid type: " + type);
|
|
589 |
}
|
|
590 |
}
|
|
591 |
|
|
592 |
/** Create branch instruction by given opcode, except LOOKUPSWITCH and TABLESWITCH.
|
|
593 |
* For those you should use the SWITCH compound instruction.
|
|
594 |
*/
|
|
595 |
public static BranchInstruction createBranchInstruction(short opcode, InstructionHandle target) {
|
|
596 |
switch(opcode) {
|
|
597 |
case Constants.IFEQ: return new IFEQ(target);
|
|
598 |
case Constants.IFNE: return new IFNE(target);
|
|
599 |
case Constants.IFLT: return new IFLT(target);
|
|
600 |
case Constants.IFGE: return new IFGE(target);
|
|
601 |
case Constants.IFGT: return new IFGT(target);
|
|
602 |
case Constants.IFLE: return new IFLE(target);
|
|
603 |
case Constants.IF_ICMPEQ: return new IF_ICMPEQ(target);
|
|
604 |
case Constants.IF_ICMPNE: return new IF_ICMPNE(target);
|
|
605 |
case Constants.IF_ICMPLT: return new IF_ICMPLT(target);
|
|
606 |
case Constants.IF_ICMPGE: return new IF_ICMPGE(target);
|
|
607 |
case Constants.IF_ICMPGT: return new IF_ICMPGT(target);
|
|
608 |
case Constants.IF_ICMPLE: return new IF_ICMPLE(target);
|
|
609 |
case Constants.IF_ACMPEQ: return new IF_ACMPEQ(target);
|
|
610 |
case Constants.IF_ACMPNE: return new IF_ACMPNE(target);
|
|
611 |
case Constants.GOTO: return new GOTO(target);
|
|
612 |
case Constants.JSR: return new JSR(target);
|
|
613 |
case Constants.IFNULL: return new IFNULL(target);
|
|
614 |
case Constants.IFNONNULL: return new IFNONNULL(target);
|
|
615 |
case Constants.GOTO_W: return new GOTO_W(target);
|
|
616 |
case Constants.JSR_W: return new JSR_W(target);
|
|
617 |
default:
|
|
618 |
throw new RuntimeException("Invalid opcode: " + opcode);
|
|
619 |
}
|
|
620 |
}
|
|
621 |
|
|
622 |
public void setClassGen(ClassGen c) { cg = c; }
|
|
623 |
public ClassGen getClassGen() { return cg; }
|
|
624 |
public void setConstantPool(ConstantPoolGen c) { cp = c; }
|
|
625 |
public ConstantPoolGen getConstantPool() { return cp; }
|
|
626 |
}
|