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

[cdac] Read types from contract descriptor #101994

Merged
merged 10 commits into from
May 13, 2024

Conversation

elinor-fung
Copy link
Member

@elinor-fung elinor-fung commented May 7, 2024

  • Read/store types from contract descriptor into an internal representation of the type layout info
  • Add functions to Target for getting type info and contract version
  • Add placeholder for thread contract and getting thread store data
    • Add ThreadStore to data descriptor
    • GetThreadStoreData continues to return E_NOTIMPL, but will go through trying to use the contract
  • Store processed data for the target by its address and data model type
  • Add unit tests for getting type info

Contributes to #99298

@dotnet-issue-labeler dotnet-issue-labeler bot added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label May 7, 2024
@elinor-fung elinor-fung added area-Diagnostics-coreclr and removed needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners labels May 7, 2024
Copy link
Contributor

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

Copy link
Member

@lambdageek lambdageek left a comment

Choose a reason for hiding this comment

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

Seems ok to me

I think there's a good balance between ceremony and separation of concerns, but if we're wrong, we can adjust once we have some contracts with non-trivial interactions.

@lambdageek
Copy link
Member

Store processed data for the target by its address - assumes each address will only be processed as one type of data

thinking about Mono, we have some places where we lean on type punning kind of heavily. For example our intrusive JIT info hashes that are treated kind of abstractly by the unwinder but concretely by the execution engines (ie the JIT and interp keep their own data past the hash key/bucket link) and rely on the first member of a struct being at the same address as the whole struct. So different contracts might want to view the same address differently. But we may want to adjust the representation to be contract-friendly, instead.


IContract contract = T.Create(_target);

// Still okay if contract was already registered by someone else
Copy link
Member

Choose a reason for hiding this comment

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

Why is this okay? Does the contract not really matter in this case? The below logic means we could fail to add the contract because one already exists, and then return the one we just created. This seems like we could get into a state where an implementation has state and isn't the one being used. I think we need some other invariant in the system if this pattern is considered safe.

Copy link
Member Author

Choose a reason for hiding this comment

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

Agreed, this should return the existing one if it got registered in between. I don't think the contracts should really have state other than what is tied to the target itself.

Copy link
Member

@lambdageek lambdageek May 9, 2024

Choose a reason for hiding this comment

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

I don't think the contracts should really have state other than what is tied to the target itself.

I kind of want contract implementations to be valuetypes. That way it's evident they have no identity. Not sure if that's going overboard, though

Copy link
Member

Choose a reason for hiding this comment

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

That way it's evident they have no identity. Not sure if that's going overboard, though

That is the kind of architecture invariant that would work for me. It isn't a compile time enforcement, but does make people ask the right question. The counter to that though then becomes, why do we have a cache if none of the objects have state? Will the constructor have a lot of logic to set itself up?

Copy link
Member

@lambdageek lambdageek May 9, 2024

Choose a reason for hiding this comment

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

Will the constructor have a lot of logic to set itself up?

My feeling is, yes. (well not literally the constructor, but the Create static virtual method). In the C++ prototype there was a lot of work upfront to query the target and establish that the necessary data was available. I think something similar is already evident in the Thread contract, too

Copy link
Member Author

Choose a reason for hiding this comment

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

1ad1da3 turns Thread into a readonly struct - thoughts? I didn't want the additional interface originally, but after actually doing it, it doesn't seem like too much.

Copy link
Member

Choose a reason for hiding this comment

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

thoughts?

I like it, but I will also readily acknowledge we landed in a very non-idiomatic way of programming C#. But maybe with static virtuals and DIMs this is what programming with immutable values looks like in C# now?

src/native/managed/cdacreader/src/Target.cs Show resolved Hide resolved
src/native/managed/cdacreader/src/Target.cs Outdated Show resolved Hide resolved
@lambdageek
Copy link
Member

rely on the first member of a struct being at the same address as the whole struct.

Thinking about it a little bit more, this will be true for all structs whether or not one happens to rely on it. So any C/C++ struct or class whose first member also happens to be a struct or class will have at least 2 different views of the same address. (I don't think we will want to completely flatten the data layout of every class)

@elinor-fung
Copy link
Member Author

Ah, indeed. I'll switch it to be by address+type. I'm keeping it on the target, as I think we do want the cache per target rather than more contract-based / per contract.

@elinor-fung elinor-fung merged commit 4b8fcd5 into dotnet:main May 13, 2024
150 checks passed
@elinor-fung elinor-fung deleted the cdac-read-types branch May 13, 2024 22:12
Ruihan-Yin pushed a commit to Ruihan-Yin/runtime that referenced this pull request May 30, 2024
- Read/store types from contract descriptor into an internal representation of the type layout info
- Add functions to `Target` for getting type info and contract version
- Add placeholder for thread contract and getting thread store data
  - Add ThreadStore to data descriptor
  - `GetThreadStoreData` continues to return E_NOTIMPL, but will go through trying to use the contract
- Store processed data for the target by its address and data model type
- Add unit tests for getting type info
@github-actions github-actions bot locked and limited conversation to collaborators Jun 14, 2024
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.

4 participants