summaryrefslogtreecommitdiff
path: root/src/vm/typeparse.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm/typeparse.cpp')
-rw-r--r--src/vm/typeparse.cpp1939
1 files changed, 1939 insertions, 0 deletions
diff --git a/src/vm/typeparse.cpp b/src/vm/typeparse.cpp
new file mode 100644
index 0000000000..356cb78423
--- /dev/null
+++ b/src/vm/typeparse.cpp
@@ -0,0 +1,1939 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ---------------------------------------------------------------------------
+// typeparse.cpp
+// ---------------------------------------------------------------------------
+//
+
+//
+
+
+#include "common.h"
+#include "class.h"
+#include "typehandle.h"
+#include "sstring.h"
+#include "typeparse.h"
+#include "typestring.h"
+#include "assemblynative.hpp"
+#include "stackprobe.h"
+#include "fstring.h"
+
+//
+// TypeNameFactory
+//
+HRESULT __stdcall TypeNameFactory::QueryInterface(REFIID riid, void **ppUnk)
+{
+ WRAPPER_NO_CONTRACT;
+
+ *ppUnk = 0;
+
+ if (riid == IID_IUnknown)
+ *ppUnk = (IUnknown *)this;
+ else if (riid == IID_ITypeNameFactory)
+ *ppUnk = (ITypeNameFactory*)this;
+ else
+ return (E_NOINTERFACE);
+
+ AddRef();
+ return S_OK;
+}
+
+HRESULT TypeNameFactoryCreateObject(REFIID riid, void **ppUnk)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ }
+ CONTRACTL_END;
+
+ HRESULT hr = S_OK;
+
+ TypeNameFactory *pTypeNameFactory = new (nothrow) TypeNameFactory();
+
+ if (!pTypeNameFactory)
+ return (E_OUTOFMEMORY);
+
+ hr = pTypeNameFactory->QueryInterface(riid, ppUnk);
+
+ if (FAILED(hr))
+ delete pTypeNameFactory;
+
+ return hr;
+}
+
+
+HRESULT __stdcall TypeNameFactory::ParseTypeName(LPCWSTR szTypeName, DWORD* pError, ITypeName** ppTypeName)
+{
+ CONTRACTL
+ {
+ SO_TOLERANT;
+ WRAPPER(THROWS);
+ }CONTRACTL_END;
+
+ if (!ppTypeName || !pError)
+ return E_INVALIDARG;
+
+ HRESULT hr = S_OK;
+ BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(return COR_E_STACKOVERFLOW);
+
+ *ppTypeName = NULL;
+ *pError = (DWORD)-1;
+
+ ITypeName* pTypeName = new (nothrow) TypeName(szTypeName, pError);
+
+ if (! pTypeName)
+ {
+ hr = E_OUTOFMEMORY;
+ }
+ else
+ {
+ pTypeName->AddRef();
+
+ if (*pError != (DWORD)-1)
+ {
+ pTypeName->Release();
+ hr = S_FALSE;
+ }
+ else
+ {
+ *ppTypeName = pTypeName;
+ }
+ }
+
+ END_SO_INTOLERANT_CODE;
+
+ return hr;
+}
+
+HRESULT __stdcall TypeNameFactory::GetTypeNameBuilder(ITypeNameBuilder** ppTypeNameBuilder)
+{
+ CONTRACTL
+ {
+ THROWS; // operator new has EX_TRY/EX_CATCH or other contract transitions(s)
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ if (!ppTypeNameBuilder)
+ return E_INVALIDARG;
+
+ *ppTypeNameBuilder = NULL;
+
+ HRESULT hr = S_OK;
+
+ BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(return COR_E_STACKOVERFLOW);
+
+ ITypeNameBuilder* pTypeNameBuilder = new (nothrow) TypeNameBuilderWrapper();
+
+ if (pTypeNameBuilder)
+ {
+ pTypeNameBuilder->AddRef();
+
+ *ppTypeNameBuilder = pTypeNameBuilder;
+ }
+ else
+ {
+ hr = E_OUTOFMEMORY;
+ }
+
+ END_SO_INTOLERANT_CODE;
+
+ return hr;
+}
+
+//
+// TypeName
+//
+SString* TypeName::ToString(SString* pBuf, BOOL bAssemblySpec, BOOL bSignature, BOOL bGenericArguments)
+{
+ WRAPPER_NO_CONTRACT;
+
+ PRECONDITION(!bGenericArguments & !bSignature &! bAssemblySpec);
+
+ BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(return pBuf);
+ {
+ TypeNameBuilder tnb(pBuf);
+
+ for (COUNT_T i = 0; i < m_names.GetCount(); i ++)
+ tnb.AddName(m_names[i]->GetUnicode());
+ }
+ END_SO_INTOLERANT_CODE;
+
+ return pBuf;
+}
+
+
+DWORD __stdcall TypeName::AddRef()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ m_count++;
+
+ return m_count;
+}
+
+DWORD __stdcall TypeName::Release()
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ SO_TOLERANT;
+ }
+ CONTRACTL_END;
+ VALIDATE_BACKOUT_STACK_CONSUMPTION;
+
+ m_count--;
+
+ DWORD dwCount = m_count;
+ if (dwCount == 0)
+ delete this;
+
+ return dwCount;
+}
+
+TypeName::~TypeName()
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ SO_TOLERANT;
+ }
+ CONTRACTL_END;
+ VALIDATE_BACKOUT_STACK_CONSUMPTION;
+
+ for(COUNT_T i = 0; i < m_genericArguments.GetCount(); i ++)
+ m_genericArguments[i]->Release();
+}
+
+HRESULT __stdcall TypeName::QueryInterface(REFIID riid, void **ppUnk)
+{
+ WRAPPER_NO_CONTRACT;
+
+ *ppUnk = 0;
+
+ if (riid == IID_IUnknown)
+ *ppUnk = (IUnknown *)this;
+ else if (riid == IID_ITypeName)
+ *ppUnk = (ITypeName*)this;
+ else
+ return (E_NOINTERFACE);
+
+ AddRef();
+ return S_OK;
+}
+
+HRESULT __stdcall TypeName::GetNameCount(DWORD* pCount)
+{
+ WRAPPER_NO_CONTRACT;
+
+ if (!pCount)
+ return E_INVALIDARG;
+
+ *pCount = m_names.GetCount();
+
+ return S_OK;
+}
+
+HRESULT __stdcall TypeName::GetNames(DWORD count, BSTR* bszName, DWORD* pFetched)
+{
+ CONTRACTL
+ {
+ SO_TOLERANT;
+ WRAPPER(THROWS);
+ }CONTRACTL_END;
+
+ HRESULT hr = S_OK;
+
+ if (!pFetched)
+ return E_INVALIDARG;
+
+ *pFetched = m_names.GetCount();
+
+ if (m_names.GetCount() > count)
+ return S_FALSE;
+
+ if (!bszName)
+ return E_INVALIDARG;
+
+ BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(return COR_E_STACKOVERFLOW);
+ {
+ for (COUNT_T i = 0; i < m_names.GetCount(); i ++)
+ bszName[i] = SysAllocString(m_names[i]->GetUnicode());
+ }
+ END_SO_INTOLERANT_CODE;
+
+ return hr;
+}
+
+HRESULT __stdcall TypeName::GetTypeArgumentCount(DWORD* pCount)
+{
+ WRAPPER_NO_CONTRACT;
+
+ if (!pCount)
+ return E_INVALIDARG;
+
+ *pCount = m_genericArguments.GetCount();
+
+ return S_OK;
+}
+
+HRESULT __stdcall TypeName::GetTypeArguments(DWORD count, ITypeName** ppArguments, DWORD* pFetched)
+{
+ WRAPPER_NO_CONTRACT;
+
+ if (!pFetched)
+ return E_INVALIDARG;
+
+ *pFetched = m_genericArguments.GetCount();
+
+ if (m_genericArguments.GetCount() > count)
+ return S_FALSE;
+
+ if (!ppArguments)
+ return E_INVALIDARG;
+
+ for (COUNT_T i = 0; i < m_genericArguments.GetCount(); i ++)
+ {
+ ppArguments[i] = m_genericArguments[i];
+ m_genericArguments[i]->AddRef();
+ }
+
+ return S_OK;
+}
+
+HRESULT __stdcall TypeName::GetModifierLength(DWORD* pCount)
+{
+ WRAPPER_NO_CONTRACT;
+
+ if (pCount == NULL)
+ return E_INVALIDARG;
+
+ *pCount = m_signature.GetCount();
+
+ return S_OK;
+}
+
+HRESULT __stdcall TypeName::GetModifiers(DWORD count, DWORD* pModifiers, DWORD* pFetched)
+{
+ WRAPPER_NO_CONTRACT;
+
+ if (!pFetched)
+ return E_INVALIDARG;
+
+ *pFetched = m_signature.GetCount();
+
+ if (m_signature.GetCount() > count)
+ return S_FALSE;
+
+ if (!pModifiers)
+ return E_INVALIDARG;
+
+ for (COUNT_T i = 0; i < m_signature.GetCount(); i ++)
+ pModifiers[i] = m_signature[i];
+
+ return S_OK;
+}
+
+HRESULT __stdcall TypeName::GetAssemblyName(BSTR* pszAssemblyName)
+{
+ CONTRACTL
+ {
+ SO_TOLERANT;
+ WRAPPER(THROWS);
+ }CONTRACTL_END;
+
+ HRESULT hr = S_OK;
+
+ if (pszAssemblyName == NULL)
+ return E_INVALIDARG;
+
+ BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(return COR_E_STACKOVERFLOW);
+ {
+ *pszAssemblyName = SysAllocString(m_assembly.GetUnicode());
+ }
+ END_SO_INTOLERANT_CODE;
+
+ if (*pszAssemblyName == NULL)
+ hr= E_OUTOFMEMORY;
+
+ return hr;
+}
+
+#if !defined(FEATURE_CORECLR) && !defined(CROSSGEN_COMPILE)
+SAFEHANDLE TypeName::GetSafeHandle()
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ }
+ CONTRACTL_END;
+
+ SAFEHANDLE objSafeHandle = NULL;
+
+ GCPROTECT_BEGIN(objSafeHandle);
+
+ objSafeHandle = (SAFEHANDLE)AllocateObject(MscorlibBinder::GetClass(CLASS__SAFE_TYPENAMEPARSER_HANDLE));
+ CallDefaultConstructor(objSafeHandle);
+
+ this->AddRef();
+ objSafeHandle->SetHandle(this);
+
+ GCPROTECT_END();
+
+ return objSafeHandle;
+}
+
+/*static*/
+void QCALLTYPE TypeName::QCreateTypeNameParser(LPCWSTR wszTypeName, QCall::ObjectHandleOnStack pHandle, BOOL throwOnError)
+{
+ QCALL_CONTRACT;
+
+ BEGIN_QCALL;
+
+ DWORD error = (DWORD)-1;
+ ReleaseHolder<TypeName> pTypeName = new TypeName(wszTypeName, &error);
+ pTypeName->AddRef();
+
+ if (error == (DWORD)-1)
+ {
+ GCX_COOP();
+ pHandle.Set(pTypeName->GetSafeHandle());
+ }
+ else
+ {
+ if (throwOnError)
+ {
+ StackSString buf;
+ StackSString msg(W("typeName@"));
+ COUNT_T size = buf.GetUnicodeAllocation();
+ _itow_s(error, buf.OpenUnicodeBuffer(size), size, /*radix*/10);
+ buf.CloseBuffer();
+ msg.Append(buf);
+ COMPlusThrowArgumentException(msg.GetUnicode(), NULL);
+ }
+ }
+
+ END_QCALL;
+}
+
+/*static*/
+void QCALLTYPE TypeName::QReleaseTypeNameParser(TypeName * pTypeName)
+{
+ CONTRACTL
+ {
+ QCALL_CHECK;
+ PRECONDITION(CheckPointer(pTypeName));
+ }
+ CONTRACTL_END;
+
+ BEGIN_QCALL;
+
+ pTypeName->Release();
+
+ END_QCALL;
+}
+
+/*static*/
+void QCALLTYPE TypeName::QGetNames(TypeName * pTypeName, QCall::ObjectHandleOnStack pNames)
+{
+ CONTRACTL
+ {
+ QCALL_CHECK;
+ PRECONDITION(CheckPointer(pTypeName));
+ }
+ CONTRACTL_END;
+
+ BEGIN_QCALL;
+
+ SArray<SString*> names = pTypeName->GetNames();
+ COUNT_T count = names.GetCount();
+
+ GCX_COOP();
+
+ if (count > 0)
+ {
+ PTRARRAYREF pReturnNames = NULL;
+
+ GCPROTECT_BEGIN(pReturnNames);
+
+ pReturnNames = (PTRARRAYREF)AllocateObjectArray(count, g_pStringClass);
+
+ for (COUNT_T i = 0; i < count; i++)
+ {
+ STRINGREF str = StringObject::NewString(names[i]->GetUnicode());
+ pReturnNames->SetAt(i, str);
+ }
+
+ pNames.Set(pReturnNames);
+
+ GCPROTECT_END();
+ }
+ else
+ {
+ pNames.Set(NULL);
+ }
+
+ END_QCALL;
+}
+
+/*static*/
+void QCALLTYPE TypeName::QGetTypeArguments(TypeName * pTypeName, QCall::ObjectHandleOnStack pTypeArguments)
+{
+ CONTRACTL
+ {
+ QCALL_CHECK;
+ PRECONDITION(CheckPointer(pTypeName));
+ }
+ CONTRACTL_END;
+
+ BEGIN_QCALL;
+
+ SArray<TypeName*> arguments = pTypeName->GetGenericArguments();
+ COUNT_T count = arguments.GetCount();
+
+ GCX_COOP();
+
+ if (count > 0)
+ {
+ PTRARRAYREF pReturnArguments = NULL;
+
+ GCPROTECT_BEGIN(pReturnArguments);
+
+ pReturnArguments = (PTRARRAYREF)AllocateObjectArray(count, MscorlibBinder::GetClass(CLASS__SAFE_TYPENAMEPARSER_HANDLE));
+
+ for (COUNT_T i = 0; i < count; i++)
+ {
+ SAFEHANDLE handle = arguments[i]->GetSafeHandle();
+ _ASSERTE(handle != NULL);
+
+ pReturnArguments->SetAt(i, handle);
+ }
+
+ pTypeArguments.Set(pReturnArguments);
+
+ GCPROTECT_END();
+ }
+ else
+ {
+ pTypeArguments.Set(NULL);
+ }
+
+ END_QCALL;
+}
+
+/*static*/
+void QCALLTYPE TypeName::QGetModifiers(TypeName * pTypeName, QCall::ObjectHandleOnStack pModifiers)
+{
+ CONTRACTL
+ {
+ QCALL_CHECK;
+ PRECONDITION(CheckPointer(pTypeName));
+ }
+ CONTRACTL_END;
+
+ BEGIN_QCALL;
+
+ SArray<DWORD> modifiers = pTypeName->GetSignature();
+ COUNT_T count = modifiers.GetCount();
+
+ GCX_COOP();
+
+ if (count > 0)
+ {
+ I4ARRAYREF pReturnModifiers = NULL;
+
+ GCPROTECT_BEGIN(pReturnModifiers);
+
+ //TODO: how do we Get
+ pReturnModifiers = (I4ARRAYREF)AllocatePrimitiveArray(ELEMENT_TYPE_I4, count);
+ INT32 *pToArray = pReturnModifiers->GetDirectPointerToNonObjectElements();
+
+ for (COUNT_T i = 0; i < count; i++)
+ {
+ pToArray[i] = modifiers[i];
+ }
+
+ pModifiers.Set(pReturnModifiers);
+
+ GCPROTECT_END();
+ }
+ else
+ {
+ pModifiers.Set(NULL);
+ }
+
+ END_QCALL;
+}
+
+/*static*/
+void QCALLTYPE TypeName::QGetAssemblyName(TypeName * pTypeName, QCall::StringHandleOnStack pAssemblyName)
+{
+ CONTRACTL
+ {
+ QCALL_CHECK;
+ PRECONDITION(CheckPointer(pTypeName));
+ }
+ CONTRACTL_END;
+
+ BEGIN_QCALL;
+
+ pAssemblyName.Set(*(pTypeName->GetAssembly()));
+
+ END_QCALL;
+}
+#endif //!FEATURE_CORECLR && !CROSSGEN_COMPILE
+
+//
+// TypeName::TypeNameParser
+//
+#undef IfFailGo
+#define IfFailGo(P) if (!P) return FALSE;
+
+TypeName* TypeName::AddGenericArgument()
+{
+ WRAPPER_NO_CONTRACT;
+
+ TypeName* pGenArg = new TypeName();
+ pGenArg->AddRef();
+
+ pGenArg->m_bIsGenericArgument = TRUE;
+ return m_genericArguments.AppendEx(pGenArg);
+}
+
+TypeName::TypeNameParser::TypeNameTokens TypeName::TypeNameParser::LexAToken(BOOL ignorePlus)
+{
+ LIMITED_METHOD_CONTRACT;
+
+ if (m_nextToken == TypeNameIdentifier)
+ return TypeNamePostIdentifier;
+
+ if (m_nextToken == TypeNameEnd)
+ return TypeNameEnd;
+
+ if (*m_itr == W('\0'))
+ return TypeNameEnd;
+
+ if (COMCharacter::nativeIsWhiteSpace(*m_itr))
+ {
+ m_itr++;
+ return LexAToken();
+ }
+
+ WCHAR c = *m_itr;
+ m_itr++;
+ switch(c)
+ {
+ case W(','): return TypeNameComma;
+ case W('['): return TypeNameOpenSqBracket;
+ case W(']'): return TypeNameCloseSqBracket;
+ case W('&'): return TypeNameAmperstand;
+ case W('*'): return TypeNameAstrix;
+ case W('+'): if (!ignorePlus) return TypeNamePlus;
+ case W('\\'):
+ m_itr--;
+ return TypeNameIdentifier;
+ }
+
+ ASSERT(!IsTypeNameReservedChar(c));
+
+ m_itr--;
+ return TypeNameIdentifier;
+}
+
+BOOL TypeName::TypeNameParser::GetIdentifier(SString* sszId, TypeName::TypeNameParser::TypeNameIdentifiers identifierType)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ PRECONDITION(m_currentToken == TypeNameIdentifier && m_nextToken == TypeNamePostIdentifier);
+
+ sszId->Clear();
+
+ LPCWSTR start = m_currentItr;
+ InlineSArray<LPCWSTR, 32> m_escape;
+
+ if (identifierType == TypeNameId)
+ {
+ do
+ {
+ switch (* m_currentItr ++)
+ {
+ case W(','):
+ case W('['):
+ case W(']'):
+ case W('&'):
+ case W('*'):
+ case W('+'):
+ case W('\0'):
+ goto done;
+
+ case W('\\'):
+ m_escape.Append(m_currentItr - 1);
+
+ if (! IsTypeNameReservedChar(*m_currentItr) || *m_currentItr == '\0')
+ return FALSE;
+
+ m_currentItr++;
+ break;
+
+ default:
+ break;
+ }
+ }
+ while(true);
+
+done:
+ m_currentItr--;
+ }
+ else if (identifierType == TypeNameFusionName)
+ {
+ while(*m_currentItr != W('\0'))
+ m_currentItr++;
+ }
+ else if (identifierType == TypeNameEmbeddedFusionName)
+ {
+ for (; (*m_currentItr != W('\0')) && (*m_currentItr != W(']')); m_currentItr++)
+ {
+ if (*m_currentItr == W('\\'))
+ {
+ if (*(m_currentItr + 1) == W(']'))
+ {
+ m_escape.Append(m_currentItr);
+ m_currentItr ++;
+ continue;
+ }
+ }
+
+ if (*m_currentItr == '\0')
+ return FALSE;
+ }
+ if (*m_currentItr == W('\0'))
+ {
+ return FALSE;
+ }
+ }
+ else
+ return FALSE;
+
+ sszId->Set(start, (COUNT_T)(m_currentItr - start));
+
+ for (SCOUNT_T i = m_escape.GetCount() - 1; i >= 0; i--)
+ sszId->Delete(sszId->Begin() + (SCOUNT_T)(m_escape[i] - start), 1);
+
+ m_itr = m_currentItr;
+ m_nextToken = LexAToken();
+ return TRUE;
+}
+
+BOOL TypeName::TypeNameParser::START()
+{
+ WRAPPER_NO_CONTRACT;
+
+ NextToken();
+ NextToken();
+ return AQN();
+}
+
+// FULLNAME ',' ASSEMSPEC
+// FULLNAME
+// /* empty */
+BOOL TypeName::TypeNameParser::AQN()
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+ IfFailGo(TokenIs(TypeNameAQN));
+
+ if (TokenIs(TypeNameEnd))
+ return TRUE;
+
+ IfFailGo(FULLNAME());
+
+ if (TokenIs(TypeNameComma))
+ {
+ NextToken();
+ IfFailGo(ASSEMSPEC());
+ }
+
+ IfFailGo(TokenIs(TypeNameEnd));
+
+ return TRUE;
+}
+
+// fusionName
+BOOL TypeName::TypeNameParser::ASSEMSPEC()
+{
+ WRAPPER_NO_CONTRACT;
+ IfFailGo(TokenIs(TypeNameASSEMSPEC));
+
+ GetIdentifier(m_pTypeName->GetAssembly(), TypeNameFusionName);
+
+ NextToken();
+
+ return TRUE;
+}
+
+// NAME GENPARAMS QUALIFIER
+BOOL TypeName::TypeNameParser::FULLNAME()
+{
+ WRAPPER_NO_CONTRACT;
+ IfFailGo(TokenIs(TypeNameFULLNAME));
+ IfFailGo(NAME());
+
+ IfFailGo(GENPARAMS());
+
+ IfFailGo(QUALIFIER());
+
+ return TRUE;
+}
+
+// *empty*
+// '[' GENARGS ']'
+BOOL TypeName::TypeNameParser::GENPARAMS()
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ if (!TokenIs(TypeNameGENPARAM))
+ return TRUE;
+
+ if (!NextTokenIs(TypeNameGENARGS))
+ return TRUE;
+
+ NextToken();
+ IfFailGo(GENARGS());
+
+ IfFailGo(TokenIs(TypeNameCloseSqBracket));
+ NextToken();
+
+ return TRUE;
+}
+
+// GENARG
+// GENARG ',' GENARGS
+BOOL TypeName::TypeNameParser::GENARGS()
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+ IfFailGo(TokenIs(TypeNameGENARGS));
+
+ IfFailGo(GENARG());
+
+ if (TokenIs(TypeNameComma))
+ {
+ NextToken();
+ IfFailGo(GENARGS());
+ }
+
+ return TRUE;
+}
+
+// '[' EAQN ']'
+// FULLNAME
+BOOL TypeName::TypeNameParser::GENARG()
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+ IfFailGo(TokenIs(TypeNameGENARG));
+
+ TypeName* pEnclosingTypeName = m_pTypeName;
+ m_pTypeName = m_pTypeName->AddGenericArgument();
+ {
+ if (TokenIs(TypeNameOpenSqBracket))
+ {
+ NextToken();
+ IfFailGo(EAQN());
+
+ IfFailGo(TokenIs(TypeNameCloseSqBracket));
+ NextToken();
+ }
+ else
+ {
+ IfFailGo(FULLNAME());
+ }
+ }
+ m_pTypeName = pEnclosingTypeName;
+
+ return TRUE;
+}
+
+// FULLNAME ',' EASSEMSPEC
+// FULLNAME
+BOOL TypeName::TypeNameParser::EAQN()
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+ IfFailGo(TokenIs(TypeNameEAQN));
+
+ IfFailGo(FULLNAME());
+
+ if (TokenIs(TypeNameComma))
+ {
+ NextToken();
+ IfFailGo(EASSEMSPEC());
+ }
+
+ return TRUE;
+}
+
+// embeddedFusionName
+BOOL TypeName::TypeNameParser::EASSEMSPEC()
+{
+ WRAPPER_NO_CONTRACT;
+ IfFailGo(TokenIs(TypeNameEASSEMSPEC));
+
+ GetIdentifier(m_pTypeName->GetAssembly(), TypeNameEmbeddedFusionName);
+
+ NextToken();
+
+ return TRUE;
+}
+
+// *empty*
+// '&'
+// '*' QUALIFIER
+// ARRAY QUALIFIER
+BOOL TypeName::TypeNameParser::QUALIFIER()
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ if (!TokenIs(TypeNameQUALIFIER))
+ return TRUE;
+
+ if (TokenIs(TypeNameAmperstand))
+ {
+ m_pTypeName->SetByRef();
+
+ NextToken();
+ }
+ else if (TokenIs(TypeNameAstrix))
+ {
+ m_pTypeName->SetPointer();
+
+ NextToken();
+ IfFailGo(QUALIFIER());
+ }
+ else
+ {
+ IfFailGo(ARRAY());
+ IfFailGo(QUALIFIER());
+ }
+
+ return TRUE;
+}
+
+// '[' RANK ']'
+// '[' '*' ']'
+BOOL TypeName::TypeNameParser::ARRAY()
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+ IfFailGo(TokenIs(TypeNameARRAY));
+
+ NextToken();
+
+ if (TokenIs(TypeNameAstrix))
+ {
+ m_pTypeName->SetArray(1);
+
+ NextToken();
+ }
+ else
+ {
+ DWORD dwRank = 1;
+ IfFailGo(RANK(&dwRank));
+
+ if (dwRank == 1)
+ m_pTypeName->SetSzArray();
+ else
+ m_pTypeName->SetArray(dwRank);
+ }
+
+ IfFailGo(TokenIs(TypeNameCloseSqBracket));
+ NextToken();
+
+ return TRUE;
+}
+
+// *empty*
+// ',' RANK
+BOOL TypeName::TypeNameParser::RANK(DWORD* pdwRank)
+{
+ WRAPPER_NO_CONTRACT;
+
+ if (!TokenIs(TypeNameRANK))
+ return TRUE;
+
+ NextToken();
+ *pdwRank = *pdwRank + 1;
+ IfFailGo(RANK(pdwRank));
+
+ return TRUE;
+}
+
+// id
+// id '+' NESTNAME
+BOOL TypeName::TypeNameParser::NAME()
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+ IfFailGo(TokenIs(TypeNameNAME));
+
+ GetIdentifier(m_pTypeName->AddName(), TypeNameId);
+
+ NextToken();
+
+ if (TokenIs(TypeNamePlus))
+ {
+ NextToken();
+ IfFailGo(NESTNAME());
+ }
+
+ return TRUE;
+}
+
+// id
+// id '+' NESTNAME
+BOOL TypeName::TypeNameParser::NESTNAME()
+{
+ WRAPPER_NO_CONTRACT;
+ IfFailGo(TokenIs(TypeNameNESTNAME));
+
+ GetIdentifier(m_pTypeName->AddName(), TypeNameId);
+
+ NextToken();
+ if (TokenIs(TypeNamePlus))
+ {
+ NextToken();
+ IfFailGo(NESTNAME());
+ }
+
+ return TRUE;
+}
+
+//--------------------------------------------------------------------------------------------------------------
+// This version is used for resolving types named in custom attributes such as those used
+// for interop. Thus, it follows a well-known multistage set of rules for determining which
+// assembly the type is in. It will also enforce that the requesting assembly has access
+// rights to the type being loaded.
+//
+// The search logic is:
+//
+// if szTypeName is ASM-qualified, only that assembly will be searched.
+// if szTypeName is not ASM-qualified, we will search for the types in the following order:
+// - in pRequestingAssembly (if not NULL). pRequestingAssembly is the assembly that contained
+// the custom attribute from which the typename was derived.
+// - in mscorlib.dll
+// - raise an AssemblyResolveEvent() in the current appdomain
+//
+// pRequestingAssembly may be NULL. In that case, the "visibility" check will simply check that
+// the loaded type has public access.
+//--------------------------------------------------------------------------------------------------------------
+/* public static */
+TypeHandle TypeName::GetTypeUsingCASearchRules(LPCUTF8 szTypeName, Assembly *pRequestingAssembly, BOOL *pfNameIsAsmQualified/* = NULL*/, BOOL bDoVisibilityChecks/* = TRUE*/)
+{
+ STATIC_CONTRACT_THROWS;
+ STATIC_CONTRACT_GC_TRIGGERS;
+ STATIC_CONTRACT_FAULT;
+
+ StackSString sszAssemblyQualifiedName(SString::Utf8, szTypeName);
+ return GetTypeUsingCASearchRules(sszAssemblyQualifiedName.GetUnicode(), pRequestingAssembly, pfNameIsAsmQualified, bDoVisibilityChecks);
+}
+
+TypeHandle TypeName::GetTypeUsingCASearchRules(LPCWSTR szTypeName, Assembly *pRequestingAssembly, BOOL *pfNameIsAsmQualified/* = NULL*/, BOOL bDoVisibilityChecks/* = TRUE*/)
+{
+ STATIC_CONTRACT_THROWS;
+ STATIC_CONTRACT_GC_TRIGGERS;
+ STATIC_CONTRACT_FAULT;
+
+ BOOL bIntrospectionOnly = pRequestingAssembly ? pRequestingAssembly->IsIntrospectionOnly() : FALSE; // classfactory loads are always for execution
+
+ DWORD error = (DWORD)-1;
+
+ GCX_COOP();
+ OBJECTREF keepAlive = NULL;
+ TypeHandle th = TypeHandle();
+
+ GCPROTECT_BEGIN(keepAlive);
+
+#ifdef __GNUC__
+ // When compiling under GCC we have to use the -fstack-check option to ensure we always spot stack
+ // overflow. But this option is intolerant of locals growing too large, so we have to cut back a bit
+ // on what we can allocate inline here. Leave the Windows versions alone to retain the perf benefits
+ // since we don't have the same constraints.
+ NewHolder<TypeName> pTypeName = new TypeName(szTypeName, &error);
+#else // __GNUC__
+ TypeName typeName(szTypeName, &error);
+ TypeName *pTypeName = &typeName;
+#endif // __GNUC__
+
+ if (error != (DWORD)-1)
+ {
+ StackSString buf;
+ StackSString msg(W("typeName@"));
+ COUNT_T size = buf.GetUnicodeAllocation();
+ _itow_s(error,buf.OpenUnicodeBuffer(size),size,10);
+ buf.CloseBuffer();
+ msg.Append(buf);
+ COMPlusThrowArgumentException(msg.GetUnicode(), NULL);
+ }
+
+ if (pfNameIsAsmQualified)
+ {
+ *pfNameIsAsmQualified = TRUE;
+ if (pTypeName->GetAssembly()->IsEmpty())
+ *pfNameIsAsmQualified = FALSE;
+ }
+
+ th = pTypeName->GetTypeWorker(
+ /*bThrowIfNotFound = */ TRUE,
+ /*bIgnoreCase = */ FALSE,
+ bIntrospectionOnly,
+ /*pAssemblyGetType =*/ NULL,
+ /*fEnableCASearchRules = */ TRUE,
+ /*fProhibitAsmQualifiedName = */ FALSE,
+ NULL,
+ pRequestingAssembly,
+ nullptr,
+ FALSE,
+ &keepAlive);
+
+ ASSERT(!th.IsNull());
+ LoaderAllocator *pLoaderAllocator = th.GetLoaderAllocator();
+
+ if (pLoaderAllocator->IsCollectible())
+ {
+ if ((pRequestingAssembly == NULL) || !pRequestingAssembly->GetLoaderAllocator()->IsCollectible())
+ {
+ COMPlusThrow(kNotSupportedException, W("NotSupported_CollectibleBoundNonCollectible"));
+ }
+ else
+ {
+ pRequestingAssembly->GetLoaderAllocator()->EnsureReference(pLoaderAllocator);
+ }
+ }
+
+ GCPROTECT_END();
+ return th;
+}
+
+
+
+
+
+
+//--------------------------------------------------------------------------------------------------------------
+// This everything-but-the-kitchen-sink version is what used to be called "GetType()". It exposes all the
+// funky knobs needed for implementing the specific requirements of the managed Type.GetType() apis and friends.
+//--------------------------------------------------------------------------------------------------------------
+/*public static */ TypeHandle TypeName::GetTypeManaged(
+ LPCWSTR szTypeName,
+ DomainAssembly* pAssemblyGetType,
+ BOOL bThrowIfNotFound,
+ BOOL bIgnoreCase,
+ BOOL bIntrospectionOnly,
+ BOOL bProhibitAsmQualifiedName,
+ StackCrawlMark* pStackMark,
+ BOOL bLoadTypeFromPartialNameHack,
+ OBJECTREF *pKeepAlive,
+ ICLRPrivBinder * pPrivHostBinder)
+{
+ STANDARD_VM_CONTRACT;
+
+ if (!*szTypeName)
+ COMPlusThrow(kArgumentException, W("Format_StringZeroLength"));
+
+ DWORD error = (DWORD)-1;
+
+ /* Partial name workaround loading must not load a collectible type */
+ if (bLoadTypeFromPartialNameHack)
+ pKeepAlive = NULL;
+
+#ifdef __GNUC__
+ // When compiling under GCC we have to use the -fstack-check option to ensure we always spot stack
+ // overflow. But this option is intolerant of locals growing too large, so we have to cut back a bit
+ // on what we can allocate inline here. Leave the Windows versions alone to retain the perf benefits
+ // since we don't have the same constraints.
+ NewHolder<TypeName> pTypeName = new TypeName(szTypeName, &error);
+#else // __GNUC__
+ TypeName typeName(szTypeName, &error);
+ TypeName *pTypeName = &typeName;
+#endif // __GNUC__
+
+ if (error != (DWORD)-1)
+ {
+ if (!bThrowIfNotFound)
+ return TypeHandle();
+
+ StackSString buf;
+ StackSString msg(W("typeName@"));
+ COUNT_T size = buf.GetUnicodeAllocation();
+ _itow_s(error, buf.OpenUnicodeBuffer(size), size, /*radix*/10);
+ buf.CloseBuffer();
+ msg.Append(buf);
+ COMPlusThrowArgumentException(msg.GetUnicode(), NULL);
+ }
+
+ BOOL bPeriodPrefix = szTypeName[0] == W('.');
+
+ TypeHandle result = pTypeName->GetTypeWorker(
+ bPeriodPrefix ? FALSE : bThrowIfNotFound,
+ bIgnoreCase,
+ bIntrospectionOnly,
+ pAssemblyGetType ? pAssemblyGetType->GetAssembly() : NULL,
+ /*fEnableCASearchRules = */TRUE,
+ bProhibitAsmQualifiedName,
+ pStackMark,
+ NULL,
+ pPrivHostBinder,
+ bLoadTypeFromPartialNameHack,
+ pKeepAlive);
+
+ if (bPeriodPrefix && result.IsNull())
+ {
+ new (pTypeName) TypeName(szTypeName + 1, &error);
+
+ if (error != (DWORD)-1)
+ {
+ if (!bThrowIfNotFound)
+ return TypeHandle();
+
+ StackSString buf;
+ StackSString msg(W("typeName@"));
+ COUNT_T size = buf.GetUnicodeAllocation();
+ _itow_s(error-1,buf.OpenUnicodeBuffer(size),size,10);
+ buf.CloseBuffer();
+ msg.Append(buf);
+ COMPlusThrowArgumentException(msg.GetUnicode(), NULL);
+ }
+
+ result = pTypeName->GetTypeWorker(
+ bThrowIfNotFound,
+ bIgnoreCase,
+ bIntrospectionOnly,
+ pAssemblyGetType ? pAssemblyGetType->GetAssembly() : NULL,
+ /*fEnableCASearchRules = */TRUE,
+ bProhibitAsmQualifiedName,
+ pStackMark,
+ NULL,
+ pPrivHostBinder,
+ bLoadTypeFromPartialNameHack,
+ pKeepAlive);
+ }
+
+ return result;
+}
+
+
+
+
+//-------------------------------------------------------------------------------------------
+// Retrieves a type from an assembly. It requires the caller to know which assembly
+// the type is in.
+//-------------------------------------------------------------------------------------------
+/* public static */ TypeHandle TypeName::GetTypeFromAssembly(LPCWSTR szTypeName, Assembly *pAssembly, BOOL bThrowIfNotFound /*= TRUE*/)
+{
+ STATIC_CONTRACT_THROWS;
+ STATIC_CONTRACT_GC_TRIGGERS;
+ STATIC_CONTRACT_FAULT;
+
+ _ASSERTE(szTypeName != NULL);
+ _ASSERTE(pAssembly != NULL);
+
+ if (!*szTypeName)
+ COMPlusThrow(kArgumentException, W("Format_StringZeroLength"));
+
+ DWORD error = (DWORD)-1;
+
+#ifdef __GNUC__
+ // When compiling under GCC we have to use the -fstack-check option to ensure we always spot stack
+ // overflow. But this option is intolerant of locals growing too large, so we have to cut back a bit
+ // on what we can allocate inline here. Leave the Windows versions alone to retain the perf benefits
+ // since we don't have the same constraints.
+ NewHolder<TypeName> pTypeName = new TypeName(szTypeName, &error);
+#else // __GNUC__
+ TypeName typeName(szTypeName, &error);
+ TypeName *pTypeName = &typeName;
+#endif // __GNUC__
+
+ if (error != (DWORD)-1)
+ {
+ StackSString buf;
+ StackSString msg(W("typeName@"));
+ COUNT_T size = buf.GetUnicodeAllocation();
+ _itow_s(error,buf.OpenUnicodeBuffer(size),size,10);
+ buf.CloseBuffer();
+ msg.Append(buf);
+ COMPlusThrowArgumentException(msg.GetUnicode(), NULL);
+ }
+
+ // Because the typename can come from untrusted input, we will throw an exception rather than assert.
+ // (This also assures that the shipping build does the right thing.)
+ if (!(pTypeName->GetAssembly()->IsEmpty()))
+ {
+ COMPlusThrow(kArgumentException, IDS_EE_CANNOT_HAVE_ASSEMBLY_SPEC);
+ }
+
+ return pTypeName->GetTypeWorker(bThrowIfNotFound, /*bIgnoreCase = */FALSE, pAssembly->IsIntrospectionOnly(), pAssembly, /*fEnableCASearchRules = */FALSE, FALSE, NULL, NULL,
+ nullptr, // pPrivHostBinder
+ FALSE, NULL /* cannot find a collectible type unless it is in assembly */);
+
+
+
+
+}
+
+//-------------------------------------------------------------------------------------------
+// Retrieves a type. Will assert if the name is not fully qualified.
+//-------------------------------------------------------------------------------------------
+/* public static */ TypeHandle TypeName::GetTypeFromAsmQualifiedName(LPCWSTR szFullyQualifiedName, BOOL bForIntrospection)
+{
+ STATIC_CONTRACT_THROWS;
+ STATIC_CONTRACT_GC_TRIGGERS;
+ STATIC_CONTRACT_FAULT;
+
+ _ASSERTE(szFullyQualifiedName != NULL);
+
+ if (!*szFullyQualifiedName)
+ COMPlusThrow(kArgumentException, W("Format_StringZeroLength"));
+
+ DWORD error = (DWORD)-1;
+
+#ifdef __GNUC__
+ // When compiling under GCC we have to use the -fstack-check option to ensure we always spot stack
+ // overflow. But this option is intolerant of locals growing too large, so we have to cut back a bit
+ // on what we can allocate inline here. Leave the Windows versions alone to retain the perf benefits
+ // since we don't have the same constraints.
+ NewHolder<TypeName> pTypeName = new TypeName(szFullyQualifiedName, &error);
+#else // __GNUC__
+ TypeName typeName(szFullyQualifiedName, &error);
+ TypeName *pTypeName = &typeName;
+#endif // __GNUC__
+
+ if (error != (DWORD)-1)
+ {
+ StackSString buf;
+ StackSString msg(W("typeName@"));
+ COUNT_T size = buf.GetUnicodeAllocation();
+ _itow_s(error,buf.OpenUnicodeBuffer(size),size,10);
+ buf.CloseBuffer();
+ msg.Append(buf);
+ COMPlusThrowArgumentException(msg.GetUnicode(), NULL);
+ }
+
+ return pTypeName->GetTypeFromAsm(bForIntrospection);
+}
+
+
+TypeHandle TypeName::GetTypeFromAsm(BOOL bForIntrospection)
+{
+ STATIC_CONTRACT_THROWS;
+ STATIC_CONTRACT_GC_TRIGGERS;
+ STATIC_CONTRACT_FAULT;
+
+ // Because the typename can come from untrusted input, we will throw an exception rather than assert.
+ // (This also assures that the shipping build does the right thing.)
+ if (this->GetAssembly()->IsEmpty())
+ {
+ COMPlusThrow(kArgumentException, IDS_EE_NEEDS_ASSEMBLY_SPEC);
+ }
+
+ return this->GetTypeWorker(
+ /*bThrowIfNotFound =*/TRUE,
+ /*bIgnoreCase = */FALSE,
+ bForIntrospection,
+ NULL,
+ /*fEnableCASearchRules = */FALSE,
+ FALSE,
+ NULL,
+ NULL,
+ nullptr, // pPrivHostBinder
+ FALSE,
+ NULL /* cannot find a collectible type */);
+}
+
+
+
+// -------------------------------------------------------------------------------------------------------------
+// This is the "uber" GetType() that all public GetType() funnels through. It's main job is to figure out which
+// Assembly to load the type from and then invoke GetTypeHaveAssembly.
+//
+// It's got a highly baroque interface partly for historical reasons and partly because it's the uber-function
+// for all of the possible GetTypes.
+// -------------------------------------------------------------------------------------------------------------
+/* private instance */ TypeHandle TypeName::GetTypeWorker(
+ BOOL bThrowIfNotFound,
+ BOOL bIgnoreCase,
+ BOOL bIntrospectionOnly,
+ Assembly* pAssemblyGetType,
+
+ BOOL fEnableCASearchRules,
+ BOOL bProhibitAsmQualifiedName,
+ StackCrawlMark* pStackMark,
+ Assembly* pRequestingAssembly,
+ ICLRPrivBinder * pPrivHostBinder,
+ BOOL bLoadTypeFromPartialNameHack,
+ OBJECTREF *pKeepAlive)
+{
+ CONTRACT(TypeHandle)
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ POSTCONDITION(!(RETVAL.IsNull() && bThrowIfNotFound));
+ }
+ CONTRACT_END
+
+ GCX_COOP();
+
+ ASSEMBLYREF asmRef = NULL;
+ TypeHandle th = TypeHandle();
+ GCPROTECT_BEGIN(asmRef);
+
+ // We don't ever want to get anything related to a collectible type in here if we are not able to return one.
+ ASSEMBLYREF *pAsmRef = &asmRef;
+ if (pKeepAlive == NULL)
+ pAsmRef = NULL;
+
+ //requires a lot of space
+ DECLARE_INTERIOR_STACK_PROBE;
+ // This function is recursive, so it must have an interior probe
+ if (bThrowIfNotFound)
+ {
+ DO_INTERIOR_STACK_PROBE_FOR_CHECK_THREAD(12);
+ }
+ else
+ {
+ DO_INTERIOR_STACK_PROBE_FOR_NOTHROW_CHECK_THREAD(12, goto Exit;);
+ }
+
+ // An explicit assembly has been specified so look for the type there
+ if (!GetAssembly()->IsEmpty())
+ {
+
+ if (bProhibitAsmQualifiedName && !m_bIsGenericArgument)
+ {
+ if (bThrowIfNotFound)
+ {
+ COMPlusThrow(kArgumentException, IDS_EE_ASSEMBLY_GETTYPE_CANNONT_HAVE_ASSEMBLY_SPEC);
+ }
+ else
+ {
+ th = TypeHandle();
+ goto Exit;
+ }
+ }
+
+ if (!pRequestingAssembly && pStackMark)
+ pRequestingAssembly = SystemDomain::GetCallersAssembly(pStackMark);
+
+ SString * pssOuterTypeName = NULL;
+ if (GetNames().GetCount() > 0)
+ {
+ pssOuterTypeName = GetNames()[0];
+ }
+
+ // We want to catch the exception if we're going to later try a partial bind.
+ if (bLoadTypeFromPartialNameHack)
+ {
+ EX_TRY
+ {
+ DomainAssembly *pDomainAssembly = LoadDomainAssembly(GetAssembly(), pRequestingAssembly,
+ pPrivHostBinder,
+ bThrowIfNotFound, bIntrospectionOnly, pssOuterTypeName);
+ if (pDomainAssembly)
+ {
+ th = GetTypeHaveAssembly(pDomainAssembly->GetAssembly(), bThrowIfNotFound, bIgnoreCase, pKeepAlive);
+ }
+ }
+ EX_CATCH
+ {
+ th = TypeHandle();
+ }
+ EX_END_CATCH(RethrowTransientExceptions);
+ }
+ else
+ {
+ DomainAssembly *pDomainAssembly = LoadDomainAssembly(GetAssembly(), pRequestingAssembly,
+ pPrivHostBinder,
+ bThrowIfNotFound, bIntrospectionOnly, pssOuterTypeName);
+ if (pDomainAssembly)
+ {
+ th = GetTypeHaveAssembly(pDomainAssembly->GetAssembly(), bThrowIfNotFound, bIgnoreCase, pKeepAlive);
+ }
+ }
+ }
+
+ // There's no explicit assembly so look in the assembly specified by the original caller (Assembly.GetType)
+ else if (pAssemblyGetType)
+ {
+ th = GetTypeHaveAssembly(pAssemblyGetType, bThrowIfNotFound, bIgnoreCase, pKeepAlive);
+ }
+
+ // Otherwise look in the caller's assembly then the system assembly
+ else if (fEnableCASearchRules)
+ {
+ if (bIntrospectionOnly)
+ {
+ if (pStackMark != NULL) // This is our test to see if we're being because of a managed api or because we are parsing a CA.
+ {
+ COMPlusThrow(kArgumentException, IDS_EE_REFLECTIONONLYGETTYPE_NOASSEMBLY);
+ }
+ }
+
+ if (!pRequestingAssembly && pStackMark)
+ pRequestingAssembly = SystemDomain::GetCallersAssembly(pStackMark);
+
+ // Look for type in caller's assembly
+ if (pRequestingAssembly)
+ th = GetTypeHaveAssembly(pRequestingAssembly, bThrowIfNotFound, bIgnoreCase, pKeepAlive);
+
+ // Look for type in system assembly
+ if (th.IsNull())
+ {
+ if (pRequestingAssembly != SystemDomain::SystemAssembly())
+ th = GetTypeHaveAssembly(SystemDomain::SystemAssembly(), bThrowIfNotFound, bIgnoreCase, pKeepAlive);
+ }
+
+ // Raise AssemblyResolveEvent to try to resolve assembly
+ if (th.IsNull() && !bIntrospectionOnly)
+ {
+ AppDomain *pDomain = (AppDomain *)SystemDomain::GetCurrentDomain();
+
+ if ((BaseDomain*)pDomain != SystemDomain::System())
+ {
+ TypeNameBuilder tnb;
+ for (COUNT_T i = 0; i < GetNames().GetCount(); i ++)
+ tnb.AddName(GetNames()[i]->GetUnicode());
+
+ StackScratchBuffer bufFullName;
+ DomainAssembly* pDomainAssembly = pDomain->RaiseTypeResolveEventThrowing(pRequestingAssembly?pRequestingAssembly->GetDomainAssembly():NULL,tnb.GetString()->GetANSI(bufFullName), pAsmRef);
+ if (pDomainAssembly)
+ th = GetTypeHaveAssembly(pDomainAssembly->GetAssembly(), bThrowIfNotFound, bIgnoreCase, pKeepAlive);
+ }
+ }
+ }
+ else
+ {
+ _ASSERTE(!"You must pass either a asm-qualified typename or an actual Assembly.");
+ }
+
+#ifdef FEATURE_FUSION
+ if (th.IsNull() && bLoadTypeFromPartialNameHack && GetAssembly() && !GetAssembly()->IsEmpty())
+ {
+ DomainAssembly* pPartialBindAssemblyHack = LoadAssemblyFromPartialNameHack(GetAssembly());
+
+ if (pPartialBindAssemblyHack)
+ th = GetTypeHaveAssembly(pPartialBindAssemblyHack->GetAssembly(), bThrowIfNotFound, bIgnoreCase, NULL);
+ }
+#endif // FEATURE_FUSION
+
+ if (!th.IsNull() && (!m_genericArguments.IsEmpty() || !m_signature.IsEmpty()))
+ {
+#ifdef CROSSGEN_COMPILE
+ // This method is used to parse type names in custom attributes. We do not support
+ // that these custom attributes will contain composed types.
+ CrossGenNotSupported("GetTypeWorker");
+#else
+ struct _gc
+ {
+ PTRARRAYREF refGenericArguments;
+ OBJECTREF keepAlive;
+ REFLECTCLASSBASEREF refGenericArg;
+ } gc;
+
+ gc.refGenericArguments = NULL;
+ gc.keepAlive = NULL;
+ gc.refGenericArg = NULL;
+
+ BOOL abortCall = FALSE;
+
+ GCPROTECT_BEGIN(gc);
+ INT32 cGenericArgs = m_genericArguments.GetCount();
+
+ if (cGenericArgs > 0)
+ {
+ TypeHandle arrayHandle = ClassLoader::LoadArrayTypeThrowing(TypeHandle(g_pRuntimeTypeClass), ELEMENT_TYPE_SZARRAY);
+ gc.refGenericArguments = (PTRARRAYREF)AllocateArrayEx(arrayHandle, &cGenericArgs, 1);
+ }
+ // Instantiate generic arguments
+ for (INT32 i = 0; i < cGenericArgs; i++)
+ {
+ TypeHandle thGenericArg = m_genericArguments[i]->GetTypeWorker(
+ bThrowIfNotFound, bIgnoreCase, bIntrospectionOnly,
+ pAssemblyGetType, fEnableCASearchRules, bProhibitAsmQualifiedName, pStackMark, pRequestingAssembly,
+ pPrivHostBinder,
+ bLoadTypeFromPartialNameHack,
+ (pKeepAlive != NULL) ? &gc.keepAlive : NULL /* Only pass a keepalive parameter if we were passed a keepalive parameter */);
+
+ if (thGenericArg.IsNull())
+ {
+ abortCall = TRUE;
+ break;
+ }
+
+ gc.refGenericArg = (REFLECTCLASSBASEREF)thGenericArg.GetManagedClassObject();
+
+ gc.refGenericArguments->SetAt(i, gc.refGenericArg);
+ }
+
+ MethodDescCallSite getTypeHelper(METHOD__RT_TYPE_HANDLE__GET_TYPE_HELPER);
+
+ ARG_SLOT args[5] = {
+ (ARG_SLOT)OBJECTREFToObject(th.GetManagedClassObject()),
+ (ARG_SLOT)OBJECTREFToObject(gc.refGenericArguments),
+ (ARG_SLOT)(SIZE_T)m_signature.OpenRawBuffer(),
+ m_signature.GetCount(),
+ };
+
+ REFLECTCLASSBASEREF refType = NULL;
+
+ if (!abortCall)
+ refType = (REFLECTCLASSBASEREF)getTypeHelper.Call_RetOBJECTREF(args);
+
+ if (refType != NULL)
+ {
+ th = refType->GetType();
+ if (pKeepAlive)
+ *pKeepAlive = refType;
+ }
+ else
+ {
+ th = TypeHandle();
+ }
+ GCPROTECT_END();
+#endif // CROSSGEN_COMPILE
+ }
+
+ if (th.IsNull() && bThrowIfNotFound)
+ {
+ StackSString buf;
+ LPCWSTR wszName = ToString(&buf)->GetUnicode();
+ MAKE_UTF8PTR_FROMWIDE(szName, wszName);
+
+ if (GetAssembly() && !GetAssembly()->IsEmpty())
+ {
+ ThrowTypeLoadException(NULL, szName, GetAssembly()->GetUnicode(), NULL, IDS_CLASSLOAD_GENERAL);
+ }
+ else if (pAssemblyGetType)
+ {
+ pAssemblyGetType->ThrowTypeLoadException(NULL, szName, IDS_CLASSLOAD_GENERAL);
+ }
+ else if (pRequestingAssembly)
+ {
+ pRequestingAssembly->ThrowTypeLoadException(NULL, szName, IDS_CLASSLOAD_GENERAL);
+ }
+ else
+ {
+ ThrowTypeLoadException(NULL, szName, NULL, NULL, IDS_CLASSLOAD_GENERAL);
+ }
+ }
+
+Exit:
+ ;
+ END_INTERIOR_STACK_PROBE;
+
+ GCPROTECT_END();
+
+ RETURN th;
+}
+
+//----------------------------------------------------------------------------------------------------------------
+// This is the one that actually loads the type once we've pinned down the Assembly it's in.
+//----------------------------------------------------------------------------------------------------------------
+/* private */
+TypeHandle
+TypeName::GetTypeHaveAssemblyHelper(
+ Assembly * pAssembly,
+ BOOL bThrowIfNotFound,
+ BOOL bIgnoreCase,
+ OBJECTREF * pKeepAlive,
+ BOOL bRecurse)
+{
+ WRAPPER_NO_CONTRACT;
+
+ TypeHandle th = TypeHandle();
+ SArray<SString *> & names = GetNames();
+ Module * pManifestModule = pAssembly->GetManifestModule();
+ Module * pLookOnlyInModule = NULL;
+ ClassLoader * pClassLoader = pAssembly->GetLoader();
+
+ NameHandle typeName(pManifestModule, mdtBaseType);
+
+#ifndef CROSSGEN_COMPILE
+ if (pAssembly->IsCollectible())
+ {
+ if (pKeepAlive == NULL)
+ {
+ COMPlusThrow(kNotSupportedException, W("NotSupported_CollectibleResolveFailure"));
+ }
+ *pKeepAlive = pAssembly->GetLoaderAllocator()->GetExposedObject();
+ }
+#endif
+
+ // Set up the name handle
+ if (bIgnoreCase)
+ typeName.SetCaseInsensitive();
+
+ EX_TRY
+ {
+ for (COUNT_T i = 0; i < names.GetCount(); i ++)
+ {
+ // each extra name represents one more level of nesting
+ LPCWSTR wname = names[i]->GetUnicode();
+
+ MAKE_UTF8PTR_FROMWIDE(name, wname);
+ typeName.SetName(name);
+
+ // typeName.m_pBucket gets set here if the type is found
+ // it will be used in the next iteration to look up the nested type
+ th = pClassLoader->LoadTypeHandleThrowing(&typeName, CLASS_LOADED, pLookOnlyInModule);
+
+ // DDB 117395: if we didn't find a type, don't bother looking for its nested type
+ if (th.IsNull())
+ break;
+
+ if (th.GetAssembly() != pAssembly)
+ { // It is forwarded type
+
+ // Use the found assembly class loader for potential nested types search
+ // The nested type has to be in the same module as the nesting type, so it doesn't make
+ // sense to follow the same chain of type forwarders again for the nested type
+ pClassLoader = th.GetAssembly()->GetLoader();
+ }
+
+ // Nested types must live in the module of the nesting type
+ if ((i == 0) && (names.GetCount() > 1) && (pLookOnlyInModule == NULL))
+ {
+ Module * pFoundModule = th.GetModule();
+
+ // Ensure that the bucket in the NameHandle is set to a valid bucket for all cases.
+
+ // If the type is in the manifest module, it will always be set correctly,
+ // or if the type is forwarded always lookup via the standard logic
+ if ((pFoundModule == pManifestModule) || (pFoundModule->GetAssembly() != pAssembly))
+ continue;
+
+ pLookOnlyInModule = pFoundModule;
+
+ // If the type is not in the manifest module, and the nesting type is in the exported
+ // types table of the manifest module, but the nested type is not, then unless the bucket
+ // is from the actual defining module, then the LoadTypeHandleThrowing logic will fail.
+ // To fix this, we must force the loader to record the bucket that refers to the nesting type
+ // from within the defining module's available class table.
+
+ // Re-run the LoadTypeHandleThrowing, but force it to only look in the class table for the module which
+ // defines the type. This should cause typeName.m_pBucket to be set to the bucket
+ // which corresponds to the type in the defining module, instead of potentially in the manifest module.
+ i = -1;
+ typeName.SetBucket(HashedTypeEntry());
+ }
+ }
+
+ if (th.IsNull() && bRecurse)
+ {
+ IMDInternalImport * pManifestImport = pManifestModule->GetMDImport();
+ HENUMInternalHolder phEnum(pManifestImport);
+ phEnum.EnumInit(mdtFile, mdTokenNil);
+ mdToken mdFile;
+
+ while (pManifestImport->EnumNext(&phEnum, &mdFile))
+ {
+ if (pManifestModule->LookupFile(mdFile))
+ continue;
+
+ pManifestModule->LoadModule(GetAppDomain(), mdFile, FALSE);
+
+ th = GetTypeHaveAssemblyHelper(pAssembly, bThrowIfNotFound, bIgnoreCase, NULL, FALSE);
+
+ if (!th.IsNull())
+ break;
+ }
+ }
+ }
+ EX_CATCH
+ {
+ if (bThrowIfNotFound)
+ EX_RETHROW;
+
+ Exception * ex = GET_EXCEPTION();
+
+ // Let non-File-not-found exceptions propagate
+ if (EEFileLoadException::GetFileLoadKind(ex->GetHR()) != kFileNotFoundException)
+ EX_RETHROW;
+ }
+ EX_END_CATCH(RethrowTerminalExceptions);
+
+ return th;
+} // TypeName::GetTypeHaveAssemblyHelper
+
+#ifdef FEATURE_FUSION
+DomainAssembly* LoadAssemblyFromPartialNameHack(SString* psszAssemblySpec, BOOL fCropPublicKey)
+{
+ CONTRACTL
+ {
+ MODE_COOPERATIVE;
+ THROWS;
+ GC_TRIGGERS;
+ INJECT_FAULT(COMPlusThrowOM(););
+ }
+ CONTRACTL_END;
+
+ MethodDescCallSite loadWithPartialNameHack(METHOD__ASSEMBLY__LOAD_WITH_PARTIAL_NAME_HACK);
+ ARG_SLOT args[2];
+ STRINGREF mszAssembly = NULL;
+ DomainAssembly* pPartialBindAssemblyHack = NULL;
+ GCPROTECT_BEGIN(mszAssembly);
+ {
+ mszAssembly = StringObject::NewString(psszAssemblySpec->GetUnicode());
+ args[0] = ObjToArgSlot(mszAssembly);
+ args[1] = BoolToArgSlot(fCropPublicKey);
+
+ ASSEMBLYREF assembly = (ASSEMBLYREF)loadWithPartialNameHack.Call_RetOBJECTREF(args);
+
+ if (assembly != NULL)
+ {
+ pPartialBindAssemblyHack = (DomainAssembly*) assembly->GetDomainAssembly();
+
+ if (pPartialBindAssemblyHack->GetAssembly()->IsCollectible())
+ {
+ // Should not be possible to reach
+ COMPlusThrow(kNotSupportedException, W("NotSupported_CollectibleAssemblyResolve"));
+ }
+ }
+ }
+ GCPROTECT_END();
+
+ return pPartialBindAssemblyHack;
+}
+#endif // FEATURE_FUSION
+
+DomainAssembly * LoadDomainAssembly(
+ SString * psszAssemblySpec,
+ Assembly * pRequestingAssembly,
+ ICLRPrivBinder * pPrivHostBinder,
+ BOOL bThrowIfNotFound,
+ BOOL bIntrospectionOnly,
+ SString * pssOuterTypeName)
+{
+ CONTRACTL
+ {
+ MODE_ANY;
+ THROWS;
+ GC_TRIGGERS;
+ INJECT_FAULT(COMPlusThrowOM(););
+ }
+ CONTRACTL_END;
+ AssemblySpec spec;
+ DomainAssembly *pDomainAssembly = NULL;
+
+ if (bIntrospectionOnly)
+ spec.SetIntrospectionOnly(TRUE);
+
+ StackScratchBuffer buffer;
+ LPCUTF8 szAssemblySpec = psszAssemblySpec->GetUTF8(buffer);
+ IfFailThrow(spec.Init(szAssemblySpec));
+
+ if (spec.IsContentType_WindowsRuntime())
+ {
+ _ASSERTE(pssOuterTypeName != NULL);
+ spec.SetWindowsRuntimeType(*pssOuterTypeName);
+ }
+
+ if (pPrivHostBinder)
+ {
+ spec.SetHostBinder(pPrivHostBinder);
+ }
+ else if (pRequestingAssembly && (!pRequestingAssembly->IsDomainNeutral()) && (!pRequestingAssembly->IsCollectible()))
+ {
+ GCX_PREEMP();
+ spec.SetParentAssembly(pRequestingAssembly->GetDomainAssembly());
+ }
+
+#if defined(FEATURE_HOST_ASSEMBLY_RESOLVER)
+ // If the requesting assembly has Fallback LoadContext binder available,
+ // then set it up in the AssemblySpec.
+ if (pRequestingAssembly != NULL)
+ {
+ PEFile *pRequestingAssemblyManifestFile = pRequestingAssembly->GetManifestFile();
+ spec.SetFallbackLoadContextBinderForRequestingAssembly(pRequestingAssemblyManifestFile->GetFallbackLoadContextBinder());
+ }
+#endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER)
+
+ if (bThrowIfNotFound)
+ {
+ pDomainAssembly = spec.LoadDomainAssembly(FILE_LOADED);
+ }
+ else
+ {
+ EX_TRY
+ {
+ pDomainAssembly = spec.LoadDomainAssembly(FILE_LOADED, NULL, bThrowIfNotFound);
+ }
+ EX_CATCH
+ {
+ Exception *ex = GET_EXCEPTION();
+
+ // Let non-File-not-found execeptions propagate
+ if (EEFileLoadException::GetFileLoadKind(ex->GetHR()) != kFileNotFoundException)
+ EX_RETHROW;
+ }
+ EX_END_CATCH(RethrowTerminalExceptions);
+ }
+
+ return pDomainAssembly;
+}
+
+