Skip to content

Conversation

@janvorli
Copy link
Member

@janvorli janvorli commented Jun 15, 2020

This change adds support to DAC for getting AssemblyLoadContext
for a MethodTable. The returned AsseblyLoadContext is the context
into which the related type was loaded.

@janvorli janvorli added this to the 5.0 milestone Jun 15, 2020
@janvorli janvorli requested review from hoyosjs, jkotas and mikem8361 June 15, 2020 12:53
@janvorli janvorli self-assigned this Jun 15, 2020
@ghost
Copy link

ghost commented Jun 15, 2020

Tagging subscribers to this area: @tommcdon
Notify danmosemsft if you want to be subscribed.

Copy link
Member

Choose a reason for hiding this comment

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

FYI @davmason is adding this in #37853 as well.

Copy link
Member

Choose a reason for hiding this comment

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

Where do you get the address of the loader allocator or the binder from? Do we also need APIs to e.g. get loader allocator from MethodTable or MethodDesc?

Copy link
Member Author

Choose a reason for hiding this comment

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

We already have that, I have added that quite some time ago.

interface ISOSDacInterface6 : IUnknown
{
    HRESULT GetMethodTableCollectibleData(CLRDATA_ADDRESS mt, struct DacpMethodTableCollectibleData *data);
};

I also have the SOS change tested and ready to get in.

Copy link
Member

Choose a reason for hiding this comment

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

GetMethodTableCollectibleData returns LoaderAllocatorObjectHandle. How do you get from LoaderAllocatorObjectHandle to loaderAllocator ?

SOS change

It may be useful to add link to the SOS change for context.

Copy link
Member Author

Choose a reason for hiding this comment

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

See #11157 (comment) for the steps to get from an object to the AssemblyLoadContext. There were two steps that couldn't be done via DAC before, those are the ones I'm adding here.

As for the SOS change, I was planning to create the PR after this one gets in.

Copy link
Contributor

Choose a reason for hiding this comment

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

You may want to write some of the SOS code to test these new DAC APIs to test the binder code added to the DAC has been properly "DACized" (dac_cast macros, etc).

@janvorli
Copy link
Member Author

Hmm, it seems that all Linux builds are broken due to a missing header. I am looking into it.

Copy link
Member

Choose a reason for hiding this comment

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

Use more self-describing name, e.g. OwningAssemblyLoadContext ?

@jkotas jkotas requested review from davmason and leculver June 15, 2020 16:59
@jkotas
Copy link
Member

jkotas commented Jun 15, 2020

It looks good to me otherwise. I would like to see somebody from the diagnostic team to signoff on this as well.

@tommcdon
Copy link
Member

It looks good to me otherwise. I would like to see somebody from the diagnostic team to signoff on this as well.

@mikem8361 @sdmaclea can you take a look?

Copy link
Contributor

Choose a reason for hiding this comment

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

You may want to write some of the SOS code to test these new DAC APIs to test the binder code added to the DAC has been properly "DACized" (dac_cast macros, etc).

@janvorli
Copy link
Member Author

I am going to redo this change to add just one new method to get pointer to managed AssemblyLoadContext for a given MethodTable. The current way worked only for collectible AssemblyLoadContext and I have realized that I can make it work for both collectible and non-collectible.
My original change was trying to expose separate data structures for a subset of members of specific native structures (subset == 1 field in this case) and use it as two of multiple steps in SOS to get to the AssemblyLoadContext. But it seems that the ISOSDacInterface methods don't follow such philosophy in general, so I can just expose a method that internally does those steps on the DAC side (basically a simple pointer chain walk) and returns just the resulting AssemblyLoadContext)

@janvorli
Copy link
Member Author

@jkotas, @mikem8361 can you please take a look again? I've made substantial changes to you'll probably want to review it from scratch. I've redone the implementation to support
dumping AssemblyLoadContext even for the cases when it is the default one or a non-collectible one. I have realized that the previous way of exposing some partial data structures is not going to work well here. So I've done it differently by adding a higher level DAC method to get AssemblyLoadContext for a MethodTable and implement all the steps needed to get from MethodTable to the ALC there. The need to access other data structures to be able to get ALC for
non-collectible types turned out into a DACization waterfall and I even had to add special handling for classes in namespaces that the DAC would not be able to handle and even update the DacTableGen to support that (symbols of classes inside namespaces are mangled in a special way).

@janvorli
Copy link
Member Author

@jkotas as for the new interface being created here and in @davmason's change, I suppose we will want to create two new versions, otherwise we would need to merge out changes into one, right?

@jkotas
Copy link
Member

jkotas commented Jun 17, 2020

create two new version

I do not think that's required as long as we ship both changes in the same release cycle.

@janvorli
Copy link
Member Author

I can see that the Unix build is broken for the DAC build, I need to investigate it.

@davmason
Copy link
Contributor

create two new version

I do not think that's required as long as we ship both changes in the same release cycle.

Right, as long as it's the same release we can change the interfaces.

@janvorli it should be fairly easy to merge, whoever merges last can just add their methods to the existing interface in sospriv.idl and then regenerate sospriv.h and make sure the guid definition is right in sospriv_i.cpp. There shouldn't be any other work.

Copy link
Member

Choose a reason for hiding this comment

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

This has a lot of non-DACized pointers. It is hard to see that none of them will get used by the DAC.

Copy link
Member Author

Choose a reason for hiding this comment

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

I have DACized only the ones that are needed for getting the ALC. It was painful enough that way.

Copy link
Member

Choose a reason for hiding this comment

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

I understand that it was painful. It is hard to see that it is correct. We prefer the type members to be fully DACized. Partially DACized types are bug farms.

Copy link
Contributor

@mikem8361 mikem8361 left a comment

Choose a reason for hiding this comment

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

I do like this approach better.

Copy link
Contributor

Choose a reason for hiding this comment

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

Did you intentionally leave this commented out?

Copy link
Member Author

Choose a reason for hiding this comment

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

I should have removed that, I have missed it when looking through the code before commit.

Copy link
Member

@jkotas jkotas Jun 17, 2020

Choose a reason for hiding this comment

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

Would it be better to store the PTR_AssemblyLoadContext in the PEFile and the object handle in AssemblyLoadContext base class to avoid DACizing the whole binder machinery?

Copy link
Member

Choose a reason for hiding this comment

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

I am worried that we will keep finding holes in the binder DACization.

Copy link
Member Author

Choose a reason for hiding this comment

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

Would it be better to store the PTR_AssemblyLoadContext in the PEFile and the object handle in AssemblyLoadContext base class to avoid DACizing the whole binder machinery?

I will try to do it that way.

Copy link
Member

Choose a reason for hiding this comment

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

TO_TADDR [](start = 42, length = 8)

Can you please change this to CLRDATA_ADDRESS_TO_TADDR

Copy link
Member Author

Choose a reason for hiding this comment

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

Sure. Btw, I am redoing it based on @jkotas feedback to simplify things considerably, so please wait with reviewing a bit.

@janvorli janvorli force-pushed the add-dac-get-alc-from-obj branch from 7e2d6e3 to 2acb8c0 Compare June 18, 2020 12:51
This change adds support to DAC for getting AssemblyLoadContext
for a MethodTable. The returned AsseblyLoadContext is the context
into which the related type was loaded.
@janvorli janvorli force-pushed the add-dac-get-alc-from-obj branch from 2acb8c0 to 0a3bfe2 Compare June 18, 2020 13:51
@janvorli
Copy link
Member Author

@jkotas I have updated the PR based on your suggestion of storing the AssemblyLoadContext in the PEFile. It worked quite well, the only little ugly thing being the need to set the ALC for the S.P.C. separately, as the PEFile (PEAssembly) for it is created during the ICLRRuntimeHost4::Start, but the related ALC much later during ICLRRuntimeHost4::CreateAppDomainWithManager.

#endif
}

#ifndef DACCESS_COMPILE
Copy link
Member

Choose a reason for hiding this comment

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

The whole function is !DACCESS_COMPILE. This ifdef should not be needed.

Copy link
Member Author

Choose a reason for hiding this comment

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

Strange, I have thought I have removed it already.

// Initialize the assembly binder for the default context loads for CoreCLR.
IfFailThrow(CCoreCLRBinderHelper::DefaultBinderSetupContext(DefaultADID, &m_pTPABinderContext));

SystemDomain::SystemFile()->SetAssemblyLoadContext(m_pTPABinderContext);
Copy link
Member

Choose a reason for hiding this comment

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

Why do we need to set it explicitly? I would expect the constructor to set it for corelib 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.

I've mentioned it in my comment above. the PEFile (PEAssembly) for it is created during the ICLRRuntimeHost4::Start, but the related ALC much later during ICLRRuntimeHost4::CreateAppDomainWithManager.

Copy link
Member

Choose a reason for hiding this comment

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

Maybe useful to add comment.

@janvorli
Copy link
Member Author

There are two tests failing.

  • System.Runtime.Loader.Tests.RefEmitLoadContextTests.LoadRefEmitAssembly
  • System.Runtime.Loader.RefEmitLoadContext.Tests

It seems there is one more way how the AssemblyLoadContext would change after the PEFile creation. In Assembly::CreateDynamic, there is a call pFile->SetFallbackLoadContextBinder(pFallbackLoadContextBinder); and the m_pFallbackContext is used in the AssemblyLoadContext computation. I guess that's causing those two tests to fail. They check for AssemblyLoadContext type and get the default one instead of a specific one.

GetILimage()->GetLayout(PEImageLayout::LAYOUT_ANY,PEImage::LAYOUT_CREATEIFNEEDED)->Release();
}

AssemblyLoadContext* PEFile::LookupAssemblyLoadContext()
Copy link
Member

Choose a reason for hiding this comment

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

SetAssemblyLoadContext + LookupAssemblyLoadContext can be merged into a single method like void SetupAssemblyLoadContext() that computes it from the other PEFile state and sets it.

@janvorli janvorli merged commit 2ddca66 into dotnet:master Jun 19, 2020
@ghost ghost locked as resolved and limited conversation to collaborators Dec 8, 2020
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.

6 participants