Skip to content
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

PR2 of conditional BP #154

Merged
merged 10 commits into from
Mar 15, 2018
Merged

PR2 of conditional BP #154

merged 10 commits into from
Mar 15, 2018

Conversation

andxu
Copy link
Contributor

@andxu andxu commented Mar 12, 2018

  1. Fix the issue when the condition is updated
  2. Add a cache to the compiled expression for conditional breakpoint.

@@ -31,6 +31,9 @@
private List<IBreakpoint> breakpoints;
private HashMap<String, HashMap<String, IBreakpoint>> sourceToBreakpoints;
private AtomicInteger nextBreakpointId = new AtomicInteger(1);
// BreakpointManager is the owner class of the breakpoint to compiled expression map, it will remove
// the breakpoint from this map if the breakpoint is removed or changing its condition
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if the breakpoint is removed or changing its condition ==> if the breakpoint is removed or its condition is changed

…am is stopped at the exception

2. update a comment
}

if (!StringUtils.equals(toAdds[i].getCondition(), added[i].getCondition())) {
manager.updateConditionCompiledExpression(added[i], toAdds[i].getCondition());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is strange put the hitCount update in here while keep the condition update in other places. The logic is mixed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because updating condition will need to clear the expression cache.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

setHitCount contains the logic to update hit count in jvm, it is not a pure set function.

}

if (project == null) {
new IllegalStateException(String.format("Project %s cannot be found.", projectName));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why new a unused exception?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will use exception for the failure of initialization to debugTarget

}
}

if (debugTarget == null) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The outside is already have this logic

debugTarget == null

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we have two if blocks with the same condition to check whether debugTarget is null?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Old issue in previous code, will fix it.

@@ -178,6 +188,37 @@ public void clearState(ThreadReference thread) {
}
}

private boolean ensureDebugTarget(VirtualMachine vm) {
String projectName = (String) options.get(Constants.PROJECTNAME);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If debugTarget is not null, this line is not necessary ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure

2. fix the issue of a dirty evaluation environment cause the next evaluation failure.
*
* @return the compiled expression map
*/
public Map<IBreakpoint, Object> getBreakpointExpressionMap() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the cache is only used by the evaluation Provider, should it be better put insider the evaluation provider?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the keys are managed by breakpoint manager, and the values are managed by evaluation evaluation provider, I don't think its better for breakpoint manager to reference JdtEvaluationProvider

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JDT are storing expression in JavaLineBreakpoint@fCompiledExpressions

/**
 * The map of cached compiled expressions (ICompiledExpression) for this
 * breakpoint, keyed by thread. This value must be cleared every time the
 * breakpoint is added to a target.
 */
private Map<IJavaThread, ICompiledExpression> fCompiledExpressions = new HashMap<>();

ASTEvaluationEngine engine = new ASTEvaluationEngine(project, debugTarget);
ICompiledExpression ie = (ICompiledExpression) breakpointExpressionMap
.computeIfAbsent(breakpoint, bp -> engine.getCompiledExpression(bp.getCondition(), stackframe));

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Return failureFuture and internalEvaluate result are two different instance. The client cannot hoop up with both future.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done with a CompletableFuture parameter in internalEvaluate

@@ -31,6 +31,9 @@
private List<IBreakpoint> breakpoints;
private HashMap<String, HashMap<String, IBreakpoint>> sourceToBreakpoints;
private AtomicInteger nextBreakpointId = new AtomicInteger(1);
// BreakpointManager is the owner class of the breakpoint to compiled expression map, it will remove
// the breakpoint from this map if the breakpoint is removed or its condition is changed
private Map<IBreakpoint, Object> breakpointExpressionMap = new HashMap<>();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is the breakpoint manager maintaining the cache map but not the evaluation engine?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cache should be kept by evaluation engine. The BreakpointManger notifies the engine to invalidate cache entries.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because evaluation engine has no information about when the breakpoint is removed or updated.

}
}

if (debugTarget == null) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we have two if blocks with the same condition to check whether debugTarget is null?

@@ -178,6 +188,37 @@ public void clearState(ThreadReference thread) {
}
}

private boolean ensureDebugTarget(VirtualMachine vm) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The return value of ensureDebugTarget is never referenced anywhere. In the implementation, you use both exception and return value to indicate success, which is not recommended.

'ensure' means make sure something is actually there. When the function is not able to ensure that, an exception should be thrown. So please only use exceptions and the return value should be void.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure

if (launch == null) {
launch = createILaunchMock(project);
}
public CompletableFuture<Value> evaluateForBreakpoint(IBreakpoint breakpoint, ThreadReference thread, Map<IBreakpoint, Object> breakpointExpressionMap) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the difference of evaluating and evaluating for breakpoints?

Copy link
Contributor Author

@andxu andxu Mar 12, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because conditional breakpoint will be executed multiple time inside a loop(eval and cont), and the condition and location don't change, we need to optimize the conditional breakpoint, consider the following case, the i == 1000 will be evaluated 999 times before the breakpoint is to hit.

for (; i < 1000 + 1; i++) {
if (i == 1000) { # conditional BP of i == 1000
System.out.println( "1111" );
}
}

2. keep only one CompletableFuture in evaluate
@andxu andxu merged commit 0b3da27 into master Mar 15, 2018
@andxu andxu deleted the andy_dev4 branch March 15, 2018 01:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants