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

[wasm][debugger] Improvement of memory consumption while Evaluating Expressions #61470

Merged
merged 15 commits into from
Nov 16, 2021

Conversation

thaystg
Copy link
Member

@thaystg thaystg commented Nov 11, 2021

Removing the usage of CSharpCompilation which was increasing the memory consumption and using CSharpScript.

@ghost
Copy link

ghost commented Nov 11, 2021

Tagging subscribers to this area: @thaystg
See info in area-owners.md if you want to be subscribed.

Issue Details

Removing the usage of CSharpCompilation which was increasing the memory consumption and using CSharpScript.

Author: thaystg
Assignees: -
Labels:

area-Debugger-mono

Milestone: -

case "void":
return "object";
case "boolean":
Copy link
Member

Choose a reason for hiding this comment

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

add this case to the tests too

Copy link
Member Author

@thaystg thaystg Nov 11, 2021

Choose a reason for hiding this comment

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

This line is testing it

("this.CallMethodWithParmBool(this.t)", TString("TRUE")),

Copy link
Member

Choose a reason for hiding this comment

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

Ah, and this was being handled by default: return value.GetType().FullName; earlier? Why the additional case then?

Copy link
Member Author

@thaystg thaystg Nov 11, 2021

Choose a reason for hiding this comment

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

Because I did this change:
image

And this change was needed because when the variable was being declared and used it was creating like this: var exampleVar4893742 = True; and the first letter of the True/False with uppercase throws a compilation error.

Copy link
Member

Choose a reason for hiding this comment

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

ok, that makes sense. IIUC, ConvertJSToCSharpType is being called once to get the value, and then GetTypeFullName also calls it. Instead, I think it would make sense for ConvertJSToCSharpType to return a (string type, string value), since the type that we want to use in the final expression is tied closely to the "value" that we return.

And the method can be renamed to something like ConvertJSToCSharpVariable.

lewing
lewing previously approved these changes Nov 11, 2021
@thaystg thaystg added the NO-MERGE The PR is not ready for merge yet (see discussion for detailed reasons) label Nov 12, 2021
Comment on lines +235 to +252
valueRet = "Newtonsoft.Json.Linq.JObject.FromObject(new {"
+ $"type = \"{type}\""
+ $", description = \"{variable["description"].Value<string>()}\""
+ $", className = \"{variable["className"].Value<string>()}\""
+ (subType != null ? $", subtype = \"{subType}\"" : "")
+ (objectId != null ? $", objectId = \"{objectId}\"" : "")
+ "})";
typeRet = "object";
break;
case "void":
return null;
}
throw new Exception($"Evaluate of this datatype {type} not implemented yet");//, "Unsupported");
}

private string GetTypeFullName(JToken variable)
{
string type = variable["type"].ToString();
string subType = variable["subtype"]?.Value<string>();
object value = ConvertJSToCSharpType(variable);

switch (type)
{
case "object":
{
if (subType == "null")
return variable["className"].Value<string>();
else
return "object";
}
case "void":
return "object";
valueRet = "Newtonsoft.Json.Linq.JObject.FromObject(new {"
+ $"type = \"object\","
+ $"description = \"object\","
+ $"className = \"object\","
+ $"subtype = \"null\""
+ "})";
typeRet = "object";
break;
Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure I understand these two.

  1. why do we need to use JObjects in the script?
  2. case "object": - would it be better to use Newtonsoft.Json.Linq.JObject.Parse(..) and pass the escaped string for variable?
  3. case "void": - why is this needed? And what does the variable look like here? And do we have a test for this?

Copy link
Member Author

Choose a reason for hiding this comment

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

  1. Because that is how we return simple variable values, so when it's something that we really need to execute we also keep the same way of returning the value.
  2. I think it's faster to not parse the string? once this is already parsed we don't need to parse it again?
  3. Yes, the tests evaluating method that return void.

Comment on lines 387 to 394
var result = await CSharpScript.EvaluateAsync(
string.Join("\n", findVarNMethodCall.variableDefinitions) + "\nreturn " + syntaxTree.ToString(),
ScriptOptions.Default.WithReferences(
typeof(object).Assembly,
typeof(Enumerable).Assembly,
typeof(JObject).Assembly
),
cancellationToken: token);
Copy link
Member

Choose a reason for hiding this comment

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

If we specifically catch CompilationErrorException here, can we surface the error to VS? or maybe just return the exception message like on line 400.

Copy link
Member

Choose a reason for hiding this comment

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

Do I understand it correctly that if the expression itself throws an exception, then we return the message on line 400? Can we detect this specific case of the expression itself throwing, and return a different message?

Copy link
Member

Choose a reason for hiding this comment

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

If we specifically catch CompilationErrorException here, can we surface the error to VS? or maybe just return the exception message like on line 400.

IIUC, this would be thrown if our constructed script fails to compile, so maybe the message doesn't need to be shown to the user.

Copy link
Member

Choose a reason for hiding this comment

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

Do I understand it correctly that if the expression itself throws an exception, then we return the message on line 400? Can we detect this specific case of the expression itself throwing, and return a different message?

Looking at the code there is some handling for exceptions, though specifically System.Exception, and that then returns the message.

Though looking at it, this.PropertyThrowException correctly returns the exception message, but this.ParmToTestObjException.MyMethod() doesn't.

This doesn't need to be handled for this PR though.

@lewing lewing self-requested a review November 12, 2021 04:53
@lewing lewing dismissed their stale review November 12, 2021 04:53

rereview

@thaystg thaystg removed the NO-MERGE The PR is not ready for merge yet (see discussion for detailed reasons) label Nov 15, 2021
Copy link
Member

@radical radical left a comment

Choose a reason for hiding this comment

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

LGTM! Thank you for patiently working with the feedback :)

@@ -7,6 +7,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="3.7.0" />
Copy link
Member

Choose a reason for hiding this comment

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

For future PR, we should consider using the common version (more than one!) property for this, being used in other places in the repo.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants