Skip to content

Commit

Permalink
Plugin speed-up: decrease the number of #beforeEvent calls (#433)
Browse files Browse the repository at this point in the history
  • Loading branch information
zuevmaxim authored Dec 10, 2024
1 parent e8fce19 commit c4745c8
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 25 deletions.
44 changes: 43 additions & 1 deletion bootstrap/src/sun/nio/ch/lincheck/Injections.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,31 @@ public class Injections {
// Used in the verification phase to store a suspended continuation.
public static Object lastSuspendedCancellableContinuationDuringVerification = null;

/**
* Mark value of {@link #requestedBeforeEventId} field to skip calls to {@link #beforeEvent}.
*/
@SuppressWarnings("unused")
private static final int DO_NOT_TRIGGER_BEFORE_EVENT = -1;

/**
* Mark value of {@link #requestedBeforeEventId} field to always call {@link #beforeEvent}.
*/
private static final int STOP_AT_NEXT_EVENT_ID = -2;

/**
* This field is updated from the debugger to request a specific ID.
* <p>
* The default value is calling always for compatibility with old plugin versions.
*/
@SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal"})
private static int requestedBeforeEventId = STOP_AT_NEXT_EVENT_ID;

/**
* This field is used by the debugger to have a fast source of current ID.
*/
@SuppressWarnings({"FieldCanBeLocal", "unused"})
private static int currentEventId = -1;

public static void storeCancellableContinuation(Object cont) {
Thread t = Thread.currentThread();
if (t instanceof TestThread) {
Expand Down Expand Up @@ -337,15 +362,32 @@ public static boolean shouldInvokeBeforeEvent() {
return getEventTracker().shouldInvokeBeforeEvent();
}

/**
* This method is introduced for performance purposes.
* Instead of calling {@link #beforeEvent} on every event, we call it only at the requested point.
* It greatly improves the performance as the debugger installs a breakpoint into {@link #beforeEvent} method,
* so each call leads to unnecessary lincheck-debugger communication.
* @param eventId current id value
* @return whether the current point should lead to {@link #beforeEvent} call
*/
public static boolean isBeforeEventRequested(int eventId) {
int requestedId = requestedBeforeEventId;
return requestedId == STOP_AT_NEXT_EVENT_ID || requestedId == eventId;
}

public static void beforeEvent(int eventId, String type) {
// IDEA plugin installs breakpoint to this method
getEventTracker().beforeEvent(eventId, type);
}

/**
* Gets current ID and sets it into {@link #currentEventId}.
* @param type type of the next event. Used only for debug purposes.
*/
public static int getNextEventId(String type) {
return getEventTracker().getEventId();
int eventId = getEventTracker().getEventId();
currentEventId = eventId;
return eventId;
}

public static void setLastMethodCallEventId() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,26 +92,26 @@ object ObjectLabelFactory {
}

@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
private val Class<out Any>?.isImmutableWithNiceToString
get() = this?.canonicalName in
listOf(
java.lang.Integer::class.java,
java.lang.Long::class.java,
java.lang.Short::class.java,
java.lang.Double::class.java,
java.lang.Float::class.java,
java.lang.Character::class.java,
java.lang.Byte::class.java,
java.lang.Boolean::class.java,
java.lang.String::class.java,
BigInteger::class.java,
BigDecimal::class.java,
kotlinx.coroutines.internal.Symbol::class.java,
).map { it.canonicalName } +
listOf(
"java.util.Collections.SingletonList",
"java.util.Collections.SingletonMap",
"java.util.Collections.SingletonSet"
)
private val Class<out Any>?.isImmutableWithNiceToString: Boolean
get() = this?.canonicalName in NICE_TO_STRING_CLASSES
}

}
private val NICE_TO_STRING_CLASSES = listOf(
java.lang.Integer::class.java,
java.lang.Long::class.java,
java.lang.Short::class.java,
java.lang.Double::class.java,
java.lang.Float::class.java,
java.lang.Character::class.java,
java.lang.Byte::class.java,
java.lang.Boolean::class.java,
java.lang.String::class.java,
BigInteger::class.java,
BigDecimal::class.java,
).map { it.canonicalName } +
listOf(
"kotlinx.coroutines.internal.Symbol",
"java.util.Collections.SingletonList",
"java.util.Collections.SingletonMap",
"java.util.Collections.SingletonSet"
)
Original file line number Diff line number Diff line change
Expand Up @@ -228,8 +228,19 @@ internal fun GeneratorAdapter.invokeBeforeEvent(debugMessage: String, setMethodE
}
push(debugMessage)
invokeStatic(Injections::getNextEventId)
push(debugMessage)
invokeStatic(Injections::beforeEvent)
dup()
ifStatement(
condition = {
invokeStatic(Injections::isBeforeEventRequested)
},
ifClause = {
push(debugMessage)
invokeStatic(Injections::beforeEvent)
},
elseClause = {
pop()
}
)
},
elseClause = {}
)
Expand Down

0 comments on commit c4745c8

Please sign in to comment.