-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
Support equivalent of AssemblyBuilder.Save to save in-memory IL to an assembly #62956
Comments
Tagging subscribers to this area: @dotnet/area-system-reflection Issue DetailsThe most common feature request in reflection, with 100+ upvotes, is to add support for equivalent Currently prototyping has started to investigate feasibility of adding the
|
Would that make |
@steveharter I have not fully investigated MetadataBuilder at this time, but is there a 'cheap' way to get all the IL needed and just pipe it into MetadataBuilder or do we need to do this IL-statement by IL-statement? Also, thanks @danmoseley for mentioning this API. I've been looking for this forever. |
It is done currently statement-by-statement, you need to create InstructionEncoder and emit statements into it, then pass it to MethodBodyStreamEncoder.AddMethodBody. I suppose, we could add new AddMethodBody overload that takes array of IL bytes and emits it as a whole if it would be found useful. But the important thing about that proposed adapter is that it should not just mechanically copy the contents of in-memory assembly into MetadataBuilder, it needs to do some changes - replace every reference to System.Private.CoreLib to System.Runtime, for example. So the ability to emit the whole IL array might not simplify the task significantly. |
@MSDN-WhiteKnight Thanks for the details. So, it's definitely not "cheap" as in "copy all IL bytes inside the assembly from A to B" but requires a more structured approach. Good to know because for me this means it's best to wait for the official API to catch up instead of doing it in my own code and then switch later on once the official API also supports it (aside from the question if/when/how best to contribute to this). |
Moving to 8.0. There is currently active prototyping work for this. |
@buyaa-n Thank you for the update! Since IL is not supported in the first drop and you mentioned testing out the APIs via Reflection: My scenario is to use runtime code generation to build subclass proxies and then persisting the generated assemblies so we don't pay for it during each application start. Right now, the Save-code is enabled only for the .NET Framework targeted assembly of our library. If I read the current state of the implementation correctly, there is no helpful information to gain if I try the current state via reflection. Since the complete feature is still marked for the .NET 8 release, I'll happily wait for the drop with IL support and test once my scenario becomes available. If there is anything I should test (and provide feedback on) before that point, please let me know. For completeness sake: right now I'm expecting that I can just call the same APIs again as I do in .NET Framework once the feature is production ready ( Thanks, Michael |
OK, sorry about that. Let's try this again, a bit less confrontationally. I was under the impression that the main reason The not-supported features described above all fall under the category of "generate IL and metadata," which doesn't feel like something that needs to be reimplemented in a cross-platform manner. (There is no platform-dependent code in |
This expectation can't be met. It is already decided that API surface is different, the new API takes additional parameter for core assembly, while .NET Framework API always implied the current implementation's core assembly.
Same goes for this expectation, too. It was already discussed at length, maintainers stated that existing code is native and tied to Windows too much, so it's too hard to bring it cross platform. So the current work entirely reimplements everything as managed implementation on top of System.Reflection.Metadata. |
Let me paraphrase:
This sentence actually confuses me a bit right now:
Do you mean the features I mentioned or the features discussed in the announcement post ? In the announcement post, method bodies are listed as not (yet) supported. Thanks, Michael |
No, this is easily handled by Roslyn and the runtime can handle this as well. Windows PDBs (non-portable) are hard, but that is why Portable PDBs exist.
The original was deep within the runtime with a lot of unmanaged code. This is a complete rewrite in pure managed so that it can be independent of the runtime implementation and shared with other runtimes (i.e., NativeAOT mono etc). Also note that in .NET 8 the goal was for an MVP see the original announcement - #62956 (comment).
This is not ready for everyone to start using as if it is full support in .NET 8. It was meant as a friendly update on status with a brief outline of current support. The goal is to have the ability to generate arbitrary .NET Assemblies in a similar way in .NET Core, but that isn't the current level as it is a full rewrite and reconciliation of how an assembly is generated. There will be slight API changes for all the reasons mentioned in #62956 (comment). |
Okay, that's not a problem. Probably should have been a bit more highlevel with "expect". What I intended to express was, that there's a way similiar to |
The latter.
OK, that would do it. Thanks for clarifying! |
@AaronRobinsonMSFT and now I'm coming full circle and I'm terribly sorry for repeating the same question. I'll try super simple / unabiguous ones:
Thanks, Michael |
I'll take this one step further. I have relevant experience in implementing stuff like this. Is there any way I can contribute to get this into .NET 8? The community's been waiting 7 years for this feature already. If I can keep from adding another whole year onto that total, I'd like to. |
No.
Sadly no. It took a substantial amount of time to detangle the current implementation and we are not up against the code complete time frame.
This is likely a .NET 9 deliverable at the moment. There just hasn't been enough time for the team to make progress on it and handle the Reflection related work in flight.
@masonwheeler I don't think we have the time this release, but I'll let @buyaa-n @steveharter or @jkotas comment specifically on whether help could change that calculus. |
@AaronRobinsonMSFT Thank you for the answers! To me, the details on the updated milestones are very helpful :) |
Sorry seems my update was not clear about remaining work will not happen in .NET 8. I had mentioned it in the description:
The above will be planned for .NET 9
Thanks @masonwheeler, bare estimate of remaining work is listed above. You are welcome to contribute to any of those, though most of these needs IL support. Now we don't have a resource to put on this effort within .NET 8 timeframe. Therefore, I don't believe all of these could finish within .NET 8 timeframe with community contributions. Though your contribution could help the feature complete successfully in .NET 9 |
@buyaa-n Where in the repo would I find the relevant work-in-progress? Also, are you guys aware of ILPack, which implements most of this already? Have you looked at it and found any good reasons why its code couldn't be pulled into the Core codebase? (I've tried using it and found it to be an imperfect replacement for |
This issue is for tracking all relevant work and you can see relevant PRs linked to this issue. The last PR was #88503 We are aware of ILPack and it is saves |
@buyaa-n thanks for the contribution. I think most people here are just interested in dumping runtime generated code. This does not mean the code has to to run when reloaded. We have the tools to inspect the IL. While falling back to .NET desktop is generally good enough, there are cases, it makes it impossible to debug codegen on .NET core. So, is it possible to dump some (possible malformed) IL to a stream for analysis? |
From within the process that generated it, or outside? If the latter, ClrMD could be used to inspect dynamic modules from external process, it represents them as ClrModule with IsDynamic property set to true. I have my project CIL View that attempts to implement viewing dynamic assemblies from external process, but it does not handle everything and it is not tested with newer CLR versions (only tested with .NET Core 3.1 as of now). |
We could consider adding a bare minimum (or empty) IL support within .NET 8 RC1 period (by August 14th). If a community willing to contribute, else currently we don't have a resource to work on it. |
Closing the issue, we will open a new issue(s) for remaining work for .NET 9 planning. |
How does the Roslyn API help with IronPython? (See IronLanguages/ironpython2#351) As far as I know, the Rosyln API is rather centric to C#, and does not support the different interpretations of the DLR needed by Python. |
Could you link those new issues here, so we can follow them? Thanks! |
I will, when the issue(s) created. |
My dear friends, I am extremely happy that this issue gets some traction, but I feel like it is getting a little bit mishandled. Perhaps new issues should've been created before we close the root one, the one that got a fair number of upvotes and people actually watching it? And also, perhaps the issue that asks for a working |
FYI the root issue is still open: #15704, this was only for tracking the work for 8.0 |
Ah, I'm sorry, my bad then. Thanks for your work! |
UPDATE: we are making progress here, see the Tracking issue for detail |
UPDATE: we are making a good progress:
Planning to finish the main functionality (excluding entry point and PDB) and make related APIs public in preview 1. Here is the tracking issue for details: #92975. Now it would be great to test the implementation with a real-life scenario. I would really appreciate if you could:
Thank you in advance! |
The most common feature request in reflection, with 100+ upvotes, is to add support for equivalent
AssemblyBuilder.Save()
functionality. Since this exists in .NET Desktop, some consider this an adoption blocker.Prototyping done in .NET 7.0 to investigate feasibility of adding the
Save()
via an adapter fromAssemblyBuilder
to the newerMetadataBuilder
which supports writing IL to a Stream\file. Related issues:System.Reflection.Emit.AssemblyBuilder.Save
Unable to set EntryPoint on generated assemblies with System.Reflection.Emit
We plan to abstract out Reflection.Emit APIs in order to have two implementations, one that having old code to support all downlevel runtime, and a new implementation that replaces the current Reflection.Emit implementation with
AssemblyBuilder.Save()
support, steps:ParameterBuilder
andAssemblyBuilder.Save(string/stream)
reviewed and approvedAssemblyBuilder.Save(string/stream)
CustomAttributes
for all members like assembly/module (PR)Remaining work that out of .NET 8.0:
AssemblyBuilder.Save(string/stream)
(mostly will rely on community contributions)SignatureCallingConvention
,*RequiredCustomModifiers
,*OptionalCustomModifiers
)The text was updated successfully, but these errors were encountered: