Skip to content
This repository has been archived by the owner on Nov 1, 2020. It is now read-only.

implemented portable PInvoke infrastructure for CppCodeGen #4503

Merged
merged 1 commit into from
Sep 15, 2017

Conversation

hippiehunter
Copy link
Contributor

No description provided.

@dnfclas
Copy link

dnfclas commented Sep 15, 2017

@hippiehunter,
Thanks for having already signed the Contribution License Agreement. Your agreement was validated by .NET Foundation. We will now review your pull request.
Thanks,
.NET Foundation Pull Request Bot

COOP_PINVOKE_HELPER(void, RhpPInvoke2, (PInvokeTransitionFrame* pFrame))
{
Thread * pCurThread = ThreadStore::RawGetCurrentThread();
pCurThread->InlinePInvoke(pFrame);
Copy link
Member

Choose a reason for hiding this comment

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

Nit: Indentation

@@ -1158,6 +1158,31 @@ FORCEINLINE void Thread::InlineReversePInvokeReturn(ReversePInvokeFrame * pFrame
}
}

FORCEINLINE void Thread::InlinePInvoke(PInvokeTransitionFrame * pFrame)
{
pFrame->m_pThread = this;
Copy link
Member

Choose a reason for hiding this comment

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

Nit: indentation


FORCEINLINE void Thread::InlinePInvokeReturn(PInvokeTransitionFrame * pFrame)
{
m_pTransitionFrame = NULL;
Copy link
Member

Choose a reason for hiding this comment

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

Nit: indentation

@@ -255,6 +255,9 @@ class Thread : private ThreadBuffer
bool InlineTryFastReversePInvoke(ReversePInvokeFrame * pFrame);
void InlineReversePInvokeReturn(ReversePInvokeFrame * pFrame);

void InlinePInvoke(PInvokeTransitionFrame * pFrame);
Copy link
Member

Choose a reason for hiding this comment

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

Nit: Indentiation

@@ -1287,4 +1312,16 @@ COOP_PINVOKE_HELPER(void, RhpReversePInvokeReturn2, (ReversePInvokeFrame * pFram
pFrame->m_savedThread->InlineReversePInvokeReturn(pFrame);
}

COOP_PINVOKE_HELPER(void, RhpPInvoke2, (PInvokeTransitionFrame* pFrame))
Copy link
Member

Choose a reason for hiding this comment

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

RhpPInvoke2/RhpPInvokeReturn2 should be under #ifdef USE_PORTABLE_HELPERS here. It does not make sense otherwise.

@@ -41,4 +41,33 @@ inline double __uint64_to_double(uint64_t v)
return val.d;
}

#endif // __CPP_CODE_GEN_H
#ifdef USE_PORTABLE_HELPERS
Copy link
Member

Choose a reason for hiding this comment

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

I meant this ifdef to be in rhbinder.h. This file is only used when USE_PORTABLE_HELPERS is defined, so the ifdef does not need to be here.

#ifdef _TARGET_ARM_
TgtPTR_Void m_ChainPointer; // R11, used by OS to walk stack quickly
#endif
TgtPTR_Void m_RIP;
Copy link
Member

Choose a reason for hiding this comment

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

What is the minimal struct PInvokeTransitionFrame that we can get away for USE_PORTABLE_HELPERS ? Ideally, it would have just m_pThread and nothing else.

if (method.IsRawPInvoke())
{
AppendLine();
Append("PInvokeTransitionFrame __piframe");
Copy link
Member

Choose a reason for hiding this comment

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

This assumes that there will be at most one RawPInvoke callsite per method. It is a safe assumption to make today, but it maybe worth a comment.

@@ -41,4 +41,33 @@ inline double __uint64_to_double(uint64_t v)
return val.d;
}
Copy link
Member

Choose a reason for hiding this comment

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

You can move ReversePInvokeFrame from common.h here as well while you are on it.

Copy link
Member

Choose a reason for hiding this comment

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

(Most of the CppCodeGen specific stuff should really be in this file actually and not in common.h.)

@hippiehunter
Copy link
Contributor Author

It appears that StackFrameIterator.cpp depends on most of the fields in PInvokeTransitionFrame. I guess that brings me to my next question, what is the way forward on enabling the stack walker here? Is it as simple as filling out the values of the transition frame when we pinvoke?

@jkotas
Copy link
Member

jkotas commented Sep 15, 2017

The stackwalker will need significant overhaul for CppCodeGen. It maybe useful to mention it in a comment in the portable version of PInvokeTransitionFrame.

Stackwalker is used for several purposes today:

  • Exception handling ([CppCodeGen] Managed Exception Dispatch and Unwind #910): Each thread needs to maintain linked list of exception handlers. Every method with exception handling needs to push/pop frame into the linked list. The linked list is necessary to support .NET two phase exception handling (exception filters). The actual unwinding can be then done by throwing C++ exception.

  • Textual stacktrace generation (e.g. stacktrace for exceptions, or Environment.StackTrace): This is extreme case of the above. Each method would need to push/pop frame into the linked list. It is very expensive to do. It may be optional feature - it is how Unity IL2CPP does it (https://blogs.unity3d.com/2015/05/13/il2cpp-internals-a-tour-of-generated-code/).

  • Root enumeration for Garbage collection ([CppCodeGen] Enable conservative GC #2033): The standard way to do garbage collection for C++ is to do conservative scanning of all potential pointers on the stack. There is a small trick to it: It is necessary to ensure that pointers in registers are spilled into into memory. The best way to do that is using __builtin_unwind_init when it is available - it will need to be added to the PInvoke GC transitions. Alternative design is for the linked list of frame records to contain pointers to all GC roots. It makes the generated harder to read and less efficient (all GC pointers have to be spilled into this structure, they cannot be kept in registers). On the other hand, GC has less work to do because of the list of stack roots can be precise.

pFrame->m_pThread->InlinePInvokeReturn(pFrame);
}

#endif
Copy link
Member

Choose a reason for hiding this comment

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

Nit: We typically have the name of the ifdef as comment on #endif.

@@ -646,6 +657,7 @@ struct PInvokeTransitionFrame
#endif
UIntTarget m_PreservedRegs[];
};
#endif
Copy link
Member

Choose a reason for hiding this comment

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

Same here

@hippiehunter
Copy link
Contributor Author

updated for comments

Copy link
Member

@jkotas jkotas left a comment

Choose a reason for hiding this comment

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

Thanks!

@jkotas jkotas merged commit 3a1a99a into dotnet:master Sep 15, 2017
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.

3 participants