Skip to content

Support using scope in evaluateInFrame #2122

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

Merged

Conversation

annagrin
Copy link
Contributor

@annagrin annagrin commented May 25, 2023

Support using scope in evaluateInFrame to allow DevTools eval-and-browse feature to work on web platform: flutter/devtools#4962

Previously, to implement VmService.evaluateInFrame, we used Runtime.evaluateOnCallFrame chrome remote debugging API to evaluate the dart expression compiled to JS. Unfortunately, this API does not allow passing additional scope, so we did not support passing additional scope for vm_service.evaluateInFrame on web platform. This worked well until the need for passing additional scope to expression evaluation surfaced in eval-and-browse feature in dart DevTools.

This change supports passing scope to VmService.evaluateInFrame by:

  • Allow passing non-empty scope in ExpressionEvaluator.evaluateExpressionInFrame.
    • Create class JsBuilder for efficient JS code building.
    • Use JsBuilder in expression evaluator to create JS expressions to pass to chrome DevTools API.
    • If scope was passed to evaluateExpressionInFrame:
      • collect all variables currently in scope from WipCallFrame object.
      • create a JS function that takes the scope as params and call it using
        Runtime.callFunctionOn API, with scope variables passed as arguments.
      • handle this parameter specially by using JS bind().
  • Keep the original implementation for empty scope case as an optimization.
  • Add tests.

Details

For example, to evaluate a dart expression

this.t + a + x + y

in a dart scope that defines a and this, and additional scope x, y, we

  • compile dart function

    (x, y, a) { return this.t + a + x + y; } 

    to JavaScript function

    jsFunc

    using the expression compiler (i.e. frontend server or expression compiler worker).

  • create JavaScript wrapper function, jsWrapperFunc, defined as

    function (x, y, a, __t$this) {
      try {
        return function (x, y, a) {
          return jsFunc(x, y, a);
        }.bind(__t$this)(x, y, a);
      } catch (error) {
        return error.name + ": " + error.message;
      }
    }
  • collect scope variable object IDs for total scope (frame scope from WipCallFrame object + additional scope)

  • call jsWrapperFunc using Runtime.callFunctionOn chrome API with scope variable object IDs passed as arguments.

Closes: #1344
Towards: flutter/devtools#4962

@annagrin annagrin marked this pull request as draft May 25, 2023 23:49
@annagrin annagrin marked this pull request as ready for review May 31, 2023 16:19
@annagrin annagrin requested review from elliette, nshahan and jacob314 May 31, 2023 16:22
Copy link
Contributor

@elliette elliette left a comment

Choose a reason for hiding this comment

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

LGTM with a couple comments

Copy link
Member

@jacob314 jacob314 left a comment

Choose a reason for hiding this comment

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

Looks good overall. Looking forward to this support!
lgtm_dog2

@annagrin annagrin merged commit b10d62b into dart-lang:master Jun 2, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

EvaluateInFrame does not support scope
4 participants