Enable Invoke and GetValue for ref-returning members #17639
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -41,7 +41,7 @@ internal INVOCATION_FLAGS InvocationFlags | |
// | ||
// first take care of all the NO_INVOKE cases. | ||
if (ContainsGenericParameters || | ||
ReturnType.IsByRef || | ||
(ReturnType.IsByRef && ReturnType.GetElementType().IsByRefLike) || | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Update the message that will be thrown for this case in ThrowNoInvokeException ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed. |
||
(declaringType != null && declaringType.ContainsGenericParameters) || | ||
((CallingConvention & CallingConventions.VarArgs) == CallingConventions.VarArgs)) | ||
{ | ||
|
@@ -443,10 +443,10 @@ private void ThrowNoInvokeException() | |
{ | ||
throw new MemberAccessException(); | ||
} | ||
// ByRef return are not allowed in reflection | ||
else if (ReturnType.IsByRef) | ||
// ByRef to ByRefLike returns are not allowed in reflection | ||
else if (ReturnType.IsByRef && ReturnType.GetElementType().IsByRefLike) | ||
{ | ||
throw new NotSupportedException(SR.NotSupported_ByRefReturn); | ||
throw new NotSupportedException(SR.NotSupported_ByRefToByRefLikeReturn); | ||
} | ||
|
||
throw new TargetException(); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -649,9 +649,14 @@ void InvokeUtil::ValidField(TypeHandle th, OBJECTREF* value) | |
COMPlusThrow(kArgumentException,W("Arg_ObjObj")); | ||
} | ||
|
||
// InternalCreateObject | ||
// This routine will create the specified object from the value | ||
OBJECTREF InvokeUtil::CreateObject(TypeHandle th, void * pValue) { | ||
// | ||
// CreateObjectAfterInvoke | ||
// This routine will create the specified object from the value returned by the Invoke target. | ||
// | ||
// This does not handle the ELEMENT_TYPE_VALUETYPE case. The caller must preallocate the box object and | ||
// copy the value type into it afterward. | ||
// | ||
OBJECTREF InvokeUtil::CreateObjectAfterInvoke(TypeHandle th, void * pValue) { | ||
CONTRACTL { | ||
THROWS; | ||
GC_TRIGGERS; | ||
|
@@ -666,6 +671,9 @@ OBJECTREF InvokeUtil::CreateObject(TypeHandle th, void * pValue) { | |
MethodTable *pMT = NULL; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The bug that broke corefx is when these two differ. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, it broke enums. I'm thinking we should just strip |
||
OBJECTREF obj = NULL; | ||
|
||
// WARNING: pValue can be an inner reference into a managed object and it is not protected from GC. You must do nothing that | ||
// triggers a GC until the all the data it points to has been captured in a GC-protected location. | ||
|
||
// Handle the non-table types | ||
switch (type) { | ||
case ELEMENT_TYPE_VOID: | ||
|
@@ -682,12 +690,8 @@ OBJECTREF InvokeUtil::CreateObject(TypeHandle th, void * pValue) { | |
goto PrimitiveType; | ||
|
||
case ELEMENT_TYPE_VALUETYPE: | ||
{ | ||
_ASSERTE(!th.IsTypeDesc()); | ||
pMT = th.AsMethodTable(); | ||
obj = pMT->Box(pValue); | ||
_ASSERTE(!"You cannot use this function for arbitrary value types. You must preallocate a box object and copy the value in yourself."); | ||
break; | ||
} | ||
|
||
case ELEMENT_TYPE_CLASS: // Class | ||
case ELEMENT_TYPE_SZARRAY: // Single Dim, Zero | ||
|
@@ -718,14 +722,17 @@ OBJECTREF InvokeUtil::CreateObject(TypeHandle th, void * pValue) { | |
{ | ||
// Don't use MethodTable::Box here for perf reasons | ||
PREFIX_ASSUME(pMT != NULL); | ||
obj = AllocateObject(pMT); | ||
DWORD size = pMT->GetNumInstanceFieldBytes(); | ||
memcpyNoGCRefs(obj->UnBox(), pValue, size); | ||
|
||
UINT64 capturedValue; | ||
memcpyNoGCRefs(&capturedValue, pValue, size); // Must capture the primitive value before we allocate the boxed object which can trigger a GC. | ||
|
||
INDEBUG(pValue = (LPVOID)0xcccccccc); // We're about to allocate a GC object - can no longer trust pValue | ||
obj = AllocateObject(pMT); | ||
memcpyNoGCRefs(obj->UnBox(), &capturedValue, size); | ||
} | ||
break; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
case ELEMENT_TYPE_BYREF: | ||
COMPlusThrow(kNotSupportedException, W("NotSupported_ByRefReturn")); | ||
case ELEMENT_TYPE_END: | ||
default: | ||
_ASSERTE(!"Unknown Type"); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need
IsByRefLike
condition here as well? Or are the ByRefLike returns handled somewhere else?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That gets handled in the "else" branch (
RuntimeMethodHandle.GetSecurityFlags(this);
)