Commit b78e4043 authored by Eric Bruneton's avatar Eric Bruneton

Improve the code quality of Handler and Handle.

parent 3f8159e0
......@@ -926,7 +926,7 @@ public class ClassWriter extends ClassVisitor {
}
} else if (cst instanceof Handle) {
Handle h = (Handle) cst;
return newHandleItem(h.tag, h.owner, h.name, h.desc, h.itf);
return newHandleItem(h.tag, h.owner, h.name, h.descriptor, h.isInterface);
} else {
throw new IllegalArgumentException("value " + cst);
}
......@@ -1126,7 +1126,8 @@ public class ClassWriter extends ClassVisitor {
int position = bootstrapMethods.length; // record current position
int hashCode = bsm.hashCode();
bootstrapMethods.putShort(newHandle(bsm.tag, bsm.owner, bsm.name, bsm.desc, bsm.isInterface()));
bootstrapMethods.putShort(
newHandle(bsm.tag, bsm.owner, bsm.name, bsm.descriptor, bsm.isInterface()));
int argsLength = bsmArgs.length;
bootstrapMethods.putShort(argsLength);
......
......@@ -51,10 +51,10 @@ public final class Handle {
final String name;
/** The descriptor of the field or method designated by this handle. */
final String desc;
final String descriptor;
/** Indicate if the owner is an interface or not. */
final boolean itf;
/** Whether the owner is an interface or not. */
final boolean isInterface;
/**
* Constructs a new field or method handle.
......@@ -67,13 +67,13 @@ public final class Handle {
* @param owner the internal name of the class that owns the field or method designated by this
* handle.
* @param name the name of the field or method designated by this handle.
* @param desc the descriptor of the field or method designated by this handle.
* @param descriptor the descriptor of the field or method designated by this handle.
* @deprecated this constructor has been superseded by {@link #Handle(int, String, String, String,
* boolean)}.
*/
@Deprecated
public Handle(int tag, String owner, String name, String desc) {
this(tag, owner, name, desc, tag == Opcodes.H_INVOKEINTERFACE);
public Handle(final int tag, final String owner, final String name, final String descriptor) {
this(tag, owner, name, descriptor, tag == Opcodes.H_INVOKEINTERFACE);
}
/**
......@@ -87,15 +87,20 @@ public final class Handle {
* @param owner the internal name of the class that owns the field or method designated by this
* handle.
* @param name the name of the field or method designated by this handle.
* @param desc the descriptor of the field or method designated by this handle.
* @param itf true if the owner is an interface.
* @param descriptor the descriptor of the field or method designated by this handle.
* @param isInterface whether the owner is an interface or not.
*/
public Handle(int tag, String owner, String name, String desc, boolean itf) {
public Handle(
final int tag,
final String owner,
final String name,
final String descriptor,
final boolean isInterface) {
this.tag = tag;
this.owner = owner;
this.name = name;
this.desc = desc;
this.itf = itf;
this.descriptor = descriptor;
this.isInterface = isInterface;
}
/**
......@@ -134,7 +139,7 @@ public final class Handle {
* @return the descriptor of the field or method designated by this handle.
*/
public String getDesc() {
return desc;
return descriptor;
}
/**
......@@ -143,44 +148,42 @@ public final class Handle {
* @return true if the owner of the field or method designated by this handle is an interface.
*/
public boolean isInterface() {
return itf;
return isInterface;
}
@Override
public boolean equals(Object obj) {
public boolean equals(final Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof Handle)) {
return false;
}
Handle h = (Handle) obj;
return tag == h.tag
&& itf == h.itf
&& owner.equals(h.owner)
&& name.equals(h.name)
&& desc.equals(h.desc);
Handle handle = (Handle) obj;
return tag == handle.tag
&& isInterface == handle.isInterface
&& owner.equals(handle.owner)
&& name.equals(handle.name)
&& descriptor.equals(handle.descriptor);
}
@Override
public int hashCode() {
return tag + (itf ? 64 : 0) + owner.hashCode() * name.hashCode() * desc.hashCode();
return tag
+ (isInterface ? 64 : 0)
+ owner.hashCode() * name.hashCode() * descriptor.hashCode();
}
/**
* Returns the textual representation of this handle. The textual representation is:
*
* <pre>
* for a reference to a class:
* owner '.' name desc ' ' '(' tag ')'
* for a reference to an interface:
* owner '.' name desc ' ' '(' tag ' ' itf ')'
* </pre>
*
* . As this format is unambiguous, it can be parsed if necessary.
* <ul>
* <li>for a reference to a class: owner "." name desc " (" tag ")",
* <li>for a reference to an interface: owner "." name desc " (" tag " itf )".
* </ul>
*/
@Override
public String toString() {
return owner + '.' + name + desc + " (" + tag + (itf ? " itf" : "") + ')';
return owner + '.' + name + descriptor + " (" + tag + (isInterface ? " itf" : "") + ')';
}
}
......@@ -28,80 +28,170 @@
package org.objectweb.asm;
/**
* Information about an exception handler block.
* Information about an exception handler. Corresponds to an element of the exception_table array of
* a Code attribute, as defined in the Java Virtual Machine Specification (JVMS). Handler instances
* can be chained together, with their {@link #nextHandler} field, to describe a full JVMS
* exception_table array.
*
* @see https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.3
* @author Eric Bruneton
*/
class Handler {
final class Handler {
/** Beginning of the exception handler's scope (inclusive). */
Label start;
/**
* The start_pc field of this JVMS exception_table entry. Corresponds to the beginning of the
* exception handler's scope (inclusive).
*/
final Label startPc;
/** End of the exception handler's scope (exclusive). */
Label end;
/**
* The end_pc field of this JVMS exception_table entry. Corresponds to the end of the exception
* handler's scope (exclusive).
*/
final Label endPc;
/** Beginning of the exception handler's code. */
Label handler;
/**
* The handler_pc field of this JVMS exception_table entry. Corresponding to the beginning of the
* exception handler's code.
*/
final Label handlerPc;
/**
* The catch_type field of this JVMS exception_table entry. This is the constant pool index of the
* internal name of the type of exceptions handled by this handler, or 0 to catch any exceptions.
*/
final int catchType;
/**
* Internal name of the type of exceptions handled by this handler, or <tt>null</tt> to catch any
* exceptions.
* The internal name of the type of exceptions handled by this handler, or <tt>null</tt> to catch
* any exceptions.
*/
String desc;
final String catchTypeDescriptor;
/** The next exception handler. */
Handler nextHandler;
/**
* Constant pool index of the internal name of the type of exceptions handled by this handler, or
* 0 to catch any exceptions.
* Constructs a new Handler.
*
* @param startPc the start_pc field of this JVMS exception_table entry.
* @param endPc the end_pc field of this JVMS exception_table entry.
* @param handlerPc the handler_pc field of this JVMS exception_table entry.
* @param catchType The catch_type field of this JVMS exception_table entry.
* @param catchTypeDescriptor The internal name of the type of exceptions handled by this handler,
* or <tt>null</tt> to catch any exceptions.
*/
int type;
Handler(
final Label startPc,
final Label endPc,
final Label handlerPc,
final int catchType,
final String catchTypeDescriptor) {
this.startPc = startPc;
this.endPc = endPc;
this.handlerPc = handlerPc;
this.catchType = catchType;
this.catchTypeDescriptor = catchTypeDescriptor;
}
/** Next exception handler block info. */
Handler next;
/**
* Constructs a new Handler from the given one, with a different scope.
*
* @param handler an existing Handler.
* @param startPc the start_pc field of this JVMS exception_table entry.
* @param endPc the end_pc field of this JVMS exception_table entry.
*/
Handler(final Handler handler, final Label startPc, final Label endPc) {
this(startPc, endPc, handler.handlerPc, handler.catchType, handler.catchTypeDescriptor);
this.nextHandler = handler.nextHandler;
}
/**
* Removes the range between start and end from the given exception handlers.
* Removes the range between start and end from the Handler list that begins with the given
* element.
*
* @param h an exception handler list.
* @param firstHandler the beginning of a Handler list. May be <tt>null</tt>.
* @param start the start of the range to be removed.
* @param end the end of the range to be removed. Maybe null.
* @param end the end of the range to be removed. Maybe <tt>null</tt>.
* @return the exception handler list with the start-end range removed.
*/
static Handler remove(Handler h, Label start, Label end) {
if (h == null) {
static Handler removeRange(final Handler firstHandler, final Label start, final Label end) {
if (firstHandler == null) {
return null;
} else {
h.next = remove(h.next, start, end);
firstHandler.nextHandler = removeRange(firstHandler.nextHandler, start, end);
}
int hstart = h.start.position;
int hend = h.end.position;
int s = start.position;
int e = end == null ? Integer.MAX_VALUE : end.position;
// if [hstart,hend[ and [s,e[ intervals intersect...
if (s < hend && e > hstart) {
if (s <= hstart) {
if (e >= hend) {
// [hstart,hend[ fully included in [s,e[, h removed
h = h.next;
} else {
// [hstart,hend[ minus [s,e[ = [e,hend[
h.start = end;
}
} else if (e >= hend) {
// [hstart,hend[ minus [s,e[ = [hstart,s[
h.end = start;
int handlerStart = firstHandler.startPc.position;
int handlerEnd = firstHandler.endPc.position;
int rangeStart = start.position;
int rangeEnd = end == null ? Integer.MAX_VALUE : end.position;
// Return early if [handlerStart,handlerEnd[ and [rangeStart,rangeEnd[ don't intersect.
if (rangeStart >= handlerEnd || rangeEnd <= handlerStart) {
return firstHandler;
}
if (rangeStart <= handlerStart) {
if (rangeEnd >= handlerEnd) {
// If [handlerStart,handlerEnd[ is included in [rangeStart,rangeEnd[, remove firstHandler.
return firstHandler.nextHandler;
} else {
// [hstart,hend[ minus [s,e[ = [hstart,s[ + [e,hend[
Handler g = new Handler();
g.start = end;
g.end = h.end;
g.handler = h.handler;
g.desc = h.desc;
g.type = h.type;
g.next = h.next;
h.end = start;
h.next = g;
// [handlerStart,handlerEnd[ - [rangeStart,rangeEnd[ = [rangeEnd,handlerEnd[
return new Handler(firstHandler, end, firstHandler.endPc);
}
} else if (rangeEnd >= handlerEnd) {
// [handlerStart,handlerEnd[ - [rangeStart,rangeEnd[ = [handlerStart,rangeStart[
return new Handler(firstHandler, firstHandler.startPc, start);
} else {
// [handlerStart,handlerEnd[ - [rangeStart,rangeEnd[ =
// [handlerStart,rangeStart[ + [rangeEnd,handerEnd[
firstHandler.nextHandler = new Handler(firstHandler, end, firstHandler.endPc);
return new Handler(firstHandler, firstHandler.startPc, start);
}
}
/**
* Returns the number of elements of the Handler list that begins with the given element.
*
* @param firstHandler the beginning of a Handler list. May be <tt>null</tt>.
* @return the number of elements of the Handler list that begins with 'handler'.
*/
static int getExceptionTableLength(final Handler firstHandler) {
int length = 0;
Handler handler = firstHandler;
while (handler != null) {
length++;
handler = handler.nextHandler;
}
return length;
}
/**
* Returns the size in bytes of the JVMS exception_table corresponding to the Handler list that
* begins with the given element. <i>This includes the exception_table_length field.</i>
*
* @param firstHandler the beginning of a Handler list. May be <tt>null</tt>.
* @return the size in bytes of the exception_table_length and exception_table structures.
*/
static int getExceptionTableSize(final Handler firstHandler) {
return 2 + 8 * getExceptionTableLength(firstHandler);
}
/**
* Puts the JVMS exception_table corresponding to the Handler list that begins with the given
* element. <i>This includes the exception_table_length field.</i>
*
* @param firstHandler the beginning of a Handler list. May be <tt>null</tt>.
* @param output where the exception_table_length and exception_table structures must be put.
*/
static void putExceptionTable(final Handler firstHandler, final ByteVector output) {
output.putShort(getExceptionTableLength(firstHandler));
Handler handler = firstHandler;
while (handler != null) {
output
.putShort(handler.startPc.position)
.putShort(handler.endPc.position)
.putShort(handler.handlerPc.position)
.putShort(handler.catchType);
handler = handler.nextHandler;
}
return h;
}
}
......@@ -221,9 +221,6 @@ class MethodWriter extends MethodVisitor {
*/
private int[] frame;
/** Number of elements in the exception handler list. */
private int handlerCount;
/** The first element in the exception handler list. */
private Handler firstHandler;
......@@ -710,7 +707,7 @@ class MethodWriter extends MethodVisitor {
} else {
code.put11(opcode, var);
}
if (opcode >= Opcodes.ISTORE && compute == FRAMES && handlerCount > 0) {
if (opcode >= Opcodes.ISTORE && compute == FRAMES && firstHandler != null) {
visitLabel(new Label());
}
}
......@@ -1203,17 +1200,11 @@ class MethodWriter extends MethodVisitor {
@Override
public void visitTryCatchBlock(
final Label start, final Label end, final Label handler, final String type) {
++handlerCount;
Handler h = new Handler();
h.start = start;
h.end = end;
h.handler = handler;
h.desc = type;
h.type = type != null ? cw.newClass(type) : 0;
if (lastHandler == null) {
Handler h = new Handler(start, end, handler, type != null ? cw.newClass(type) : 0, type);
if (firstHandler == null) {
firstHandler = h;
} else {
lastHandler.next = h;
lastHandler.nextHandler = h;
}
lastHandler = h;
}
......@@ -1329,11 +1320,14 @@ class MethodWriter extends MethodVisitor {
// completes the control flow graph with exception handler blocks
Handler handler = firstHandler;
while (handler != null) {
Label l = handler.start.getFirst();
Label h = handler.handler.getFirst();
Label e = handler.end.getFirst();
Label l = handler.startPc.getFirst();
Label h = handler.handlerPc.getFirst();
Label e = handler.endPc.getFirst();
// computes the kind of the edges to 'h'
String t = handler.desc == null ? "java/lang/Throwable" : handler.desc;
String t =
handler.catchTypeDescriptor == null
? "java/lang/Throwable"
: handler.catchTypeDescriptor;
int kind = Frame.OBJECT | cw.addType(t);
// h is an exception handler
h.status |= Label.TARGET;
......@@ -1349,7 +1343,7 @@ class MethodWriter extends MethodVisitor {
// goes to the next label
l = l.successor;
}
handler = handler.next;
handler = handler.nextHandler;
}
// creates and visits the first (implicit) frame
......@@ -1423,27 +1417,20 @@ class MethodWriter extends MethodVisitor {
endFrame();
// removes the start-end range from the exception
// handlers
firstHandler = Handler.remove(firstHandler, l, k);
firstHandler = Handler.removeRange(firstHandler, l, k);
}
}
l = l.successor;
}
handler = firstHandler;
handlerCount = 0;
while (handler != null) {
handlerCount += 1;
handler = handler.next;
}
this.maxStack = max;
} else if (compute == MAXS) {
// completes the control flow graph with exception handler blocks
Handler handler = firstHandler;
while (handler != null) {
Label l = handler.start;
Label h = handler.handler;
Label e = handler.end;
Label l = handler.startPc;
Label h = handler.handlerPc;
Label e = handler.endPc;
// adds 'h' as a successor of labels between 'start' and 'end'
while (l != e) {
// creates an edge to 'h'
......@@ -1464,7 +1451,7 @@ class MethodWriter extends MethodVisitor {
// goes to the next label
l = l.successor;
}
handler = handler.next;
handler = handler.nextHandler;
}
if (subroutines > 0) {
......@@ -1930,7 +1917,7 @@ class MethodWriter extends MethodVisitor {
throw new RuntimeException("Method code too large!");
}
cw.newUTF8("Code");
size += 18 + code.length + 8 * handlerCount;
size += 16 + code.length + Handler.getExceptionTableSize(firstHandler);
if (localVar != null) {
cw.newUTF8("LocalVariableTable");
size += 8 + localVar.length;
......@@ -2079,7 +2066,7 @@ class MethodWriter extends MethodVisitor {
}
out.putShort(attributeCount);
if (code.length > 0) {
int size = 12 + code.length + 8 * handlerCount;
int size = 10 + code.length + Handler.getExceptionTableSize(firstHandler);
if (localVar != null) {
size += 8 + localVar.length;
}
......@@ -2104,17 +2091,7 @@ class MethodWriter extends MethodVisitor {
out.putShort(cw.newUTF8("Code")).putInt(size);
out.putShort(maxStack).putShort(maxLocals);
out.putInt(code.length).putByteArray(code.data, 0, code.length);
out.putShort(handlerCount);
if (handlerCount > 0) {
Handler h = firstHandler;
while (h != null) {
out.putShort(h.start.position)
.putShort(h.end.position)
.putShort(h.handler.position)
.putShort(h.type);
h = h.next;
}
}
Handler.putExceptionTable(firstHandler, out);
attributeCount = 0;
if (localVar != null) {
++attributeCount;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment