50 * handlers, adding thrown exceptions, local variables and attributes, whereas |
50 * handlers, adding thrown exceptions, local variables and attributes, whereas |
51 * the `LocalVariableTable' and `LineNumberTable' attributes will be set |
51 * the `LocalVariableTable' and `LineNumberTable' attributes will be set |
52 * automatically for the code. Use stripAttributes() if you don't like this. |
52 * automatically for the code. Use stripAttributes() if you don't like this. |
53 * |
53 * |
54 * While generating code it may be necessary to insert NOP operations. You can |
54 * While generating code it may be necessary to insert NOP operations. You can |
55 * use the `removeNOPs' method to get rid off them. The resulting method object |
55 * use the `removeNOPs' method to get rid off them. |
56 * can be obtained via the `getMethod()' method. |
56 * The resulting method object can be obtained via the `getMethod()' method. |
57 * |
57 * |
58 * @version $Id: MethodGen.java 1749603 2016-06-21 20:50:19Z ggregory $ |
58 * @version $Id$ |
59 * @see InstructionList |
59 * @see InstructionList |
60 * @see Method |
60 * @see Method |
61 * @LastModified: Oct 2017 |
61 * @LastModified: Jun 2019 |
62 */ |
62 */ |
63 public class MethodGen extends FieldGenOrMethodGen { |
63 public class MethodGen extends FieldGenOrMethodGen { |
64 |
64 |
65 private String class_name; |
65 private String class_name; |
66 private Type[] arg_types; |
66 private Type[] arg_types; |
67 private String[] arg_names; |
67 private String[] arg_names; |
68 private int max_locals; |
68 private int max_locals; |
69 private int max_stack; |
69 private int max_stack; |
70 private InstructionList il; |
70 private InstructionList il; |
71 private boolean strip_attributes; |
71 private boolean strip_attributes; |
|
72 private LocalVariableTypeTable local_variable_type_table = null; |
72 private final List<LocalVariableGen> variable_vec = new ArrayList<>(); |
73 private final List<LocalVariableGen> variable_vec = new ArrayList<>(); |
73 private final List<LocalVariableGen> type_vec = new ArrayList<>(); |
|
74 private final List<LineNumberGen> line_number_vec = new ArrayList<>(); |
74 private final List<LineNumberGen> line_number_vec = new ArrayList<>(); |
75 private final List<CodeExceptionGen> exception_vec = new ArrayList<>(); |
75 private final List<CodeExceptionGen> exception_vec = new ArrayList<>(); |
76 private final List<String> throws_vec = new ArrayList<>(); |
76 private final List<String> throws_vec = new ArrayList<>(); |
77 private final List<Attribute> code_attrs_vec = new ArrayList<>(); |
77 private final List<Attribute> code_attrs_vec = new ArrayList<>(); |
78 |
78 |
81 private boolean haveUnpackedParameterAnnotations = false; |
81 private boolean haveUnpackedParameterAnnotations = false; |
82 |
82 |
83 private static BCELComparator bcelComparator = new BCELComparator() { |
83 private static BCELComparator bcelComparator = new BCELComparator() { |
84 |
84 |
85 @Override |
85 @Override |
86 public boolean equals(final Object o1, final Object o2) { |
86 public boolean equals( final Object o1, final Object o2 ) { |
87 final MethodGen THIS = (MethodGen) o1; |
87 final MethodGen THIS = (MethodGen) o1; |
88 final MethodGen THAT = (MethodGen) o2; |
88 final MethodGen THAT = (MethodGen) o2; |
89 return THIS.getName().equals(THAT.getName()) |
89 return THIS.getName().equals(THAT.getName()) |
90 && THIS.getSignature().equals(THAT.getSignature()); |
90 && THIS.getSignature().equals(THAT.getSignature()); |
91 } |
91 } |
92 |
92 |
|
93 |
93 @Override |
94 @Override |
94 public int hashCode(final Object o) { |
95 public int hashCode( final Object o ) { |
95 final MethodGen THIS = (MethodGen) o; |
96 final MethodGen THIS = (MethodGen) o; |
96 return THIS.getSignature().hashCode() ^ THIS.getName().hashCode(); |
97 return THIS.getSignature().hashCode() ^ THIS.getName().hashCode(); |
97 } |
98 } |
98 }; |
99 }; |
99 |
100 |
100 /** |
101 |
101 * Declare method. If the method is non-static the constructor automatically |
102 /** |
102 * declares a local variable `$this' in slot 0. The actual code is contained |
103 * Declare method. If the method is non-static the constructor |
103 * in the `il' parameter, which may further manipulated by the user. But he |
104 * automatically declares a local variable `$this' in slot 0. The |
104 * must take care not to remove any instruction (handles) that are still |
105 * actual code is contained in the `il' parameter, which may further |
105 * referenced from this object. |
106 * manipulated by the user. But he must take care not to remove any |
|
107 * instruction (handles) that are still referenced from this object. |
106 * |
108 * |
107 * For example one may not add a local variable and later remove the |
109 * For example one may not add a local variable and later remove the |
108 * instructions it refers to without causing havoc. It is safe however if |
110 * instructions it refers to without causing havoc. It is safe |
109 * you remove that local variable, too. |
111 * however if you remove that local variable, too. |
110 * |
112 * |
111 * @param access_flags access qualifiers |
113 * @param access_flags access qualifiers |
112 * @param return_type method type |
114 * @param return_type method type |
113 * @param arg_types argument types |
115 * @param arg_types argument types |
114 * @param arg_names argument names (if this is null, default names will be |
116 * @param arg_names argument names (if this is null, default names will be provided |
115 * provided for them) |
117 * for them) |
116 * @param method_name name of method |
118 * @param method_name name of method |
117 * @param class_name class name containing this method (may be null, if you |
119 * @param class_name class name containing this method (may be null, if you don't care) |
118 * don't care) |
120 * @param il instruction list associated with this method, may be null only for |
119 * @param il instruction list associated with this method, may be null only |
121 * abstract or native methods |
120 * for abstract or native methods |
|
121 * @param cp constant pool |
122 * @param cp constant pool |
122 */ |
123 */ |
123 public MethodGen(final int access_flags, final Type return_type, final Type[] arg_types, String[] arg_names, |
124 public MethodGen(final int access_flags, final Type return_type, final Type[] arg_types, String[] arg_names, |
124 final String method_name, final String class_name, final InstructionList il, final ConstantPoolGen cp) { |
125 final String method_name, final String class_name, final InstructionList il, final ConstantPoolGen cp) { |
125 super(access_flags); |
126 super(access_flags); |
250 addAttribute(a); |
249 addAttribute(a); |
251 } |
250 } |
252 } |
251 } |
253 } |
252 } |
254 |
253 |
255 private void repairHandles(final LocalVariable[] lv, boolean isLVT) { |
|
256 for (int k = 0; k < lv.length; k++) { |
|
257 LocalVariable l = lv[k]; |
|
258 InstructionHandle start = il.findHandle(l.getStartPC()); |
|
259 InstructionHandle end = il.findHandle(l.getStartPC() + l.getLength()); |
|
260 // Repair malformed handles |
|
261 if (null == start) { |
|
262 start = il.getStart(); |
|
263 } |
|
264 if (null == end) { |
|
265 end = il.getEnd(); |
|
266 } |
|
267 if (isLVT) { |
|
268 addLocalVariableType(l.getName(), Type.getType(l.getSignature()), |
|
269 l.getIndex(), start, end); |
|
270 } else { |
|
271 addLocalVariable(l.getName(), Type.getType(l.getSignature()), |
|
272 l.getIndex(), start, end); |
|
273 } |
|
274 } |
|
275 } |
|
276 |
|
277 /** |
254 /** |
278 * Adds a local variable to this method. |
255 * Adds a local variable to this method. |
279 * |
256 * |
280 * @param name variable name |
257 * @param name variable name |
281 * @param type variable type |
258 * @param type variable type |
282 * @param slot the index of the local variable, if type is long or double, |
259 * @param slot the index of the local variable, if type is long or double, the next available |
283 * the next available index is slot+2 |
260 * index is slot+2 |
284 * @param start from where the variable is valid |
261 * @param start from where the variable is valid |
285 * @param end until where the variable is valid |
262 * @param end until where the variable is valid |
|
263 * @param orig_index the index of the local variable prior to any modifications |
286 * @return new local variable object |
264 * @return new local variable object |
287 * @see LocalVariable |
265 * @see LocalVariable |
288 */ |
266 */ |
289 public LocalVariableGen addLocalVariable(final String name, final Type type, final int slot, |
267 public LocalVariableGen addLocalVariable( final String name, final Type type, final int slot, |
290 final InstructionHandle start, final InstructionHandle end) { |
268 final InstructionHandle start, final InstructionHandle end, final int orig_index ) { |
291 |
|
292 final byte t = type.getType(); |
269 final byte t = type.getType(); |
293 if (t != Const.T_ADDRESS) { |
270 if (t != Const.T_ADDRESS) { |
294 final int add = type.getSize(); |
271 final int add = type.getSize(); |
295 if (slot + add > max_locals) { |
272 if (slot + add > max_locals) { |
296 max_locals = slot + add; |
273 max_locals = slot + add; |
297 } |
274 } |
298 final LocalVariableGen l = new LocalVariableGen(slot, name, type, start, end); |
275 final LocalVariableGen l = new LocalVariableGen(slot, name, type, start, end, orig_index); |
299 int i; |
276 int i; |
300 if ((i = variable_vec.indexOf(l)) >= 0) { |
277 if ((i = variable_vec.indexOf(l)) >= 0) { |
301 variable_vec.set(i, l); |
278 variable_vec.set(i, l); |
302 } else { |
279 } else { |
303 variable_vec.add(l); |
280 variable_vec.add(l); |
306 } |
283 } |
307 throw new IllegalArgumentException("Can not use " + type |
284 throw new IllegalArgumentException("Can not use " + type |
308 + " as type for local variable"); |
285 + " as type for local variable"); |
309 } |
286 } |
310 |
287 |
311 /** |
288 |
312 * Adds a local variable to this method and assigns an index automatically. |
289 /** |
|
290 * Adds a local variable to this method. |
313 * |
291 * |
314 * @param name variable name |
292 * @param name variable name |
315 * @param type variable type |
293 * @param type variable type |
316 * @param start from where the variable is valid, if this is null, it is |
294 * @param slot the index of the local variable, if type is long or double, the next available |
317 * valid from the start |
295 * index is slot+2 |
318 * @param end until where the variable is valid, if this is null, it is |
296 * @param start from where the variable is valid |
319 * valid to the end |
297 * @param end until where the variable is valid |
320 * @return new local variable object |
298 * @return new local variable object |
321 * @see LocalVariable |
299 * @see LocalVariable |
322 */ |
300 */ |
323 public LocalVariableGen addLocalVariable(final String name, final Type type, |
301 public LocalVariableGen addLocalVariable( final String name, final Type type, final int slot, |
324 final InstructionHandle start, final InstructionHandle end) { |
302 final InstructionHandle start, final InstructionHandle end ) { |
|
303 return addLocalVariable(name, type, slot, start, end, slot); |
|
304 } |
|
305 |
|
306 /** |
|
307 * Adds a local variable to this method and assigns an index automatically. |
|
308 * |
|
309 * @param name variable name |
|
310 * @param type variable type |
|
311 * @param start from where the variable is valid, if this is null, |
|
312 * it is valid from the start |
|
313 * @param end until where the variable is valid, if this is null, |
|
314 * it is valid to the end |
|
315 * @return new local variable object |
|
316 * @see LocalVariable |
|
317 */ |
|
318 public LocalVariableGen addLocalVariable( final String name, final Type type, final InstructionHandle start, |
|
319 final InstructionHandle end ) { |
325 return addLocalVariable(name, type, max_locals, start, end); |
320 return addLocalVariable(name, type, max_locals, start, end); |
326 } |
321 } |
|
322 |
327 |
323 |
328 /** |
324 /** |
329 * Remove a local variable, its slot will not be reused, if you do not use |
325 * Remove a local variable, its slot will not be reused, if you do not use |
330 * addLocalVariable with an explicit index argument. |
326 * addLocalVariable with an explicit index argument. |
331 */ |
327 */ |
332 public void removeLocalVariable(final LocalVariableGen l) { |
328 public void removeLocalVariable(final LocalVariableGen l) { |
333 variable_vec.remove(l); |
329 variable_vec.remove(l); |
334 } |
330 } |
335 |
331 |
|
332 |
336 /** |
333 /** |
337 * Remove all local variables. |
334 * Remove all local variables. |
338 */ |
335 */ |
339 public void removeLocalVariables() { |
336 public void removeLocalVariables() { |
340 variable_vec.clear(); |
337 variable_vec.clear(); |
341 } |
338 } |
|
339 |
342 |
340 |
343 /* |
341 /* |
344 * If the range of the variable has not been set yet, it will be set to be valid from |
342 * If the range of the variable has not been set yet, it will be set to be valid from |
345 * the start to the end of the instruction list. |
343 * the start to the end of the instruction list. |
346 * |
344 * |
347 * @return array of declared local variables sorted by index |
345 * @return array of declared local variables sorted by index |
348 */ |
346 */ |
349 public LocalVariableGen[] getLocalVariables() { |
347 public LocalVariableGen[] getLocalVariables() { |
350 return getLocalVariableOrTypes(false); |
348 final int size = variable_vec.size(); |
351 } |
349 final LocalVariableGen[] lg = new LocalVariableGen[size]; |
352 |
350 variable_vec.toArray(lg); |
353 /* |
|
354 * If the range of the variable has not been set yet, it will be set to be |
|
355 * valid from the start to the end of the instruction list. |
|
356 * |
|
357 * @return array of declared local variable types sorted by index |
|
358 */ |
|
359 private LocalVariableGen[] getLocalVariableTypes() { |
|
360 return getLocalVariableOrTypes(true); |
|
361 } |
|
362 |
|
363 /* |
|
364 * If the range of the variable or type has not been set yet, it will be set |
|
365 * to be valid from the start to the end of the instruction list. |
|
366 * |
|
367 * @return array of declared local variables or types sorted by index |
|
368 */ |
|
369 private LocalVariableGen[] getLocalVariableOrTypes(boolean isLVT) { |
|
370 int size = (isLVT) ? type_vec.size() : variable_vec.size(); |
|
371 LocalVariableGen[] lg = new LocalVariableGen[size]; |
|
372 if (isLVT) { |
|
373 type_vec.toArray(lg); |
|
374 } else { |
|
375 variable_vec.toArray(lg); |
|
376 } |
|
377 |
|
378 for (int i = 0; i < size; i++) { |
351 for (int i = 0; i < size; i++) { |
379 if (lg[i].getStart() == null) { |
352 if ((lg[i].getStart() == null) && (il != null)) { |
380 lg[i].setStart(il.getStart()); |
353 lg[i].setStart(il.getStart()); |
381 } |
354 } |
382 |
355 if ((lg[i].getEnd() == null) && (il != null)) { |
383 if (lg[i].getEnd() == null) { |
|
384 lg[i].setEnd(il.getEnd()); |
356 lg[i].setEnd(il.getEnd()); |
385 } |
357 } |
386 } |
358 } |
387 |
|
388 if (size > 1) { |
359 if (size > 1) { |
389 Arrays.sort(lg, new Comparator<LocalVariableGen>() { |
360 Arrays.sort(lg, new Comparator<LocalVariableGen>() { |
390 @Override |
361 @Override |
391 public int compare(final LocalVariableGen o1, final LocalVariableGen o2) { |
362 public int compare(final LocalVariableGen o1, final LocalVariableGen o2) { |
392 return o1.getIndex() - o2.getIndex(); |
363 return o1.getIndex() - o2.getIndex(); |
393 } |
364 } |
394 }); |
365 }); |
395 } |
366 } |
396 |
|
397 return lg; |
367 return lg; |
398 } |
368 } |
399 |
369 |
400 /** |
370 |
401 * @return `LocalVariableTable' attribute of all the local variables of this |
371 /** |
402 * method. |
372 * @return `LocalVariableTable' attribute of all the local variables of this method. |
403 */ |
373 */ |
404 public LocalVariableTable getLocalVariableTable(final ConstantPoolGen cp) { |
374 public LocalVariableTable getLocalVariableTable( final ConstantPoolGen cp ) { |
405 final LocalVariableGen[] lg = getLocalVariables(); |
375 final LocalVariableGen[] lg = getLocalVariables(); |
406 final int size = lg.length; |
376 final int size = lg.length; |
407 final LocalVariable[] lv = new LocalVariable[size]; |
377 final LocalVariable[] lv = new LocalVariable[size]; |
408 for (int i = 0; i < size; i++) { |
378 for (int i = 0; i < size; i++) { |
409 lv[i] = lg[i].getLocalVariable(cp); |
379 lv[i] = lg[i].getLocalVariable(cp); |
411 return new LocalVariableTable(cp.addUtf8("LocalVariableTable"), 2 + lv.length * 10, lv, cp |
381 return new LocalVariableTable(cp.addUtf8("LocalVariableTable"), 2 + lv.length * 10, lv, cp |
412 .getConstantPool()); |
382 .getConstantPool()); |
413 } |
383 } |
414 |
384 |
415 /** |
385 /** |
416 * @return `LocalVariableTypeTable' attribute of all the local variable |
386 * @return `LocalVariableTypeTable' attribute of this method. |
417 * types of this method. |
387 */ |
418 */ |
388 public LocalVariableTypeTable getLocalVariableTypeTable() { |
419 public LocalVariableTypeTable getLocalVariableTypeTable(ConstantPoolGen cp) { |
389 return local_variable_type_table; |
420 LocalVariableGen[] lg = getLocalVariableTypes(); |
|
421 int size = lg.length; |
|
422 LocalVariable[] lv = new LocalVariable[size]; |
|
423 |
|
424 for (int i = 0; i < size; i++) { |
|
425 lv[i] = lg[i].getLocalVariable(cp); |
|
426 } |
|
427 |
|
428 return new LocalVariableTypeTable(cp.addUtf8("LocalVariableTypeTable"), |
|
429 2 + lv.length * 10, lv, cp.getConstantPool()); |
|
430 } |
|
431 |
|
432 /** |
|
433 * Adds a local variable type to this method. |
|
434 * |
|
435 * @param name variable name |
|
436 * @param type variable type |
|
437 * @param slot the index of the local variable, if type is long or double, |
|
438 * the next available index is slot+2 |
|
439 * @param start from where the variable is valid |
|
440 * @param end until where the variable is valid |
|
441 * @return new local variable object |
|
442 * @see LocalVariable |
|
443 */ |
|
444 private LocalVariableGen addLocalVariableType(String name, Type type, int slot, |
|
445 InstructionHandle start, |
|
446 InstructionHandle end) { |
|
447 byte t = type.getType(); |
|
448 |
|
449 if (t != Const.T_ADDRESS) { |
|
450 int add = type.getSize(); |
|
451 |
|
452 if (slot + add > max_locals) { |
|
453 max_locals = slot + add; |
|
454 } |
|
455 |
|
456 LocalVariableGen l = new LocalVariableGen(slot, name, type, start, end); |
|
457 int i; |
|
458 |
|
459 if ((i = type_vec.indexOf(l)) >= 0) // Overwrite if necessary |
|
460 { |
|
461 type_vec.set(i, l); |
|
462 } else { |
|
463 type_vec.add(l); |
|
464 } |
|
465 |
|
466 return l; |
|
467 } else { |
|
468 throw new IllegalArgumentException("Can not use " + type |
|
469 + " as type for local variable"); |
|
470 } |
|
471 } |
|
472 |
|
473 /** |
|
474 * Remove all local variable types. |
|
475 */ |
|
476 private void removeLocalVariableTypes() { |
|
477 type_vec.clear(); |
|
478 } |
390 } |
479 |
391 |
480 /** |
392 /** |
481 * Give an instruction a line number corresponding to the source code line. |
393 * Give an instruction a line number corresponding to the source code line. |
482 * |
394 * |
483 * @param ih instruction to tag |
395 * @param ih instruction to tag |
484 * @return new line number object |
396 * @return new line number object |
485 * @see LineNumber |
397 * @see LineNumber |
486 */ |
398 */ |
487 public LineNumberGen addLineNumber(final InstructionHandle ih, final int src_line) { |
399 public LineNumberGen addLineNumber( final InstructionHandle ih, final int src_line ) { |
488 final LineNumberGen l = new LineNumberGen(ih, src_line); |
400 final LineNumberGen l = new LineNumberGen(ih, src_line); |
489 line_number_vec.add(l); |
401 line_number_vec.add(l); |
490 return l; |
402 return l; |
491 } |
403 } |
492 |
404 |
|
405 |
493 /** |
406 /** |
494 * Remove a line number. |
407 * Remove a line number. |
495 */ |
408 */ |
496 public void removeLineNumber(final LineNumberGen l) { |
409 public void removeLineNumber( final LineNumberGen l ) { |
497 line_number_vec.remove(l); |
410 line_number_vec.remove(l); |
498 } |
411 } |
|
412 |
499 |
413 |
500 /** |
414 /** |
501 * Remove all line numbers. |
415 * Remove all line numbers. |
502 */ |
416 */ |
503 public void removeLineNumbers() { |
417 public void removeLineNumbers() { |
504 line_number_vec.clear(); |
418 line_number_vec.clear(); |
505 } |
419 } |
|
420 |
506 |
421 |
507 /* |
422 /* |
508 * @return array of line numbers |
423 * @return array of line numbers |
509 */ |
424 */ |
510 public LineNumberGen[] getLineNumbers() { |
425 public LineNumberGen[] getLineNumbers() { |
511 final LineNumberGen[] lg = new LineNumberGen[line_number_vec.size()]; |
426 final LineNumberGen[] lg = new LineNumberGen[line_number_vec.size()]; |
512 line_number_vec.toArray(lg); |
427 line_number_vec.toArray(lg); |
513 return lg; |
428 return lg; |
514 } |
429 } |
515 |
430 |
516 /** |
431 |
517 * @return `LineNumberTable' attribute of all the local variables of this |
432 /** |
518 * method. |
433 * @return `LineNumberTable' attribute of all the local variables of this method. |
519 */ |
434 */ |
520 public LineNumberTable getLineNumberTable(final ConstantPoolGen cp) { |
435 public LineNumberTable getLineNumberTable( final ConstantPoolGen cp ) { |
521 final int size = line_number_vec.size(); |
436 final int size = line_number_vec.size(); |
522 final LineNumber[] ln = new LineNumber[size]; |
437 final LineNumber[] ln = new LineNumber[size]; |
523 for (int i = 0; i < size; i++) { |
438 for (int i = 0; i < size; i++) { |
524 ln[i] = line_number_vec.get(i).getLineNumber(); |
439 ln[i] = line_number_vec.get(i).getLineNumber(); |
525 } |
440 } |
526 return new LineNumberTable(cp.addUtf8("LineNumberTable"), 2 + ln.length * 4, ln, cp |
441 return new LineNumberTable(cp.addUtf8("LineNumberTable"), 2 + ln.length * 4, ln, cp |
527 .getConstantPool()); |
442 .getConstantPool()); |
528 } |
443 } |
529 |
444 |
530 /** |
445 |
531 * Add an exception handler, i.e., specify region where a handler is active |
446 /** |
532 * and an instruction where the actual handling is done. |
447 * Add an exception handler, i.e., specify region where a handler is active and an |
|
448 * instruction where the actual handling is done. |
533 * |
449 * |
534 * @param start_pc Start of region (inclusive) |
450 * @param start_pc Start of region (inclusive) |
535 * @param end_pc End of region (inclusive) |
451 * @param end_pc End of region (inclusive) |
536 * @param handler_pc Where handling is done |
452 * @param handler_pc Where handling is done |
537 * @param catch_type class type of handled exception or null if any |
453 * @param catch_type class type of handled exception or null if any |
538 * exception is handled |
454 * exception is handled |
539 * @return new exception handler object |
455 * @return new exception handler object |
540 */ |
456 */ |
541 public CodeExceptionGen addExceptionHandler(final InstructionHandle start_pc, |
457 public CodeExceptionGen addExceptionHandler( final InstructionHandle start_pc, |
542 final InstructionHandle end_pc, final InstructionHandle handler_pc, final ObjectType catch_type) { |
458 final InstructionHandle end_pc, final InstructionHandle handler_pc, final ObjectType catch_type ) { |
543 if ((start_pc == null) || (end_pc == null) || (handler_pc == null)) { |
459 if ((start_pc == null) || (end_pc == null) || (handler_pc == null)) { |
544 throw new ClassGenException("Exception handler target is null instruction"); |
460 throw new ClassGenException("Exception handler target is null instruction"); |
545 } |
461 } |
546 final CodeExceptionGen c = new CodeExceptionGen(start_pc, end_pc, handler_pc, catch_type); |
462 final CodeExceptionGen c = new CodeExceptionGen(start_pc, end_pc, handler_pc, catch_type); |
547 exception_vec.add(c); |
463 exception_vec.add(c); |
548 return c; |
464 return c; |
549 } |
465 } |
550 |
466 |
|
467 |
551 /** |
468 /** |
552 * Remove an exception handler. |
469 * Remove an exception handler. |
553 */ |
470 */ |
554 public void removeExceptionHandler(final CodeExceptionGen c) { |
471 public void removeExceptionHandler( final CodeExceptionGen c ) { |
555 exception_vec.remove(c); |
472 exception_vec.remove(c); |
556 } |
473 } |
|
474 |
557 |
475 |
558 /** |
476 /** |
559 * Remove all line numbers. |
477 * Remove all line numbers. |
560 */ |
478 */ |
561 public void removeExceptionHandlers() { |
479 public void removeExceptionHandlers() { |
562 exception_vec.clear(); |
480 exception_vec.clear(); |
563 } |
481 } |
|
482 |
564 |
483 |
565 /* |
484 /* |
566 * @return array of declared exception handlers |
485 * @return array of declared exception handlers |
567 */ |
486 */ |
568 public CodeExceptionGen[] getExceptionHandlers() { |
487 public CodeExceptionGen[] getExceptionHandlers() { |
569 final CodeExceptionGen[] cg = new CodeExceptionGen[exception_vec.size()]; |
488 final CodeExceptionGen[] cg = new CodeExceptionGen[exception_vec.size()]; |
570 exception_vec.toArray(cg); |
489 exception_vec.toArray(cg); |
571 return cg; |
490 return cg; |
572 } |
491 } |
573 |
492 |
|
493 |
574 /** |
494 /** |
575 * @return code exceptions for `Code' attribute |
495 * @return code exceptions for `Code' attribute |
576 */ |
496 */ |
577 private CodeException[] getCodeExceptions() { |
497 private CodeException[] getCodeExceptions() { |
578 final int size = exception_vec.size(); |
498 final int size = exception_vec.size(); |
579 final CodeException[] c_exc = new CodeException[size]; |
499 final CodeException[] c_exc = new CodeException[size]; |
580 for (int i = 0; i < size; i++) { |
500 for (int i = 0; i < size; i++) { |
581 final CodeExceptionGen c = exception_vec.get(i); |
501 final CodeExceptionGen c = exception_vec.get(i); |
582 c_exc[i] = c.getCodeException(super.getConstantPool()); |
502 c_exc[i] = c.getCodeException(super.getConstantPool()); |
583 } |
503 } |
584 return c_exc; |
504 return c_exc; |
585 } |
505 } |
586 |
506 |
|
507 |
587 /** |
508 /** |
588 * Add an exception possibly thrown by this method. |
509 * Add an exception possibly thrown by this method. |
589 * |
510 * |
590 * @param class_name (fully qualified) name of exception |
511 * @param class_name (fully qualified) name of exception |
591 */ |
512 */ |
592 public void addException(final String class_name) { |
513 public void addException( final String class_name ) { |
593 throws_vec.add(class_name); |
514 throws_vec.add(class_name); |
594 } |
515 } |
595 |
516 |
|
517 |
596 /** |
518 /** |
597 * Remove an exception. |
519 * Remove an exception. |
598 */ |
520 */ |
599 public void removeException(final String c) { |
521 public void removeException( final String c ) { |
600 throws_vec.remove(c); |
522 throws_vec.remove(c); |
601 } |
523 } |
|
524 |
602 |
525 |
603 /** |
526 /** |
604 * Remove all exceptions. |
527 * Remove all exceptions. |
605 */ |
528 */ |
606 public void removeExceptions() { |
529 public void removeExceptions() { |
607 throws_vec.clear(); |
530 throws_vec.clear(); |
608 } |
531 } |
|
532 |
609 |
533 |
610 /* |
534 /* |
611 * @return array of thrown exceptions |
535 * @return array of thrown exceptions |
612 */ |
536 */ |
613 public String[] getExceptions() { |
537 public String[] getExceptions() { |
614 final String[] e = new String[throws_vec.size()]; |
538 final String[] e = new String[throws_vec.size()]; |
615 throws_vec.toArray(e); |
539 throws_vec.toArray(e); |
616 return e; |
540 return e; |
617 } |
541 } |
618 |
542 |
619 /** |
543 |
620 * @return `Exceptions' attribute of all the exceptions thrown by this |
544 /** |
621 * method. |
545 * @return `Exceptions' attribute of all the exceptions thrown by this method. |
622 */ |
546 */ |
623 private ExceptionTable getExceptionTable(final ConstantPoolGen cp) { |
547 private ExceptionTable getExceptionTable( final ConstantPoolGen cp ) { |
624 final int size = throws_vec.size(); |
548 final int size = throws_vec.size(); |
625 final int[] ex = new int[size]; |
549 final int[] ex = new int[size]; |
626 for (int i = 0; i < size; i++) { |
550 for (int i = 0; i < size; i++) { |
627 ex[i] = cp.addClass(throws_vec.get(i)); |
551 ex[i] = cp.addClass(throws_vec.get(i)); |
628 } |
552 } |
629 return new ExceptionTable(cp.addUtf8("Exceptions"), 2 + 2 * size, ex, cp.getConstantPool()); |
553 return new ExceptionTable(cp.addUtf8("Exceptions"), 2 + 2 * size, ex, cp.getConstantPool()); |
630 } |
554 } |
631 |
555 |
|
556 |
632 /** |
557 /** |
633 * Add an attribute to the code. Currently, the JVM knows about the |
558 * Add an attribute to the code. Currently, the JVM knows about the |
634 * LineNumberTable, LocalVariableTable and StackMap attributes, where the |
559 * LineNumberTable, LocalVariableTable and StackMap attributes, |
635 * former two will be generated automatically and the latter is used for the |
560 * where the former two will be generated automatically and the |
636 * MIDP only. Other attributes will be ignored by the JVM but do no harm. |
561 * latter is used for the MIDP only. Other attributes will be |
|
562 * ignored by the JVM but do no harm. |
637 * |
563 * |
638 * @param a attribute to be added |
564 * @param a attribute to be added |
639 */ |
565 */ |
640 public void addCodeAttribute(final Attribute a) { |
566 public void addCodeAttribute( final Attribute a ) { |
641 code_attrs_vec.add(a); |
567 code_attrs_vec.add(a); |
642 } |
568 } |
643 |
569 |
|
570 |
|
571 /** |
|
572 * Remove the LocalVariableTypeTable |
|
573 */ |
|
574 public void removeLocalVariableTypeTable( ) { |
|
575 local_variable_type_table = null; |
|
576 } |
|
577 |
644 /** |
578 /** |
645 * Remove a code attribute. |
579 * Remove a code attribute. |
646 */ |
580 */ |
647 public void removeCodeAttribute(final Attribute a) { |
581 public void removeCodeAttribute( final Attribute a ) { |
648 code_attrs_vec.remove(a); |
582 code_attrs_vec.remove(a); |
649 } |
583 } |
650 |
584 |
|
585 |
651 /** |
586 /** |
652 * Remove all code attributes. |
587 * Remove all code attributes. |
653 */ |
588 */ |
654 public void removeCodeAttributes() { |
589 public void removeCodeAttributes() { |
|
590 local_variable_type_table = null; |
655 code_attrs_vec.clear(); |
591 code_attrs_vec.clear(); |
656 } |
592 } |
|
593 |
657 |
594 |
658 /** |
595 /** |
659 * @return all attributes of this method. |
596 * @return all attributes of this method. |
660 */ |
597 */ |
661 public Attribute[] getCodeAttributes() { |
598 public Attribute[] getCodeAttributes() { |
802 } |
774 } |
803 } |
775 } |
804 } |
776 } |
805 } |
777 } |
806 |
778 |
|
779 |
807 /** |
780 /** |
808 * Set maximum number of local variables. |
781 * Set maximum number of local variables. |
809 */ |
782 */ |
810 public void setMaxLocals(final int m) { |
783 public void setMaxLocals( final int m ) { |
811 max_locals = m; |
784 max_locals = m; |
812 } |
785 } |
|
786 |
813 |
787 |
814 public int getMaxLocals() { |
788 public int getMaxLocals() { |
815 return max_locals; |
789 return max_locals; |
816 } |
790 } |
817 |
791 |
|
792 |
818 /** |
793 /** |
819 * Set maximum stack size for this method. |
794 * Set maximum stack size for this method. |
820 */ |
795 */ |
821 public void setMaxStack(final int m) { // TODO could be package-protected? |
796 public void setMaxStack( final int m ) { // TODO could be package-protected? |
822 max_stack = m; |
797 max_stack = m; |
823 } |
798 } |
|
799 |
824 |
800 |
825 public int getMaxStack() { |
801 public int getMaxStack() { |
826 return max_stack; |
802 return max_stack; |
827 } |
803 } |
828 |
804 |
829 /** |
805 |
830 * @return class that contains this method |
806 /** @return class that contains this method |
831 */ |
807 */ |
832 public String getClassName() { |
808 public String getClassName() { |
833 return class_name; |
809 return class_name; |
834 } |
810 } |
835 |
811 |
836 public void setClassName(final String class_name) { // TODO could be package-protected? |
812 |
|
813 public void setClassName( final String class_name ) { // TODO could be package-protected? |
837 this.class_name = class_name; |
814 this.class_name = class_name; |
838 } |
815 } |
839 |
816 |
840 public void setReturnType(final Type return_type) { |
817 |
|
818 public void setReturnType( final Type return_type ) { |
841 setType(return_type); |
819 setType(return_type); |
842 } |
820 } |
|
821 |
843 |
822 |
844 public Type getReturnType() { |
823 public Type getReturnType() { |
845 return getType(); |
824 return getType(); |
846 } |
825 } |
847 |
826 |
848 public void setArgumentTypes(final Type[] arg_types) { |
827 |
|
828 public void setArgumentTypes( final Type[] arg_types ) { |
849 this.arg_types = arg_types; |
829 this.arg_types = arg_types; |
850 } |
830 } |
|
831 |
851 |
832 |
852 public Type[] getArgumentTypes() { |
833 public Type[] getArgumentTypes() { |
853 return arg_types.clone(); |
834 return arg_types.clone(); |
854 } |
835 } |
855 |
836 |
856 public void setArgumentType(final int i, final Type type) { |
837 |
|
838 public void setArgumentType( final int i, final Type type ) { |
857 arg_types[i] = type; |
839 arg_types[i] = type; |
858 } |
840 } |
859 |
841 |
860 public Type getArgumentType(final int i) { |
842 |
|
843 public Type getArgumentType( final int i ) { |
861 return arg_types[i]; |
844 return arg_types[i]; |
862 } |
845 } |
863 |
846 |
864 public void setArgumentNames(final String[] arg_names) { |
847 |
|
848 public void setArgumentNames( final String[] arg_names ) { |
865 this.arg_names = arg_names; |
849 this.arg_names = arg_names; |
866 } |
850 } |
|
851 |
867 |
852 |
868 public String[] getArgumentNames() { |
853 public String[] getArgumentNames() { |
869 return arg_names.clone(); |
854 return arg_names.clone(); |
870 } |
855 } |
871 |
856 |
872 public void setArgumentName(final int i, final String name) { |
857 |
|
858 public void setArgumentName( final int i, final String name ) { |
873 arg_names[i] = name; |
859 arg_names[i] = name; |
874 } |
860 } |
875 |
861 |
876 public String getArgumentName(final int i) { |
862 |
|
863 public String getArgumentName( final int i ) { |
877 return arg_names[i]; |
864 return arg_names[i]; |
878 } |
865 } |
|
866 |
879 |
867 |
880 public InstructionList getInstructionList() { |
868 public InstructionList getInstructionList() { |
881 return il; |
869 return il; |
882 } |
870 } |
883 |
871 |
884 public void setInstructionList(final InstructionList il) { // TODO could be package-protected? |
872 |
|
873 public void setInstructionList( final InstructionList il ) { // TODO could be package-protected? |
885 this.il = il; |
874 this.il = il; |
886 } |
875 } |
|
876 |
887 |
877 |
888 @Override |
878 @Override |
889 public String getSignature() { |
879 public String getSignature() { |
890 return Type.getMethodSignature(super.getType(), arg_types); |
880 return Type.getMethodSignature(super.getType(), arg_types); |
891 } |
881 } |
|
882 |
892 |
883 |
893 /** |
884 /** |
894 * Computes max. stack size by performing control flow analysis. |
885 * Computes max. stack size by performing control flow analysis. |
895 */ |
886 */ |
896 public void setMaxStack() { // TODO could be package-protected? (some tests would need repackaging) |
887 public void setMaxStack() { // TODO could be package-protected? (some tests would need repackaging) |
951 static final class BranchStack { |
944 static final class BranchStack { |
952 |
945 |
953 private final Stack<BranchTarget> branchTargets = new Stack<>(); |
946 private final Stack<BranchTarget> branchTargets = new Stack<>(); |
954 private final Map<InstructionHandle, BranchTarget> visitedTargets = new HashMap<>(); |
947 private final Map<InstructionHandle, BranchTarget> visitedTargets = new HashMap<>(); |
955 |
948 |
956 public void push(final InstructionHandle target, final int stackDepth) { |
949 |
|
950 public void push( final InstructionHandle target, final int stackDepth ) { |
957 if (visited(target)) { |
951 if (visited(target)) { |
958 return; |
952 return; |
959 } |
953 } |
960 branchTargets.push(visit(target, stackDepth)); |
954 branchTargets.push(visit(target, stackDepth)); |
961 } |
955 } |
|
956 |
962 |
957 |
963 public BranchTarget pop() { |
958 public BranchTarget pop() { |
964 if (!branchTargets.empty()) { |
959 if (!branchTargets.empty()) { |
965 final BranchTarget bt = branchTargets.pop(); |
960 final BranchTarget bt = branchTargets.pop(); |
966 return bt; |
961 return bt; |
967 } |
962 } |
968 return null; |
963 return null; |
969 } |
964 } |
970 |
965 |
971 private BranchTarget visit(final InstructionHandle target, final int stackDepth) { |
966 |
|
967 private BranchTarget visit( final InstructionHandle target, final int stackDepth ) { |
972 final BranchTarget bt = new BranchTarget(target, stackDepth); |
968 final BranchTarget bt = new BranchTarget(target, stackDepth); |
973 visitedTargets.put(target, bt); |
969 visitedTargets.put(target, bt); |
974 return bt; |
970 return bt; |
975 } |
971 } |
976 |
972 |
977 private boolean visited(final InstructionHandle target) { |
973 |
|
974 private boolean visited( final InstructionHandle target ) { |
978 return visitedTargets.get(target) != null; |
975 return visitedTargets.get(target) != null; |
979 } |
976 } |
980 } |
977 } |
981 |
978 |
982 /** |
979 |
983 * Computes stack usage of an instruction list by performing control flow |
980 /** |
984 * analysis. |
981 * Computes stack usage of an instruction list by performing control flow analysis. |
985 * |
982 * |
986 * @return maximum stack depth used by method |
983 * @return maximum stack depth used by method |
987 */ |
984 */ |
988 public static int getMaxStack(final ConstantPoolGen cp, final InstructionList il, |
985 public static int getMaxStack( final ConstantPoolGen cp, final InstructionList il, final CodeExceptionGen[] et ) { |
989 final CodeExceptionGen[] et) { |
|
990 final BranchStack branchTargets = new BranchStack(); |
986 final BranchStack branchTargets = new BranchStack(); |
991 /* Initially, populate the branch stack with the exception |
987 /* Initially, populate the branch stack with the exception |
992 * handlers, because these aren't (necessarily) branched to |
988 * handlers, because these aren't (necessarily) branched to |
993 * explicitly. in each case, the stack will have depth 1, |
989 * explicitly. in each case, the stack will have depth 1, |
994 * containing the exception object. |
990 * containing the exception object. |