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

CoreRT support #4

Open
mjsabby opened this issue Jul 5, 2019 · 3 comments
Open

CoreRT support #4

mjsabby opened this issue Jul 5, 2019 · 3 comments

Comments

@mjsabby
Copy link
Contributor

mjsabby commented Jul 5, 2019

Part of the work is exposing the helpers from S.P.C so our serialized can call it.
dotnet/corert#7589

The other part is actually understanding how to go from an EEType* to GCDesc when deserializing. And for serializing hoping and praying that the layout algorithm is the same so that the serializer can run on .NET Core and deserialize on CoreRT when doing it on the same OS and architecture.

@mjsabby
Copy link
Contributor Author

mjsabby commented Jul 5, 2019

The flag to check if an EEType (CoreRT) contains pointers is 0x0020. The flag to check if a MethodTable (CoreCLR) has pointers is 0x0100. This is annoying because now I have to have a forked code path for CoreRT.

I wonder why this was done ...

@mjsabby
Copy link
Contributor Author

mjsabby commented Jul 5, 2019

CoreRT Code Path:

            while (objectId < buffer + length)
            {
                var typeHandle = runtimeTypeHandles[(int)Marshal.ReadIntPtr((IntPtr)objectId)].Value;
                var eetype = (EEType*)typeHandle;

                var objectSize = eetype->BaseSize;
                var numComponents = Marshal.ReadInt32((IntPtr)objectId, IntPtr.Size);
                objectSize += numComponents * eetype->ComponentSize;

                bool containsPointers = (eetype->Flags & 0x0020) == 0x0020;
                if (containsPointers)
                {
                    var entries = *(int*)((byte*)eetype - IntPtr.Size);
                    if (entries < 0)
                    {
                        entries -= entries;
                    }

                    var slots = 1 + entries * 2;

                    var gcdesc = new GCDesc(buffer, (byte*)eetype - (slots * IntPtr.Size), slots * IntPtr.Size);

                    if (IntPtr.Size == 8)
                    {
                        gcdesc.FixupObject64(objectId, objectSize);
                    }
                    else
                    {
                        gcdesc.FixupObject32(objectId, objectSize);
                    }
                }

                Marshal.WriteIntPtr((IntPtr)objectId, (IntPtr)eetype);
                objectId += objectSize + Padding(objectSize, IntPtr.Size);
            }

CoreCLR code path:

            while (objectId < buffer + length)
            {
                var typeHandle = runtimeTypeHandles[(int)Marshal.ReadIntPtr((IntPtr)objectId)].Value;
                bool isArray = (typeHandle.ToInt64() & 0x2) == 0x2;

                var mt = (MethodTable*)typeHandle;
                if (isArray)
                {
                    mt = (MethodTable*)Marshal.ReadIntPtr(typeHandle, 6);
                }

                var objectSize = mt->BaseSize;
                var flags = mt->Flags;
                bool hasComponentSize = (flags & 0x80000000) == 0x80000000;

                if (hasComponentSize)
                {
                    var numComponents = Marshal.ReadInt32((IntPtr)objectId, IntPtr.Size);
                    objectSize += numComponents * mt->ComponentSize;
                }

                bool containsPointerOrCollectible = (flags & 0x10000000) == 0x10000000 || (flags & 0x1000000) == 0x1000000;
                if (containsPointerOrCollectible)
                {
                    var entries = *(int*)((byte*)mt - IntPtr.Size);
                    if (entries < 0)
                    {
                        entries -= entries;
                    }

                    var slots = 1 + entries * 2;

                    var gcdesc = new GCDesc(buffer, (byte*)mt - (slots * IntPtr.Size), slots * IntPtr.Size);

                    if (IntPtr.Size == 8)
                    {
                        gcdesc.FixupObject64(objectId, objectSize);
                    }
                    else
                    {
                        gcdesc.FixupObject32(objectId, objectSize);
                    }
                }

                Marshal.WriteIntPtr((IntPtr)objectId, (IntPtr)mt);
                objectId += objectSize + Padding(objectSize, IntPtr.Size);
            }

Notice that in the CoreCLR path I have to first check if it is an array, and switch from TypeDesc to MT. Then the containsPointerOrCollectible check is different.

Unrelated note: I'm also checking hasComponentSize, which I don't think I need to since in places in CoreCLR I've seen a blind read of numComponents even if it is not an array or string because it gets multiplied by componentSize. I guess the question is, the check is helping or not?

@mjsabby
Copy link
Contributor Author

mjsabby commented Jul 5, 2019

After bringing this up with @MichalStrehovsky & @jkotas I will fork the code paths for CoreRT as we don't want to modify the EEType bits to conform to the CoreCLR MT.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant