This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

Bug 171342

Summary: Add API for ability to plug-in evaluator engine.
Product: debugger Reporter: Martin Entlicher <mentlicher>
Component: JavaAssignee: Martin Entlicher <mentlicher>
Status: CLOSED FIXED    
Severity: blocker CC: ivan, non_migrated_user, phejl, pjiricka
Priority: P3 Keywords: API, API_REVIEW_FAST
Version: 6.x   
Hardware: All   
OS: All   
Issue Type: ENHANCEMENT Exception Reporter:
Bug Depends on:    
Bug Blocks: 167254    
Attachments: Proposed API
Reworked Evaluator API

Description Martin Entlicher 2009-09-02 17:27:21 UTC
Currently JPDA debugger defines evaluator for Java language. But when JPDA debugger is debugging bytecode compiled from
different languages, language-specific evaluator is expected.
API that allows to register language-specific evaluator is necessary.
Comment 1 Martin Entlicher 2009-09-02 17:53:00 UTC
The idea is to introduce an abstract class Evaluator with two methods:
public Variable evaluate (String expression, CallStackFrame csf, ObjectVariable var)
and
public Value evaluate (String expression, StackFrame csf, int stackDepth, ObjectReference var, boolean canInvokeMethods,
                       Runnable methodInvokePreprocessor)

The first one should be overridden if the evaluator implementation can perform the evaluation using JPDADebugger APIs.
The implementation does not have to deal with JDI exceptions and it should be more safe.
The second method should be overridden if the evaluator implementation needs to use all functionality that JDI provides.
In that case it needs to count with JDI exceptions and when it's going to invoke methods, it's required to call
methodInvokePreprocessor.run() so that JPDA implementation is aware of running threads.
The implementation needs to override at least one of these two methods.

It's expected that clients will register one implementation of Evaluator class per language.
Comment 2 Martin Entlicher 2009-09-03 15:57:03 UTC
Created attachment 87061 [details]
Proposed API
Comment 3 Martin Entlicher 2009-09-03 15:59:33 UTC
Please review the API change and let me know whether this is suitable for JavaFX (and eventually other) language evaluator.
Comment 4 Martin Entlicher 2009-09-03 16:02:09 UTC
There will always be a default Evaluator implementation for Java language. That default implementation also acts as a
test of the Evaluator registration mechanism and Evaluator usage.
Comment 5 ivan 2009-09-03 21:08:37 UTC
question 1:
This is an api for debugging JVM based languages (javafx, jruby etc) right?
It's not connected to any truly generic evaluation?

question 2 (a bit of-topic):
native debugging would like to utilize EvaluateCode and the corresponding
window with a History node ... is any of that up and coming?


Comment 6 Jaroslav Tulach 2009-09-04 09:49:43 UTC
Y01 typo in "fro the desired"

Y02 what exactly the Registration.language() can return? Mime type?

Y03 Eliminate magic or test it. What exactly is the purpose of "class uoev extends UnsupportedOperationException 
implements Value"?

Y04 Split the Evaluator class into two interfaces JPDAEvaluator and JDIEvaluator each with single method. Possibly 
allow a single implementor to implement both (if that is a valid use case, is it?)

Y05 Get ready for growing parameters. Replace the three and six argument method with request/response pattern. 
http://wiki.apidesign.org/wiki/RequestResponse It will simplify your life when you find out you need fourth and 
seventh argument in future.
Comment 7 Martin Entlicher 2009-09-04 10:06:47 UTC
question 1:
Yes, this API is for JVM based languages that are compiled into bytecode.
We do not have a truly generic API (with representation of a stack frame and variables) that would allow to specify
truly generic evaluation. And it does not seem to be required so far.

question 2:
I've expected such question... We first try new UI in JPDA debugger and after they evolve into stable state, we can move
it into debuggercore. Please file a separate issue for this.
Comment 8 Martin Entlicher 2009-09-04 10:54:07 UTC
Y01: will fix, thanks.

Y02: Registration.language() returns what you specify in the annotation of the Evaluator implementation. E.g. "Java" for
default Java evaluator:
@Evaluator.Registration(language="Java")
It's the stratum of the language, or file name extension if the stratum is not defined.

Y03: Since the implementor does not have to override both methods, originally I planned them to just throw
UnsupportedOperationException. The calling code would try the second if the first one threw
UnsupportedOperationException. But since throwing an exception hurts performance, we just return it. It's an
implementation detail - private contract between Evaluator class and the calling code. This serves as a test of which
method is implemented.

Y04: Possible, but I would like to keep it as an abstract class so that I may add more methods in the future (though
it's not very likely we'll need more methods). It does not make much sense to implement both methods, if the first one
is implemented, the second is not called.

Y05: Good idea, perhaps both methods could be replaced with:

public interface Evaluator {
    Result evaluate(String expression, Context context);

    public final class Result {
        Variable var;
        Value v;
        public Result(Variable var) { this.var = var; }
        public Result(Value v) { this.v = v; }
        public Variable getVariable() { return var; }
        public Value getValue() { return v; }
    }

    /** Warning that clients must not implement this, new methods can be added. */
    // Clients receive implementation of this interface, created by debugger.jpda module.
    // This interface resides in api.debugger.jpda, so it can not be a final class,
    // since all the logic is in implementation module - debugger.jpda.
    public interface Context {
        CallStackFrame getCallStackFrame();
        ObjectVariable getContextVariable();
        StackFrame getStackFrame();
        int getStackDepth();
        ObjectReference getContextObject();
        boolean canInvokeMethods();
        void notifyMethodInvoke();
    }
}

The two separate methods are more clear IMHO, but this allows more flexibility.
Comment 9 Jaroslav Tulach 2009-09-04 12:51:33 UTC
Re. Y05. public interface Evaluator { void evaluate(Context context, Result res); }, would imho be even more flexible 
(context would need getExpression() getter too). Of course Context and Result shall be final classes. I know that the 
Context is created by other module, but that shall be easy resolve with a factory method like Context 
create(CallStackFrame, ObjectVariable, StackFrame, int, ObjectReference, boolean, Runnable), or (if you need lazy 
implementation you could even have Context create(Callable<CallStackFrame>, Callable<ObjectVariable>, 
Callable<StackFrame>, Callable<Integer>, Callable<ObjectReference>, boolean, Runnable). In spite of ugliness of such 
method, it does not hurt the API usability (if you hide it enough), as the only one who is supposed to call it is you.

Re. Y04, with Y05 you are unlikely to need to add new methods into the interface(s). You will be adding the methods to 
Context or Result classes which are easily extensible (as they are final).


Y06 I am not sure if you considered such solution, but with @EvaluatorRegistration you do not need the (public) 
Evaluator interface much. People could annotate any static method and you could call it via reflection:
@EvaluatorRegistration public static void evaluateLookup(Context c, Result r) {  ...  }



Re. Y03 Oh, the exception is returned, not thrown! That is really inventive (but I don't like it). In fact the 
throwing of exception is not that slow, the slowest operation (as far as I know) is exception's constructor and its 
fillInStackTrace() method. Anyway this will not be needed if you implement Y05 and/or Y04.

Comment 10 Martin Entlicher 2009-09-08 14:43:02 UTC
Created attachment 87277 [details]
Reworked Evaluator API
Comment 11 Martin Entlicher 2009-09-08 14:49:48 UTC
Reworked Evaluator API attached. It uses Y05 approach and therefore a single evaluate() method takes parameters through
Expression and Context final classes and produces Result. This adds more flexibility.
Comment 12 Martin Entlicher 2009-09-09 11:01:07 UTC
If there are no more comments on this, I'd like to integrate it tomorrow so that we can continue the work on JavaFX
evaluator...
Thanks.
Comment 13 Martin Entlicher 2009-09-10 08:31:44 UTC
Thanks for the review.
Comment 14 Martin Entlicher 2009-09-10 08:32:47 UTC
The Evaluator API together with the default implementation for Java language is implemented in changeset:  
144697:a3b3a7c43bed
http://hg.netbeans.org/main/rev/a3b3a7c43bed
Comment 15 Quality Engineering 2009-09-18 22:17:44 UTC
Integrated into 'main-golden', will be available in build *200909181401* on http://bits.netbeans.org/dev/nightly/ (upload may still be in progress)
Changeset: http://hg.netbeans.org/main-golden/rev/a3b3a7c43bed
User: mentlicher@netbeans.org
Log: #171342 - Evaluator API for languages compiled into bytecode.
Comment 16 Marian Mirilovic 2010-05-10 09:04:57 UTC
verified closed