-
Notifications
You must be signed in to change notification settings - Fork 130
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
debugging transformed code #7
Comments
Hi! I've had some thoughts about potentially allowing a way to disable async just for debugging. This would work by replacing calls to await with a basic join. That would likely fix the debugging issues, but then the runtime behaviour would be significantly different as the code would block the thread rather than rewriting your method to be a state machine returning a task immediately, so it's not ideal from that point of view. If you (or anyone else) has any thoughts on how we might approach this problem I'm certainly open to ideas! |
I see, What if you had a code transformation for async that only add bytecode to the existing method and don't completely modify the existing byte code - doesn't then the existing debug information will be kept relevant and therefore will allow debugging? Let me try to explain myself: (and on this occasion also say sorry for the long post :) ) assume that you have the following class: class Test {
static CompletableFuture<Integer> doSomthingAsync() { ... }
static CompletableFuture<Integer> transformMe(int k) {
int sum=0; //line 1
for (int i=0; i<k; i++) //line 2
sum+=await(doSomethingAsync()); //line 3
return completedFuture(sum); //line 4
}
} If it will be compiled with debug information it will contain a LineNumberTable for the debugger that is in sync with the source code, static CompletableFuture<Integer> transformMe(int k) {
AsyncState$transformMe state = AsyncState.get();
if (state == null) {
state = new AsyncState$transformMe(k);
}
switch (state.state) {
case 0: goto START; //using the goto op code
case 1: goto STATE_1; //using the goto op code
}
START:
int sum=0; //line 1
for (int i=0; i<k; i++) { //line 2
state.$local1 = sum;
state.$local2 = i;
return state.bind(doSomethingAsync(), 1)
STATE_1:
sum = state.$local1;
i = state$local2;
sum+=(Integer) state.lastAwaitResult(); //line 3
}
return state.complete(completedFuture(sum)); //line 4
} Where AsyncState is the following class: abstract class AsyncState {
private final static ThreadLocal<AsyncState> STATE_HOLDER = new ThreadLocal<>();
public static <T extends AsyncState> T get() {
T res = (T) STATE_HOLDER.get();
STATE_HOLDER.remove();
return res;
}
public static void set(AsyncState state) {STATE_HOLDER.set(state); }
private CompletableFuture result = new CompletableFuture();
public int state = 0;
public Object lastResult;
abstract void doContinue();
CompletableFuture bind (CompletablFuture target, int nextState) {
target.whenComplete((v,e) -> {
if (e == null) {
this.state = nextState;
AsyncState.set(this);
this.lastResult = v;
doContinue();
}else {
result.completeExceptionally(e);
}
});
return result;
}
CompletableFuture complete(CompletableFuture fin) {
fin.whenComplete((v,e) -> {
if (e == null) {
result.complete(v);
}else {
result.completeExceptionally(e);
}
});
return result;
}
} And public class AsyncState$transformMe extends AsyncState {
public int $arg1;
public int $local1;
public int $local2;
public AsyncState$transformMe(int $arg1) {this.$arg1 = $arg1;}
void doContinue() {
transformMe($arg1);
}
} Under this transformation, the original source code is still inside the same method and with a little adjustments one can align the LineNumbersTable accordingly which (theoretically at least) should keep the debugger happy.. Do you think It can work? BTW, I am sure that it is a huge change in the code and I not suggesting you should change the whole design - It is just an idea that I hope can help.. |
@bennylut It is usually still possible to debug the instrumented code. the line information is not lost. The only situation where we have problems debugging it is when the instrumentation is done in runtime without the java agent. Offline instrumentation; or runtime instrumentation with the java agent; seem to debug fine. However, your issue might be something we haven't encountered before. Which IDE are you using? |
Great work on the project! I still encounter that problem in IntelliJ, I encountered using the Gradle instrumental tool, and the runtime option |
Hi, first I just want to say - great job!
I noticed that when I use this library I cannot debug a method that has been modified, when I try to I receive the following error:
JDWP exit error JVMTI_ERROR_NONE(0): getting frame location [stepControl.c:641]
is this a limitation that you planning to resolve?
The text was updated successfully, but these errors were encountered: