diff options
Diffstat (limited to 'src/vm/typeparse.cpp')
-rw-r--r-- | src/vm/typeparse.cpp | 1939 |
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; +} + + |