-
Notifications
You must be signed in to change notification settings - Fork 223
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
Cache the reflection call done for completions #736
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good call! One possible optimization.
@@ -337,5 +326,28 @@ static public string[] FindDotSourcedIncludes(Ast scriptAst) | |||
|
|||
return dotSourcedVisitor.DotSourcedFiles.ToArray(); | |||
} | |||
|
|||
private static MethodInfo GetExtentCloneMethod(Ast scriptAst) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this would be better as just a static field. If your looking for how you could do that without an instance, you could do this:
private static MethodInfo s_extentCloneWithNewOffset =
typeof(PSObject).Assembly.GetType("System.Management.Automation.InternalScriptExtent")
.GetMethod(...
Maybe set in a static constructor because of the compiler directives.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I was wondering what the best way to do this was. Figured we'd find a better way in the PR. Thanks!
Ok, I've updated to use a better way to get the MethodInfo. Once we're on netstandard2.0, we might be able to improve on the
You can model what I'm imagining doing with this PowerShell: $cwno = [psobject].GetTypeInfo().Assembly.GetType("System.Management.Automation.Language.InternalScriptPosition", $true).GetMethod("CloneWithNewOffset", [System.Reflection.BindingFlags]::Instance -bor [System.Reflection.BindingFlags]::NonPublic)
$t = [System.Linq.Expressions.Expression]::GetFuncType(@($cwno.ReturnType, [int], $cwno.ReturnType))
[System.Delegate]::CreateDelegate($t, $null, $cwno) That should create the open delegate we want. The problem is just being able to invoke it when we can't express the type of the |
You could craft the delegate using LINQ expressions, e.g. using namespace System.Linq.Expressions
using namespace System.Management.Automation.Language
$scriptPositionType = [psobject].Assembly.
GetType('System.Management.Automation.Language.InternalScriptPosition')
$method = $scriptPositionType.
GetMethod(
'CloneWithNewOffset',
[System.Reflection.BindingFlags]'NonPublic, Instance',
$null,
[type[]][int],
@(1))
$source = [Expression]::Parameter([IScriptPosition], 'source')
$offset = [Expression]::Parameter([int], 'offset')
# (IScriptPosition)((InternalScriptPosition)source).CloneWithNewOffset(source, offset)
$delegateBody =
[Expression]::Convert(
[Expression]::Call(
[Expression]::Convert(
$source,
$scriptPositionType),
$method,
$offset),
[IScriptPosition])
$delegate = [Expression]::Lambda(
[Func[IScriptPosition, int, IScriptPosition]],
$delegateBody,
[ParameterExpression[]]($source, $offset)).
Compile() You could also write it in IL with |
Yeah I thought about writing a compiled LINQ expression around it, especially since that might be the right way to get around having to provide an But as you say, it gets pretty out of hand. Especially if we're just trying to avoid an array allocation. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Oooh, tests have found another breakage! Will look into it tomorrow. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like it!
I noticed that completion queries do a reflection call every time. This code caches instead, but it's not terribly elegant. So if you have any suggestions, please let me know.