Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.

Delete RETURNTYPE and change how we get ReturnKind for gccover. #24600

Merged
merged 11 commits into from May 24, 2019

Conversation

sandreenko
Copy link

@sandreenko sandreenko commented May 16, 2019

There are several places where we need to know the return type for a call:

  1. HijackFrame::GcScanRoots, it uses vm\threadsuspend.cpp::GetReturnKind that gets correct kind it from EECodeInfo that points to a compiled method (it can't be a prestub), so code in HijackFrame::GcScanRoots is our role model:
    void HijackFrame::GcScanRoots(promote_func *fn, ScanContext* sc)

question: can hijacking happen when we are in a compile stub and EECodeInfo is invalid?

  1. GcCover.cpp needs to know when to protect call return values when imitating Hijacking, but it doesn't have EECodeInfo (because most MethodDescriptor point to uncompiled code and PCODEs point to compile stubs, so we can't get EECodeInfo->gcInfoToken), so we have to restore ReturnKind from method descriptor. This PR changes MethodDesc::ReturnsObject to return precise information using code that was in ReturnKind GetReturnKindFromMethodTable(Thread *pThread, EECodeInfo *codeInfo) as example.
    Using this ReturnKind we can correctly understand when we need to protect first/second/both return registers on x64 Unix/arm64 and, for example, do not use INTERRUPT_INSTR_PROTECT_RET in tricky cases.

However, ReturnKind GetReturnKindFromMethodTable supports only x64 Unix and doesn't support arm64. So if we call it on arm64 with a method that return 16 bytes struct it fails with assert:

coreclr/src/vm/method.cpp

Lines 1266 to 1278 in 221dc73

#ifdef UNIX_AMD64_ABI
if (pReturnTypeMT->IsRegPassedStruct())
{
return MetaSig::RETVALUETYPE;
}
#endif // !UNIX_AMD64_ABI
if (pReturnTypeMT->ContainsPointers())
{
_ASSERTE(pReturnTypeMT->GetNumInstanceFieldBytes() == sizeof(void*));
return MetaSig::RETOBJ;
}
}

and there is comment:

// The Multi-reg return case using the classhandle is only implemented for AMD64 SystemV ABI.
// On other platforms, multi-reg return is not supported with GcInfo v1.
// So, the relevant information must be obtained from the GcInfo tables (which requires version2).

that says that it is not a simple restriction.

question: how can we get the necessary information for arm64?

  1. ComPlusMethodFrame::GcScanRoots needs to know which registers to protect but has the same issues as GCCoder, but this method is not stress testing specific, so I assume it can cause gc holes in a real app that uses COM methods that return struct on arm64 Windows (we can't have COM on Unix).

question: What should we do in this case?

This PR is preparation for https://github.com/dotnet/coreclr/issues/23199. With that change, I have correct kind in GCCover and can use different instruction to mark which registers I need to restore.

Changes by commits:
0af5c96: Move GetReturnKindFromMethodTable to method.hpp.

We would need this in other places in the next commits.

2b0b08d: Delete unnecessary checks from callhelpers.

56e4ad8: Do not check return types in CanDeduplicateCode.

GC info v.2 has this information and it is checked in another place.

f96c1a0: Change ComPlusMethodFrame to use the new function.

92708d4: Change gccover.cpp to use GetReturnKindFromMethodTable.

6930780: Delete RETURNTYPE.

fcb3ee4: Add check to ComPlusMethodFrame.

2e6011d: Delete check from threadsuspend.

codeInfo->GetCodeManager()->GetReturnKind(gcInfoToken) must always return a valid kind nowdays (it could return an invalid lind only when GC Info v2 was not available).

@sandreenko sandreenko added the * NO MERGE * The PR is not ready for merge yet (see discussion for detailed reasons) label May 16, 2019
src/vm/callhelpers.h Outdated Show resolved Hide resolved
src/vm/clrtocomcall.cpp Outdated Show resolved Hide resolved
Sergey Andreenko added 4 commits May 20, 2019 16:04
codeInfo->GetCodeManager()->GetReturnKind(gcInfoToken) must always return a valid kind nowdays (it could return an invalid lind only when GC Info v2 was not available).
@sandreenko sandreenko changed the title [WIP] Delete returntype Delete RETURNTYPE and change how we get ReturnKind for gccover. May 22, 2019
@sandreenko sandreenko removed the * NO MERGE * The PR is not ready for merge yet (see discussion for detailed reasons) label May 22, 2019
@sandreenko sandreenko marked this pull request as ready for review May 22, 2019 22:12
@sandreenko
Copy link
Author

PTAL @jkotas @BruceForstall @dotnet/jit-contrib

src/vm/method.cpp Outdated Show resolved Hide resolved
src/vm/method.cpp Outdated Show resolved Hide resolved
src/vm/method.cpp Outdated Show resolved Hide resolved
@jkotas
Copy link
Member

jkotas commented May 22, 2019

Are all the questions in your PR description addressed, or do you still need answers to some of them?

Copy link
Member

@BruceForstall BruceForstall left a comment

Choose a reason for hiding this comment

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

LGTM after addressing @jkotas comments, plus minor questions/nits.

src/inc/gcinfotypes.h Outdated Show resolved Hide resolved
src/vm/compile.cpp Show resolved Hide resolved
@sandreenko
Copy link
Author

Are all the questions in your PR description addressed, or do you still need answers to some of them?

I am not sure about these two:

question: can hijacking happen when we are in a compile stub and EECodeInfo is invalid?
My understanding is not, it can't, but I have not found how it is guaranteed.

ComPlusMethodFrame::GcScanRoots: What should we do in this case?
I have found an example where we use COM method that returns struct, but it did not have two pointers.
I will try to write my own test case to expose this issue, I still do not know how to fix it if I expose the issue.

@jkotas
Copy link
Member

jkotas commented May 22, 2019

can hijacking happen when we are in a compile stub and EECodeInfo is invalid?

It cannot happen. Hijacking is only done for JITed/R2R code.

ComPlusMethodFrame::GcScanRoots:

ComPlusMethodFrame is only used for a few special cases, like COM events. These special cases cannot return structs.

@sandreenko
Copy link
Author

ComPlusMethodFrame is only used for a few special cases, like COM events. These special cases cannot return structs.

Interop\COM\NETClients\IDispatch\NETClientIDispatch has a test that returns struct from COM method frame (its signature is instance valuetype Server.Contract.HFA_4 Server.Contract.IDispatchTesting::DoubleHVAValues(valuetype Server.Contract.HFA_4&)), we call it here:

Console.WriteLine($"IDispatch with structs not supported...");
var dispatchTesting = (DispatchTesting)new DispatchTestingClass();
var input = new HFA_4() { x = 1f, y = 2f, z = 3f, w = 4f };
Assert.Throws<NotSupportedException>(() => dispatchTesting.DoubleHVAValues(ref input));
}

but because this struct doesn't have pointer fields we do not need to report it and return just RT_Scalar.

Thanks for the explanation, now I am sure that the current variant is safe and if in the future somebody adds a case with return RT_*_Obj they will see the new assert.

@sandreenko sandreenko merged commit d5d1889 into dotnet:master May 24, 2019
@sandreenko sandreenko deleted the DeleteRETURNTYPE branch June 6, 2019 18:56
picenka21 pushed a commit to picenka21/runtime that referenced this pull request Feb 18, 2022
…et/coreclr#24600)

* Move GetReturnKindFromMethodTable to method.hpp.

We would need this in other places in the next commits.

* Delete unnecessary checks from callhelpers.

* Do not check return types in CanDeduplicateCode.

GC info v.2 has this information and it is checked in another place.

* Change ComPlusMethodFrame to use the new function.

* Change gccover.cpp to use GetReturnKindFromMethodTable.

* Delete RETURNTYPE.

* Add check to ComPlusMethodFrame.

* Delete check from threadsuspend.

codeInfo->GetCodeManager()->GetReturnKind(gcInfoToken) must always return a valid kind nowdays (it could return an invalid lind only when GC Info v2 was not available).

* Rename functions/arguments.

* Add check for IsValidReturnKind.

* delete unused var.


Commit migrated from dotnet/coreclr@d5d1889
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
3 participants