From 23be9f8d44d7f5f0982281f782ab96942bc2a220 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Sun, 12 May 2013 18:09:31 +0300 Subject: [PATCH] Fixed the case of using 'this' before throw in constructor --- .../InterceptionInstrumenter.java | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/compiler/preloader/instrumentation/src/org/jetbrains/jet/preloading/instrumentation/InterceptionInstrumenter.java b/compiler/preloader/instrumentation/src/org/jetbrains/jet/preloading/instrumentation/InterceptionInstrumenter.java index 780613d264a..f95973fb2c6 100644 --- a/compiler/preloader/instrumentation/src/org/jetbrains/jet/preloading/instrumentation/InterceptionInstrumenter.java +++ b/compiler/preloader/instrumentation/src/org/jetbrains/jet/preloading/instrumentation/InterceptionInstrumenter.java @@ -302,6 +302,8 @@ public class InterceptionInstrumenter { mv = getDumpingVisitorWrapper(mv, name, desc); } + final boolean isConstructor = "".equals(name); + final int finalMaxParamCount = maxParamCount; return new MethodVisitorWithUniversalHandler(ASM4, mv) { @@ -331,7 +333,9 @@ public class InterceptionInstrumenter { if (enterDataWritten) return; enterDataWritten = true; for (MethodData methodData : enterData) { - invokeMethod(access, name, desc, getInstructionAdapter(), methodData, "".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 ATHROW: 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; } @@ -398,7 +404,7 @@ public class InterceptionInstrumenter { String instrumentedMethodDesc, InstructionAdapter ia, MethodData methodData, - boolean constructorEntryPoint + boolean thisUnavailable ) { FieldData field = methodData.getOwnerField(); ia.getstatic(field.getDeclaringClass(), field.getName(), field.getDesc()); @@ -412,10 +418,9 @@ public class InterceptionInstrumenter { int parameterOffset = 0; for (int i = 0; i < parameterCount; i++) { if (i == methodData.getThisParameterIndex()) { - if (isStatic || constructorEntryPoint) { + if (isStatic || thisUnavailable) { // a) static method, 'this' is null - // b) 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 + // b) this is not available (some locations in constructors ia.aconst(null); } else {