Fixed the case of using 'this' before throw in constructor

This commit is contained in:
Andrey Breslav
2013-05-12 18:09:31 +03:00
parent dc8fca2532
commit 23be9f8d44
@@ -302,6 +302,8 @@ public class InterceptionInstrumenter {
mv = getDumpingVisitorWrapper(mv, name, desc); mv = getDumpingVisitorWrapper(mv, name, desc);
} }
final boolean isConstructor = "<init>".equals(name);
final int finalMaxParamCount = maxParamCount; final int finalMaxParamCount = maxParamCount;
return new MethodVisitorWithUniversalHandler(ASM4, mv) { return new MethodVisitorWithUniversalHandler(ASM4, mv) {
@@ -331,7 +333,9 @@ public class InterceptionInstrumenter {
if (enterDataWritten) return; if (enterDataWritten) return;
enterDataWritten = true; enterDataWritten = true;
for (MethodData methodData : enterData) { for (MethodData methodData : enterData) {
invokeMethod(access, name, desc, getInstructionAdapter(), methodData, "<init>".equals(name)); // At the very beginning of a constructor, i.e. before any super() call, 'this' is not available
// It's too hard to detect a place right after the super() call, so we just put null instead of 'this' in such cases
invokeMethod(access, name, desc, getInstructionAdapter(), methodData, isConstructor);
} }
} }
@@ -347,7 +351,9 @@ public class InterceptionInstrumenter {
case ARETURN: case ARETURN:
case ATHROW: case ATHROW:
for (MethodData methodData : exitData) { for (MethodData methodData : exitData) {
invokeMethod(access, name, desc, getInstructionAdapter(), methodData, false); // A constructor may throw before calling super(), 'this' is not available in this case
boolean beforeThrowInConstructor = opcode == ATHROW && isConstructor;
invokeMethod(access, name, desc, getInstructionAdapter(), methodData, beforeThrowInConstructor);
} }
break; break;
} }
@@ -398,7 +404,7 @@ public class InterceptionInstrumenter {
String instrumentedMethodDesc, String instrumentedMethodDesc,
InstructionAdapter ia, InstructionAdapter ia,
MethodData methodData, MethodData methodData,
boolean constructorEntryPoint boolean thisUnavailable
) { ) {
FieldData field = methodData.getOwnerField(); FieldData field = methodData.getOwnerField();
ia.getstatic(field.getDeclaringClass(), field.getName(), field.getDesc()); ia.getstatic(field.getDeclaringClass(), field.getName(), field.getDesc());
@@ -412,10 +418,9 @@ public class InterceptionInstrumenter {
int parameterOffset = 0; int parameterOffset = 0;
for (int i = 0; i < parameterCount; i++) { for (int i = 0; i < parameterCount; i++) {
if (i == methodData.getThisParameterIndex()) { if (i == methodData.getThisParameterIndex()) {
if (isStatic || constructorEntryPoint) { if (isStatic || thisUnavailable) {
// a) static method, 'this' is null // a) static method, 'this' is null
// b) At the very beginning of a constructor, i.e. before any super() call, 'this' is not available // b) this is not available (some locations in constructors
// It's too hard to detect a place right after the super() call, so we just put null instead of 'this' in such cases
ia.aconst(null); ia.aconst(null);
} }
else { else {