* Cleanup changes from #21793.
* Emit the data pointer offset directly into the IL stream (and calculate it as needed instead of passing it through)
* Fix broken assumption that OverrideProcArgs::na::m_pMT is the array type instead of the element type (which it was).
// the other. Since there is no enforcement of this, apps blithely depend
// on it.
//
-
- // The base offset should only be 0 for System.Array parameters for which
- // OleVariant::GetMarshalerForVarType(vt) should never return NULL.
- _ASSERTE(m_pargs->na.m_optionalbaseoffset != 0);
EmitSetupSigAndDefaultHomesCLRToNative();
EmitStoreNativeValue(m_pcsMarshal);
EmitLoadManagedValue(m_pcsMarshal);
- m_pcsMarshal->EmitBRFALSE(pNullRefLabel);
-
+ m_pcsMarshal->EmitBRFALSE(pNullRefLabel);
+
+ // COMPAT: We cannot generate the same code that the C# compiler generates for
+ // a fixed() statement on an array since we need to provide a non-null value
+ // for a 0-length array. For compat reasons, we need to preserve old behavior.
+ // Additionally, we need to ensure that we do not pass non-null for a zero-length
+ // array when interacting with GDI/GDI+ since they fail on null arrays but succeed
+ // on 0-length arrays.
EmitLoadManagedValue(m_pcsMarshal);
m_pcsMarshal->EmitSTLOC(dwPinnedLocal);
m_pcsMarshal->EmitLDLOC(dwPinnedLocal);
m_pcsMarshal->EmitCONV_I();
- m_pcsMarshal->EmitLDC(m_pargs->na.m_optionalbaseoffset);
+ // Optimize marshalling by emitting the data ptr offset directly into the IL stream
+ // instead of doing an FCall to recalulate it each time when possible.
+ m_pcsMarshal->EmitLDC(ArrayBase::GetDataPtrOffset(m_pargs->m_pMarshalInfo->GetArrayElementTypeHandle().MakeSZArray().GetMethodTable()));
m_pcsMarshal->EmitADD();
EmitStoreNativeValue(m_pcsMarshal);
LocalDesc ILHiddenLengthArrayMarshaler::GetManagedType()
{
LIMITED_METHOD_CONTRACT;
+
return LocalDesc(ELEMENT_TYPE_OBJECT);
}
m_pcsMarshal->EmitSTLOC(dwPinnedLocal);
// native = pinnedLocal + dataOffset
+
+ // COMPAT: We cannot generate the same code that the C# compiler generates for
+ // a fixed() statement on an array since we need to provide a non-null value
+ // for a 0-length array. For compat reasons, we need to preserve old behavior.
+ EmitLoadManagedValue(m_pcsMarshal);
+ m_pcsMarshal->EmitSTLOC(dwPinnedLocal);
m_pcsMarshal->EmitLDLOC(dwPinnedLocal);
m_pcsMarshal->EmitCONV_I();
- m_pcsMarshal->EmitLDC(m_pargs->na.m_optionalbaseoffset);
+ // Optimize marshalling by emitting the data ptr offset directly into the IL stream
+ // instead of doing an FCall to recalulate it each time.
+ m_pcsMarshal->EmitLDC(ArrayBase::GetDataPtrOffset(m_pargs->m_pMarshalInfo->GetArrayElementTypeHandle().MakeSZArray().GetMethodTable()));
m_pcsMarshal->EmitADD();
EmitStoreNativeValue(m_pcsMarshal);
return false;
}
- if (m_pargs->na.m_optionalbaseoffset == 0)
- {
- return false;
- }
-
return true;
}
pGenericMD,
pGenericMD->GetMethodTable(),
FALSE, // forceBoxedEntryPoint
- m_pargs->na.m_pMT->GetInstantiation(), // methodInst
+ m_pargs->m_pMarshalInfo->GetArrayElementTypeHandle().GetInstantiation(), // methodInst
FALSE, // allowInstParam
TRUE); // forceRemotableMethod
}
}
CONTRACTL_END;
- CONSISTENCY_CHECK(pManagedType->cbType == 1);
if (pManagedType->IsValueClass())
{
EmitLoadHomeAddr(pslILEmit); // dest
ParamInfo.m_SafeArrayElementVT = VT_VARIANT;
}
- IfFailGoto(HandleArrayElemType(&ParamInfo, 0, thElement, -1, FALSE, isParam, pAssembly), lFail);
+ IfFailGoto(HandleArrayElemType(&ParamInfo, thElement, -1, FALSE, isParam, pAssembly), lFail);
break;
}
}
}
- unsigned ofs = 0;
- if (arrayTypeHnd.GetMethodTable())
- {
- ofs = ArrayBase::GetDataPtrOffset(arrayTypeHnd.GetMethodTable());
- if (ofs > 0xffff)
- {
- ofs = 0; // can't represent it, so pass on magic value (which causes fallback to regular ML code)
- }
- }
-
// Handle retrieving the information for the array type.
- IfFailGoto(HandleArrayElemType(&ParamInfo, (UINT16)ofs, thElement, asArray->GetRank(), mtype == ELEMENT_TYPE_SZARRAY, isParam, pAssembly), lFail);
+ IfFailGoto(HandleArrayElemType(&ParamInfo, thElement, asArray->GetRank(), mtype == ELEMENT_TYPE_SZARRAY, isParam, pAssembly), lFail);
break;
}
}
-HRESULT MarshalInfo::HandleArrayElemType(NativeTypeParamInfo *pParamInfo, UINT16 optbaseoffset, TypeHandle thElement, int iRank, BOOL fNoLowerBounds, BOOL isParam, Assembly *pAssembly)
+HRESULT MarshalInfo::HandleArrayElemType(NativeTypeParamInfo *pParamInfo, TypeHandle thElement, int iRank, BOOL fNoLowerBounds, BOOL isParam, Assembly *pAssembly)
{
CONTRACTL
{
{
// Retrieve the extra information associated with the native array marshaling.
m_args.na.m_vt = m_arrayElementType;
- m_args.na.m_pMT = !m_hndArrayElemType.IsTypeDesc() ? m_hndArrayElemType.AsMethodTable() : NULL;
- m_args.na.m_optionalbaseoffset = optbaseoffset;
m_countParamIdx = pParamInfo->m_CountParamIdx;
m_multiplier = pParamInfo->m_Multiplier;
m_additive = pParamInfo->m_Additive;
#ifdef FEATURE_COMINTEROP
else if (m_type == MARSHAL_TYPE_HIDDENLENGTHARRAY)
{
- m_args.na.m_optionalbaseoffset = optbaseoffset;
-
m_args.na.m_vt = m_arrayElementType;
- m_args.na.m_pMT = m_hndArrayElemType.AsMethodTable();
m_args.na.m_cbElementSize = arrayMarshalInfo.GetElementSize();
m_args.na.m_redirectedTypeIndex = arrayMarshalInfo.GetRedirectedTypeIndex();
}
struct
{
VARTYPE m_vt;
- UINT16 m_optionalbaseoffset; //for fast marshaling, offset of dataptr if known and less than 64k (0 otherwise)
- MethodTable* m_pMT;
#ifdef FEATURE_COMINTEROP
SIZE_T m_cbElementSize;
WinMDAdapter::RedirectedTypeIndex m_redirectedTypeIndex;
VOID EmitOrThrowInteropParamException(NDirectStubLinker* psl, BOOL fMngToNative, UINT resID, UINT paramIdx);
// These methods retrieve the information for different element types.
- HRESULT HandleArrayElemType(NativeTypeParamInfo *pParamInfo,
- UINT16 optbaseoffset,
+ HRESULT HandleArrayElemType(NativeTypeParamInfo *pParamInfo,
TypeHandle elemTypeHnd,
int iRank,
BOOL fNoLowerBounds,
#endif // _WIN64
Emit(CEE_LDC_R8, 1, (UINT_PTR)uConst);
}
+void ILCodeStream::EmitLDELEMA(int token)
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_LDELEMA, -1, token);
+}
void ILCodeStream::EmitLDELEM_REF()
{
WRAPPER_NO_CONTRACT;
{
CONTRACTL
{
- PRECONDITION(pType->cbType == 1);
+ PRECONDITION(pType->cbType >= 1);
}
CONTRACTL_END;
+
+ CorElementType elementType = ELEMENT_TYPE_END;
+
+ bool onlyFoundModifiers = true;
+ for(size_t i = 0; i < pType->cbType && onlyFoundModifiers; i++)
+ {
+ elementType = (CorElementType)pType->ElementType[i];
+ onlyFoundModifiers = (elementType == ELEMENT_TYPE_PINNED);
+ }
- switch (pType->ElementType[0])
+
+ switch (elementType)
{
case ELEMENT_TYPE_I1: EmitLDIND_I1(); break;
case ELEMENT_TYPE_BOOLEAN: // fall through
{
CONTRACTL
{
- PRECONDITION(pType->cbType == 1);
+ PRECONDITION(pType->cbType >= 1);
}
CONTRACTL_END;
-
+
+ CorElementType elementType = ELEMENT_TYPE_END;
+
+ bool onlyFoundModifiers = true;
+ for(size_t i = 0; i < pType->cbType && onlyFoundModifiers; i++)
+ {
+ elementType = (CorElementType)pType->ElementType[i];
+ onlyFoundModifiers = (elementType == ELEMENT_TYPE_PINNED);
+ }
switch (pType->ElementType[0])
{
case ELEMENT_TYPE_I1: EmitSTIND_I1(); break;
void MakeByRef()
{
+ LIMITED_METHOD_CONTRACT;
ChangeType(ELEMENT_TYPE_BYREF);
}
void MakePinned()
{
+ LIMITED_METHOD_CONTRACT;
ChangeType(ELEMENT_TYPE_PINNED);
}
+ void MakeArray()
+ {
+ LIMITED_METHOD_CONTRACT;
+ ChangeType(ELEMENT_TYPE_SZARRAY);
+ }
+
// makes the LocalDesc semantically equivalent to ET_TYPE_CMOD_REQD<IsCopyConstructed>/ET_TYPE_CMOD_REQD<NeedsCopyConstructorModifier>
void MakeCopyConstructedPointer()
{
+ LIMITED_METHOD_CONTRACT;
ChangeType(ELEMENT_TYPE_PTR);
bIsCopyConstructed = TRUE;
}
THROWS;
GC_TRIGGERS;
MODE_ANY;
- PRECONDITION(cbType == 1); // this only works on 1-element types for now
}
CONTRACTL_END;
+
+ bool lastElementTypeIsValueType = false;
if (ElementType[0] == ELEMENT_TYPE_VALUETYPE)
{
- return true;
+ lastElementTypeIsValueType = true;
}
else if ((ElementType[0] == ELEMENT_TYPE_INTERNAL) &&
(InternalToken.IsNativeValueType() ||
InternalToken.GetMethodTable()->IsValueType()))
{
- return true;
+ lastElementTypeIsValueType = true;
+ }
+
+ if (!lastElementTypeIsValueType)
+ {
+ return false;
+ }
+
+ // verify that the prefix element types don't make the type a non-value type
+ // this only works on LocalDescs with the prefixes exposed in the Add* methods above.
+ for (size_t i = 0; i < cbType - 1; i++)
+ {
+ if (ElementType[i] == ELEMENT_TYPE_BYREF
+ || ElementType[i] == ELEMENT_TYPE_SZARRAY
+ || ElementType[i] == ELEMENT_TYPE_PTR)
+ {
+ return false;
+ }
}
- return false;
+ return true;
}
};
void EmitLDC (DWORD_PTR uConst);
void EmitLDC_R4 (UINT32 uConst);
void EmitLDC_R8 (UINT64 uConst);
+ void EmitLDELEMA (int token);
void EmitLDELEM_REF ();
void EmitLDFLD (int token);
void EmitLDFLDA (int token);
}
catch (Exception e)
{
- Console.WriteLine($"\nTEST FAIL: {e.Message}");
+ Console.WriteLine($"\nTEST FAIL: {e}");
return 101;
}
}
}
catch (Exception e)
{
- Console.WriteLine($"\nTEST FAIL: {e.Message}");
+ Console.WriteLine($"\nTEST FAIL: {e}");
return 101;
}
}