-
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
[mono] Hot Reload: support for reloadable types #66749
Merged
lambdageek
merged 37 commits into
dotnet:main
from
lambdageek:hack-add-reloadable-types
Mar 18, 2022
Merged
[mono] Hot Reload: support for reloadable types #66749
lambdageek
merged 37 commits into
dotnet:main
from
lambdageek:hack-add-reloadable-types
Mar 18, 2022
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This reverts commit 51ebd8d77d3d8e8a0e04bfba641134448e3c1813.
it "works" but only because we don't look very hard for the new properties anywhere. reflection is probably pretty broken.
keep the instance field ifdef for now
allow CustomAttribute row modifications to change Parent, while dotnet/roslyn#60125 is being sorted out
also mono_class_set_nested_classes_property
Change the iterator from storing MonoMethod** values to storing an iteration count. For added methods, when the iteration count is more than mono_class_get_method_count, run through the hot reload added_members list and iterate over any relevant methods
also mono_class_get_field_count
Use GSList to simplify the concurrency story for accessing added_fields (and added_props and added_events, eventually): unlike a GPtrArray it won't resize, so we don't need to lock readers. Add a from_update bit to MonoProperty and MonoEvent - when props or events are added to existing classes, they will have the bit set. That means that pointer arithmetic to figure out the prop (or event) tokens won't be usable (since they're not allocated in one big block).
vargaz
approved these changes
Mar 17, 2022
This was referenced Mar 17, 2022
The upper 16 bits aren't used for ECMA flags, so grab a bit for metadata-update
since Mono doesn't support them yet
/azp run runtime-extra-platforms |
Azure Pipelines successfully started running 1 pipeline(s). |
/azp run runtime-extra-platforms |
Azure Pipelines successfully started running 1 pipeline(s). |
lambdageek
force-pushed
the
hack-add-reloadable-types
branch
from
March 17, 2022 22:14
07cab10
to
a98c4d8
Compare
/azp run runtime-extra-platforms |
Azure Pipelines successfully started running 1 pipeline(s). |
lambdageek
force-pushed
the
hack-add-reloadable-types
branch
from
March 17, 2022 23:12
a98c4d8
to
ed8cfe6
Compare
/azp run runtime-extra-platforms |
Azure Pipelines successfully started running 1 pipeline(s). |
lambdageek
force-pushed
the
hack-add-reloadable-types
branch
from
March 18, 2022 01:46
ed8cfe6
to
69bec93
Compare
/azp run runtime-extra-platforms |
Azure Pipelines successfully started running 1 pipeline(s). |
lambdageek
force-pushed
the
hack-add-reloadable-types
branch
from
March 18, 2022 03:47
69bec93
to
e3d7a58
Compare
/azp run runtime-extra-platforms |
Azure Pipelines successfully started running 1 pipeline(s). |
Add some fields to the baseline versions of some test assemblies to keep some types that are used in the deltas from getting trimmed away
lambdageek
force-pushed
the
hack-add-reloadable-types
branch
from
March 18, 2022 04:59
e3d7a58
to
2c56d90
Compare
/azp run runtime-extra-platforms |
Azure Pipelines successfully started running 1 pipeline(s). |
radekdoulik
pushed a commit
to radekdoulik/runtime
that referenced
this pull request
Mar 30, 2022
Fully implement support for the `NewTypeDefinition` EnC capability: a hot reload edit can add a new type definition (class, struct, interface, enum) that contains new fields, methods, properties, events, and nested classes, and can have generic params. Also add reflection support for all of the above. This is sufficient to support hot reload of types tagged with [`CreateNewOnMetadataUpdateAttribute`](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.createnewonmetadataupdateattribute?view=net-6.0). Contributes to dotnet#63643 and dotnet#57365 --- The implementation introduces `MonoAddedDefSkeleton` which is a bookkeeping structure that records the metadata indexes of where to find methods, fields, properties and events for a newly-added class. The issue is that normally `mono_class_create_from_typedef` expects to find all that stuff in a contiguous block starting at the row pointed by the `MONO_TYPEDEF_FIELD_LIST` or `MONO_TYPEDEF_METHOD_LIST` columns of the new typedef. But in EnC deltas, those columns are zeroed out, and instead the EnCLog functions like `ENC_FUNC_ADD_METHOD` and `ENC_FUNC_ADD_FIELD` explicitly record when a new row is added that is relevant to a particular type definition. So during the pass over the EnCLog, we start creating skeletons when we see a new row added to the typedef table. Then when we see the add functions, we record the row indices of the field, method, etc tables. As far as I can tell, the rows for a particular type definition are contiguous, so we just record the first index and the count. At the end of the pass, we save the skeletons on the metadata delta, and when code finally creates the `MonoClass` for a particular freshly-added type definition, we check the skeleton and use the recorded rows to populate the fields and methods. Event and property data is created on-demand (the demand being reflection) in basically the same way. One important note: we try very hard not to accidentally materialize a newly-added class as a `MonoClass` during the update itself - we need to at least get through the entire EnCLog - otherwise we might not see every field/method/etc and set up the class incorrectly. The upshot is that the newly-added `MonoClass` behaves like any other "normal" class - all its fields are laid out normally (they're stored in the object, not in a separate hash table). It can be generic. It can have base types, interfaces, etc. This is different from how added fields, props and events will be implemented on existing classes - we won't modify `MonoClass:fields` or the `MonoClassPropertyInfo:properties` arrays - once they have been allocated, we don't want to mess with them. Instead additions to existing classes with create `MonoClassMetadataUpdateField` (`MonoClassMetadataUpdateProperty` and `MonoClassMetadataUpdateEvent`) structs that are going to be stored on the `MonoClassMetadataUpdateInfo` that's associated with each `MonoClass`. The various iterators like `mono_class_get_fields` and `mono_class_get_props` will be modified to return the added fields/props/etc after the existing ones. This is already implemented for fields. Props and Events will be part of a separate effort to implement reflection support for them. --- * Checkpoint. Infrastructure for added types * register member->parent lookups for newly-added classes and members * fix off by one error creating class from skeleton * AddNestedClass test works with mono now; also make it generic * checkpoint: adding properties it "works" but only because we don't look very hard for the new properties anywhere. reflection is probably pretty broken. * Add a property to AddNestedClass test * remove allow class/field/method/property ifdefs keep the instance field ifdef for now * add event to AddNestedClass * add DISALLOW_BROKEN_PARENT ifdef allow CustomAttribute row modifications to change Parent, while dotnet/roslyn#60125 is being sorted out * checkpoint: adding events * Add new test ReflectionAddNewType * Add new types to the image name cache * Assembly.GetTypes and additional tests * Make nested types work * GetInterfaces on new types; also Activator.CreateInstance * Mark mono_class_get_nested_classes_property as a component API also mono_class_set_nested_classes_property * Add GetMethods, GetFields, GetMethod, GetField test * [class] Implement added method iteration Change the iterator from storing MonoMethod** values to storing an iteration count. For added methods, when the iteration count is more than mono_class_get_method_count, run through the hot reload added_members list and iterate over any relevant methods * Implement added field iteration * Add a GetField(BindingFlags.Static) test case * Add Enum.GetNames and GetProperties tests - not working yet * Mark mono_class_get_method_count as a component API also mono_class_get_field_count * Enum values work * Use GSList for added_fields (and props, events); add from_update bit Use GSList to simplify the concurrency story for accessing added_fields (and added_props and added_events, eventually): unlike a GPtrArray it won't resize, so we don't need to lock readers. Add a from_update bit to MonoProperty and MonoEvent - when props or events are added to existing classes, they will have the bit set. That means that pointer arithmetic to figure out the prop (or event) tokens won't be usable (since they're not allocated in one big block). * Reflection on props in new classes works * events on new classes work * Add CustomAttribute reflection test * remove test for props on existing type - it's not part of this PR * instance field additions to existing types aren't supported yet * rm TODO and FIXME * store prop and event from_update bit in attrs The upper 16 bits aren't used for ECMA flags, so grab a bit for metadata-update * remove instance fields from reflection test since Mono doesn't support them yet * make the Browser EAT lanes happy Add some fields to the baseline versions of some test assemblies to keep some types that are used in the deltas from getting trimmed away
ghost
locked as resolved and limited conversation to collaborators
Apr 17, 2022
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Fully implement support for the
NewTypeDefinition
EnC capability: a hot reload edit can add a new type definition (class, struct, interface, enum) that contains new fields, methods, properties, events, and nested classes, and can have generic params. Also add reflection support for all of the above.This is sufficient to support hot reload of types tagged with
CreateNewOnMetadataUpdateAttribute
.Contributes to #63643 and #57365
The implementation introduces
MonoAddedDefSkeleton
which is a bookkeeping structure that records the metadata indexes of where to find methods, fields, properties and events for a newly-added class. The issue is that normallymono_class_create_from_typedef
expects to find all that stuff in a contiguous block starting at the row pointed by theMONO_TYPEDEF_FIELD_LIST
orMONO_TYPEDEF_METHOD_LIST
columns of the new typedef. But in EnC deltas, those columns are zeroed out, and instead the EnCLog functions likeENC_FUNC_ADD_METHOD
andENC_FUNC_ADD_FIELD
explicitly record when a new row is added that is relevant to a particular type definition.So during the pass over the EnCLog, we start creating skeletons when we see a new row added to the typedef table. Then when we see the add functions, we record the row indices of the field, method, etc tables. As far as I can tell, the rows for a particular type definition are contiguous, so we just record the first index and the count.
At the end of the pass, we save the skeletons on the metadata delta, and when code finally creates the
MonoClass
for a particular freshly-added type definition, we check the skeleton and use the recorded rows to populate the fields and methods. Event and property data is created on-demand (the demand being reflection) in basically the same way.One important note: we try very hard not to accidentally materialize a newly-added class as a
MonoClass
during the update itself - we need to at least get through the entire EnCLog - otherwise we might not see every field/method/etc and set up the class incorrectly.The upshot is that the newly-added
MonoClass
behaves like any other "normal" class - all its fields are laid out normally (they're stored in the object, not in a separate hash table). It can be generic. It can have base types, interfaces, etc.This is different from how added fields, props and events will be implemented on existing classes - we won't modify
MonoClass:fields
or theMonoClassPropertyInfo:properties
arrays - once they have been allocated, we don't want to mess with them. Instead additions to existing classes with createMonoClassMetadataUpdateField
(MonoClassMetadataUpdateProperty
andMonoClassMetadataUpdateEvent
) structs that are going to be stored on theMonoClassMetadataUpdateInfo
that's associated with eachMonoClass
. The various iterators likemono_class_get_fields
andmono_class_get_props
will be modified to return the added fields/props/etc after the existing ones.This is already implemented for fields. Props and Events will be part of a separate effort to implement reflection support for them.