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

C# dynamic feature #154

Closed
eusebiu opened this issue May 2, 2011 · 3 comments
Closed

C# dynamic feature #154

eusebiu opened this issue May 2, 2011 · 3 comments
Assignees
Labels

Comments

@eusebiu
Copy link
Contributor

eusebiu commented May 2, 2011

I've pasted only a part of the original and generated code but you can find it all in here: ICSharpCode.SharpDevelop.Project.WebProjectService.CreateVirtualDirectory

Original:
dynamic manager = webAdministrationAssembly.CreateInstance("Microsoft.Web.Administration.ServerManager");
if (manager.Sites[DEFAULT_WEB_SITE] != null) {
...
} else {...}

Generated:
object arg2 = assembly.CreateInstance("Microsoft.Web.Administration.ServerManager");
if (WebProjectService.o__SiteContainer0.<>p__Site1 == null)
{
WebProjectService.o__SiteContainer0.<>p__Site1 = CallSite<Func<CallSite, object, bool>>.Create(Microsoft.CSharp.RuntimeBinder.Binder.UnaryOperation(CSharpBinderFlags.None, ExpressionType.IsTrue, typeof(WebProjectService), new CSharpArgumentInfo[]
{
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)
}));
}
Func<CallSite, object, bool> arg_1CB_0 = WebProjectService.o__SiteContainer0.<>p__Site1.Target;
CallSite arg_1CB_1 = WebProjectService.o__SiteContainer0.<>p__Site1;
if (WebProjectService.o__SiteContainer0.<>p__Site2 == null)
{
WebProjectService.o__SiteContainer0.<>p__Site2 = CallSite<Func<CallSite, object, object, object>>.Create(Microsoft.CSharp.RuntimeBinder.Binder.BinaryOperation(CSharpBinderFlags.None, ExpressionType.NotEqual, typeof(WebProjectService), new CSharpArgumentInfo[]
{
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.Constant, null)
}));
}

@kg
Copy link

kg commented May 23, 2011

I have a partial implementation of this in sq@f65f90b . I may never finish it, since it currently provides all the metadata I need (I use ILAst instead of C# AST), but if anyone wants to own finishing this I'd be glad to help you out.

@siegfriedpammer siegfriedpammer modified the milestone: 3.0 Sep 7, 2017
@siegfriedpammer siegfriedpammer added C# Decompiler The decompiler engine itself labels Sep 14, 2017
@dgrunwald dgrunwald removed this from the 3.0 milestone Oct 13, 2017
@dgrunwald
Copy link
Member

dgrunwald commented May 1, 2018

Implementation idea: Replace call site delegate invocations with special IL instructions.

Create a bunch of new types of IL instructions, one for each method in the Microsoft.CSharp.RuntimeBinder.Binder class:

  • DynamicBinaryOperation
  • DynamicConvert
  • DynamicGetIndex
  • DynamicGetMember
  • DynamicInvoke
  • DynamicInvokeConstructor
  • DynamicInvokeMember
  • DynamicIsEvent
  • DynamicSetIndex
  • DynamicSetMember
  • DynamicUnaryOperation

These instructions would contain the information from the dynamic call-site, and have child-instructions for the arguments passed to the delegate call.
For example, class DynamicBinaryOperation would have fields:

CSharpBinderFlags flags;
ExpressionType operation;
IType context;
DynamicArgumentInfo leftArgumentInfo;
ILInstruction left;
DynamicArgumentInfo rightArgumentInfo;
ILInstruction right;

All the dynamic instruction types should probably derive from a common base class (DynamicInstruction?), and the flags member might be stored in that base class.

Create a new ILAst transform that detects the if (cachedCallSite == null) { ... } pattern and replaces cachedCallSite.Target delegate invocations with the new ILInstructions.
Due to interactions with short-circuiting operators &&/||, this transform should run before ConditionDetection. Maybe somewhere around the switch transforms?

The transform should probably not expect the call site initialization to be directly before the target delegate invocation -- while this assumption held true in all our tests so far, I wouldn't count on it; and it's easy to keep the transform flexible in this regard.

Extend the C# ExpressionBuilder to translate the new ILAst instructions into the corresponding C# expressions. It's important to cast all input operands to the exact expected type -- either the static type stored in the call-site, or to dynamic (also, mind special cases such as the null literal).

Now, some instructions (e.g. DynamicIsEvent or DynamicUnaryOperation with operator false don't have a direct C# equivalent). Instead, they are part of a higher-level pattern made up of multiple ILAst instructions (so far, we've identified "dynamic compound assignments" and "dynamic short-circuiting operators" as separate high-level patterns, but there might be more).
We'll handle these in a separate transform. But I think we can ignore them for the first implementation, as there are plenty uses of dynamic that won't encounter these special cases.

@siegfriedpammer siegfriedpammer self-assigned this May 3, 2018
@siegfriedpammer
Copy link
Member

Implemented in 58c174c

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 10, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

4 participants