Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/corert.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichal Strehovský <MichalStrehovsky@users.noreply.github.com>2017-08-31 04:05:28 +0300
committerGitHub <noreply@github.com>2017-08-31 04:05:28 +0300
commit2b40a707239a9974a63cf992ce6a6f8303f5b362 (patch)
treef2499c94260c3c02c368aaade7885db361a89d1c /src/System.Private.TypeLoader
parent47f76ea83121b629abeccf152841516d66ce9b42 (diff)
parent81a8e55b2e32c0a27a17e1ba67664c593a14810b (diff)
Merge pull request #4370 from dotnet/nmirror
Merge nmirror to master
Diffstat (limited to 'src/System.Private.TypeLoader')
-rw-r--r--src/System.Private.TypeLoader/src/Internal/Reflection/Execution/AssemblyBinderImplementation.Ecma.cs6
-rw-r--r--src/System.Private.TypeLoader/src/Internal/Reflection/Execution/AssemblyBinderImplementation.cs45
-rw-r--r--src/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeBuilder.cs126
-rw-r--r--src/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.cs76
-rw-r--r--src/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/genericdictionarycell.cs63
-rw-r--r--src/System.Private.TypeLoader/src/Resources/Strings.resx5
6 files changed, 307 insertions, 14 deletions
diff --git a/src/System.Private.TypeLoader/src/Internal/Reflection/Execution/AssemblyBinderImplementation.Ecma.cs b/src/System.Private.TypeLoader/src/Internal/Reflection/Execution/AssemblyBinderImplementation.Ecma.cs
index 6f926d7a2..c6342da01 100644
--- a/src/System.Private.TypeLoader/src/Internal/Reflection/Execution/AssemblyBinderImplementation.Ecma.cs
+++ b/src/System.Private.TypeLoader/src/Internal/Reflection/Execution/AssemblyBinderImplementation.Ecma.cs
@@ -86,14 +86,14 @@ namespace Internal.Reflection.Execution
}
}
- partial void BindEcmaAssemblyName(RuntimeAssemblyName refName, ref AssemblyBindResult result, ref Exception exception, ref bool foundMatch)
+ partial void BindEcmaAssemblyName(RuntimeAssemblyName refName, ref AssemblyBindResult result, ref Exception exception, ref Exception preferredException, ref bool foundMatch)
{
lock(s_ecmaLoadedAssemblies)
{
for (int i = 0; i < s_ecmaLoadedAssemblies.Count; i++)
{
PEInfo info = s_ecmaLoadedAssemblies[i];
- if (AssemblyNameMatches(refName, info.Name))
+ if (AssemblyNameMatches(refName, info.Name, ref preferredException))
{
if (foundMatch)
{
@@ -146,7 +146,7 @@ namespace Internal.Reflection.Execution
RuntimeAssemblyName runtimeAssemblyName = reader.GetAssemblyDefinition().ToRuntimeAssemblyName(reader).CanonicalizePublicKeyToken();
// If assembly name doesn't match, it isn't the one we're looking for. Continue to look for more assemblies
- if (!AssemblyNameMatches(refName, runtimeAssemblyName))
+ if (!AssemblyNameMatches(refName, runtimeAssemblyName, ref preferredException))
continue;
// This is the one we are looking for, add it to the list of loaded assemblies
diff --git a/src/System.Private.TypeLoader/src/Internal/Reflection/Execution/AssemblyBinderImplementation.cs b/src/System.Private.TypeLoader/src/Internal/Reflection/Execution/AssemblyBinderImplementation.cs
index e17a26c13..701160534 100644
--- a/src/System.Private.TypeLoader/src/Internal/Reflection/Execution/AssemblyBinderImplementation.cs
+++ b/src/System.Private.TypeLoader/src/Internal/Reflection/Execution/AssemblyBinderImplementation.cs
@@ -35,7 +35,7 @@ namespace Internal.Reflection.Execution
public static AssemblyBinderImplementation Instance { get; } = new AssemblyBinderImplementation();
partial void BindEcmaByteArray(byte[] rawAssembly, byte[] rawSymbolStore, ref AssemblyBindResult bindResult, ref Exception exception, ref bool? result);
- partial void BindEcmaAssemblyName(RuntimeAssemblyName refName, ref AssemblyBindResult result, ref Exception exception, ref bool resultBoolean);
+ partial void BindEcmaAssemblyName(RuntimeAssemblyName refName, ref AssemblyBindResult result, ref Exception exception, ref Exception preferredException, ref bool resultBoolean);
partial void InsertEcmaLoadedAssemblies(List<AssemblyBindResult> loadedAssemblies);
public sealed override bool Bind(byte[] rawAssembly, byte[] rawSymbolStore, out AssemblyBindResult bindResult, out Exception exception)
@@ -59,6 +59,8 @@ namespace Internal.Reflection.Execution
result = default(AssemblyBindResult);
exception = null;
+ Exception preferredException = null;
+
refName = refName.CanonicalizePublicKeyToken();
// At least one real-world app calls Type.GetType() for "char" using the assembly name "mscorlib". To accomodate this,
@@ -80,7 +82,7 @@ namespace Internal.Reflection.Execution
}
else
{
- nameMatches = AssemblyNameMatches(refName, group.Key);
+ nameMatches = AssemblyNameMatches(refName, group.Key, ref preferredException);
}
if (nameMatches)
@@ -100,13 +102,13 @@ namespace Internal.Reflection.Execution
}
}
- BindEcmaAssemblyName(refName, ref result, ref exception, ref foundMatch);
+ BindEcmaAssemblyName(refName, ref result, ref exception, ref preferredException, ref foundMatch);
if (exception != null)
return false;
if (!foundMatch)
{
- exception = new IOException(SR.Format(SR.FileNotFound_AssemblyNotFound, refName.FullName));
+ exception = preferredException ?? new FileNotFoundException(SR.Format(SR.FileNotFound_AssemblyNotFound, refName.FullName));
return false;
}
@@ -159,7 +161,7 @@ namespace Internal.Reflection.Execution
//
// Encapsulates the assembly ref->def matching policy.
//
- private bool AssemblyNameMatches(RuntimeAssemblyName refName, RuntimeAssemblyName defName)
+ private bool AssemblyNameMatches(RuntimeAssemblyName refName, RuntimeAssemblyName defName, ref Exception preferredException)
{
//
// The defName came from trusted metadata so it should be fully specified.
@@ -175,9 +177,11 @@ namespace Internal.Reflection.Execution
if (refName.Version != null)
{
- int compareResult = refName.Version.CompareTo(defName.Version);
- if (compareResult > 0)
+ if (!AssemblyVersionMatches(refVersion: refName.Version, defVersion: defName.Version))
+ {
+ preferredException = new FileLoadException(SR.Format(SR.FileLoadException_RefDefMismatch, refName.FullName, defName.Version, refName.Version));
return false;
+ }
}
if (refName.CultureName != null)
@@ -206,6 +210,33 @@ namespace Internal.Reflection.Execution
return true;
}
+ private static bool AssemblyVersionMatches(Version refVersion, Version defVersion)
+ {
+ if (defVersion.Major < refVersion.Major)
+ return false;
+ if (defVersion.Major > refVersion.Major)
+ return true;
+
+ if (defVersion.Minor < refVersion.Minor)
+ return false;
+ if (defVersion.Minor > refVersion.Minor)
+ return true;
+
+ if (refVersion.Build == -1)
+ return true;
+ if (defVersion.Build < refVersion.Build)
+ return false;
+ if (defVersion.Build > refVersion.Build)
+ return true;
+
+ if (refVersion.Revision == -1)
+ return true;
+ if (defVersion.Revision < refVersion.Revision)
+ return false;
+
+ return true;
+ }
+
/// <summary>
/// This callback gets called whenever a module gets registered. It adds the metadata reader
/// for the new module to the available scopes. The lock in ExecutionEnvironmentImplementation ensures
diff --git a/src/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeBuilder.cs b/src/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeBuilder.cs
index a1da52d2c..a23b0453b 100644
--- a/src/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeBuilder.cs
+++ b/src/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeBuilder.cs
@@ -417,7 +417,7 @@ namespace Internal.Runtime.TypeLoader
internal void ParseNativeLayoutInfo(InstantiatedMethod method)
{
- TypeLoaderLogger.WriteLine("Parsing NativeLayoutInfo for method " + ToString() + " ...");
+ TypeLoaderLogger.WriteLine("Parsing NativeLayoutInfo for method " + method.ToString() + " ...");
Debug.Assert(method.Dictionary == null);
@@ -1867,6 +1867,103 @@ namespace Internal.Runtime.TypeLoader
}
}
+ //
+ // This method is used to build the floating portion of a generic dictionary.
+ //
+ private unsafe IntPtr BuildFloatingDictionary(TypeSystemContext typeSystemContext, IntPtr context, bool isTypeContext, IntPtr fixedDictionary, out bool isNewlyAllocatedDictionary)
+ {
+ isNewlyAllocatedDictionary = true;
+
+ NativeParser nativeLayoutParser;
+ NativeLayoutInfoLoadContext nlilContext;
+
+ if (isTypeContext)
+ {
+ TypeDesc typeContext = typeSystemContext.ResolveRuntimeTypeHandle(*(RuntimeTypeHandle*)&context);
+
+ TypeLoaderLogger.WriteLine("Building floating dictionary layout for type " + typeContext.ToString() + "...");
+
+ // We should only perform updates to floating dictionaries for types that share normal canonical code
+ Debug.Assert(typeContext.CanShareNormalGenericCode());
+
+ // Computing the template will throw if no template is found.
+ typeContext.ComputeTemplate();
+
+ TypeBuilderState state = typeContext.GetOrCreateTypeBuilderState();
+ nativeLayoutParser = state.GetParserForNativeLayoutInfo();
+ nlilContext = state.NativeLayoutInfo.LoadContext;
+ }
+ else
+ {
+ RuntimeTypeHandle declaringTypeHandle;
+ MethodNameAndSignature nameAndSignature;
+ RuntimeTypeHandle[] genericMethodArgHandles;
+ bool success = TypeLoaderEnvironment.Instance.TryGetGenericMethodComponents(context, out declaringTypeHandle, out nameAndSignature, out genericMethodArgHandles);
+ Debug.Assert(success);
+
+ DefType declaringType = (DefType)typeSystemContext.ResolveRuntimeTypeHandle(declaringTypeHandle);
+ InstantiatedMethod methodContext = (InstantiatedMethod)typeSystemContext.ResolveGenericMethodInstantiation(
+ false,
+ declaringType,
+ nameAndSignature,
+ typeSystemContext.ResolveRuntimeTypeHandles(genericMethodArgHandles),
+ IntPtr.Zero,
+ false);
+
+ TypeLoaderLogger.WriteLine("Building floating dictionary layout for method " + methodContext.ToString() + "...");
+
+ // We should only perform updates to floating dictionaries for gemeric methods that share normal canonical code
+ Debug.Assert(!methodContext.IsNonSharableMethod);
+
+ uint nativeLayoutInfoToken;
+ NativeFormatModuleInfo nativeLayoutModule;
+ MethodDesc templateMethod = (new TemplateLocator()).TryGetGenericMethodTemplate(methodContext, out nativeLayoutModule, out nativeLayoutInfoToken);
+ if (templateMethod == null)
+ throw new TypeBuilder.MissingTemplateException();
+
+ NativeReader nativeLayoutInfoReader = TypeLoaderEnvironment.Instance.GetNativeLayoutInfoReader(nativeLayoutModule.Handle);
+
+ nativeLayoutParser = new NativeParser(nativeLayoutInfoReader, nativeLayoutInfoToken);
+ nlilContext = new NativeLayoutInfoLoadContext
+ {
+ _typeSystemContext = methodContext.Context,
+ _typeArgumentHandles = methodContext.OwningType.Instantiation,
+ _methodArgumentHandles = methodContext.Instantiation,
+ _module = nativeLayoutModule
+ };
+ }
+
+ NativeParser dictionaryLayoutParser = nativeLayoutParser.GetParserForBagElementKind(BagElementKind.DictionaryLayout);
+ if (dictionaryLayoutParser.IsNull)
+ return IntPtr.Zero;
+
+ int floatingVersionCellIndex, floatingVersionInLayout;
+ GenericDictionaryCell[] floatingCells = GenericDictionaryCell.BuildFloatingDictionary(this, nlilContext, dictionaryLayoutParser, out floatingVersionCellIndex, out floatingVersionInLayout);
+ if (floatingCells == null)
+ return IntPtr.Zero;
+
+ // First, check if the current version of the existing floating dictionary matches the version in the native layout. If so, there
+ // is no need to allocate anything new, and we can just use the existing statically compiled floating portion of the input dictionary.
+ int currentFloatingVersion = (int)(((IntPtr*)fixedDictionary)[floatingVersionCellIndex]);
+ if(currentFloatingVersion == floatingVersionInLayout)
+ {
+ isNewlyAllocatedDictionary = false;
+ return fixedDictionary + IntPtr.Size * floatingVersionCellIndex;
+ }
+
+ GenericTypeDictionary floatingDict = new GenericTypeDictionary(floatingCells);
+
+ IntPtr result = floatingDict.Allocate();
+
+ ProcessTypesNeedingPreparation();
+
+ FinishTypeAndMethodBuilding();
+
+ floatingDict.Finish(this);
+
+ return result;
+ }
+
public static bool TryBuildGenericType(RuntimeTypeHandle genericTypeDefinitionHandle, RuntimeTypeHandle[] genericTypeArgumentHandles, out RuntimeTypeHandle runtimeTypeHandle)
{
Debug.Assert(!genericTypeDefinitionHandle.IsNull() && genericTypeArgumentHandles != null && genericTypeArgumentHandles.Length > 0);
@@ -2142,5 +2239,32 @@ namespace Internal.Runtime.TypeLoader
return success;
}
+
+ //
+ // This method is used to build the floating portion of a generic dictionary.
+ //
+ internal static IntPtr TryBuildFloatingDictionary(IntPtr context, bool isTypeContext, IntPtr fixedDictionary, out bool isNewlyAllocatedDictionary)
+ {
+ isNewlyAllocatedDictionary = true;
+
+ try
+ {
+ TypeSystemContext typeSystemContext = TypeSystemContextFactory.Create();
+
+ IntPtr ret = new TypeBuilder().BuildFloatingDictionary(typeSystemContext, context, isTypeContext, fixedDictionary, out isNewlyAllocatedDictionary);
+
+ TypeSystemContextFactory.Recycle(typeSystemContext);
+
+ return ret;
+ }
+ catch (MissingTemplateException e)
+ {
+ // This should not ever happen. The static compiler should ensure that the templates are always
+ // available for types and methods that have floating dictionaries
+ Environment.FailFast("MissingTemplateException thrown during dictionary update", e);
+
+ return IntPtr.Zero;
+ }
+ }
}
}
diff --git a/src/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.cs b/src/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.cs
index e4a05ff8b..b3b39230e 100644
--- a/src/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.cs
+++ b/src/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.cs
@@ -86,6 +86,11 @@ namespace Internal.Runtime.TypeLoader
return TypeLoaderEnvironment.Instance.TryGetArrayTypeForElementType(elementTypeHandle, isMdArray, rank, out arrayTypeHandle);
}
+ public override IntPtr UpdateFloatingDictionary(IntPtr context, IntPtr dictionaryPtr)
+ {
+ return TypeLoaderEnvironment.Instance.UpdateFloatingDictionary(context, dictionaryPtr);
+ }
+
/// <summary>
/// Register a new runtime-allocated code thunk in the diagnostic stream.
/// </summary>
@@ -513,6 +518,77 @@ namespace Internal.Runtime.TypeLoader
}
}
+ public unsafe IntPtr UpdateFloatingDictionary(IntPtr context, IntPtr dictionaryPtr)
+ {
+ IntPtr newFloatingDictionary;
+ bool isNewlyAllocatedDictionary;
+ bool isTypeContext = context != dictionaryPtr;
+
+ if (isTypeContext)
+ {
+ EEType* pEEType = (EEType*)context.ToPointer();
+ IntPtr curDictPtr = EETypeCreator.GetDictionary(pEEType);
+
+ // Look for the exact base type that owns the dictionary. We may be having
+ // a virtual method run on a derived type and the generic lookup are performed
+ // on the base type's dictionary.
+ while (curDictPtr != dictionaryPtr)
+ {
+ pEEType = pEEType->BaseType;
+ Debug.Assert(pEEType != null);
+ curDictPtr = EETypeCreator.GetDictionary(pEEType);
+ Debug.Assert(curDictPtr != IntPtr.Zero);
+ }
+
+ context = (IntPtr)pEEType;
+ }
+
+ using (LockHolder.Hold(_typeLoaderLock))
+ {
+ // Check if some other thread already allocated a floating dictionary and updated the fixed portion
+ if(*(IntPtr*)dictionaryPtr != IntPtr.Zero)
+ return *(IntPtr*)dictionaryPtr;
+
+ try
+ {
+ if (t_isReentrant)
+ Environment.FailFast("Reentrant update to floating dictionary");
+ t_isReentrant = true;
+
+ newFloatingDictionary = TypeBuilder.TryBuildFloatingDictionary(context, isTypeContext, dictionaryPtr, out isNewlyAllocatedDictionary);
+
+ t_isReentrant = false;
+ }
+ catch
+ {
+ // Catch and rethrow any exceptions instead of using finally block. Otherwise, filters that are run during
+ // the first pass of exception unwind may hit the re-entrancy fail fast above.
+
+ // TODO: Convert this to filter for better diagnostics once we switch to Roslyn
+
+ t_isReentrant = false;
+ throw;
+ }
+ }
+
+ if (newFloatingDictionary == IntPtr.Zero)
+ {
+ Environment.FailFast("Unable to update floating dictionary");
+ return IntPtr.Zero;
+ }
+
+ // The pointer to the floating dictionary is the first slot of the fixed dictionary.
+ if (Interlocked.CompareExchange(ref *(IntPtr*)dictionaryPtr, newFloatingDictionary, IntPtr.Zero) != IntPtr.Zero)
+ {
+ // Some other thread beat us and updated the pointer to the floating dictionary.
+ // Free the one allocated by the current thread
+ if (isNewlyAllocatedDictionary)
+ MemoryHelpers.FreeMemory(newFloatingDictionary);
+ }
+
+ return *(IntPtr*)dictionaryPtr;
+ }
+
public bool CanInstantiationsShareCode(RuntimeTypeHandle[] genericArgHandles1, RuntimeTypeHandle[] genericArgHandles2, CanonicalFormKind kind)
{
if (genericArgHandles1.Length != genericArgHandles2.Length)
diff --git a/src/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/genericdictionarycell.cs b/src/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/genericdictionarycell.cs
index a07d6dad8..2ddeff53c 100644
--- a/src/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/genericdictionarycell.cs
+++ b/src/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/genericdictionarycell.cs
@@ -1073,8 +1073,7 @@ namespace Internal.Runtime.TypeLoader
{
TypeLoaderLogger.WriteLine(" -> DictionaryCell[" + i.LowLevelToString() + "] = ");
- GenericDictionaryCell cell = ParseAndCreateCell(nativeLayoutInfoLoadContext, ref parser);
- dictionary[i] = cell;
+ dictionary[i] = ParseAndCreateCell(nativeLayoutInfoLoadContext, ref parser);
}
for (uint i = 0; i < count; i++)
@@ -1083,6 +1082,66 @@ namespace Internal.Runtime.TypeLoader
return dictionary;
}
+ internal static unsafe GenericDictionaryCell[] BuildFloatingDictionary(TypeBuilder typeBuilder, NativeLayoutInfoLoadContext nativeLayoutInfoLoadContext, NativeParser parser, out int floatingVersionCellIndex, out int floatingVersionInLayout)
+ {
+ //
+ // The format of a dictionary that has a floating portion is as follows:
+ //
+ // "Fixed" portion:
+ // - First slot is a pointer to the first cell of the "floating" portion
+ // - Followed by N various dictionary lookup cells
+ // "Floating" portion:
+ // - Cell containing the version number of the floating portion
+ // - Followed by N various dictionary lookup cells
+ //
+
+ floatingVersionCellIndex = floatingVersionInLayout = -1;
+
+ uint count = parser.GetSequenceCount();
+ Debug.Assert(count > 1);
+
+ GenericDictionaryCell cell = ParseAndCreateCell(nativeLayoutInfoLoadContext, ref parser);
+ if (!(cell is PointerToOtherDictionarySlotCell))
+ {
+ // This is not a dictionary layout that has a floating portion
+ Debug.Assert(false, "Unreachable: we should never reach here if the target dictionary does not have a floating layout");
+ return null;
+ }
+
+ PointerToOtherDictionarySlotCell pointerToCell = (PointerToOtherDictionarySlotCell)cell;
+ floatingVersionCellIndex = (int)pointerToCell.OtherDictionarySlot;
+ Debug.Assert(count > pointerToCell.OtherDictionarySlot);
+
+ GenericDictionaryCell[] dictionary = new GenericDictionaryCell[count - pointerToCell.OtherDictionarySlot];
+
+ for (uint i = 1; i < pointerToCell.OtherDictionarySlot; i++)
+ {
+ // Parse and discard the fixed dictionary cells. We only need to build the cells of the floating portion
+ ParseAndCreateCell(nativeLayoutInfoLoadContext, ref parser);
+ }
+
+ for (uint i = pointerToCell.OtherDictionarySlot; i < count; i++)
+ {
+ TypeLoaderLogger.WriteLine(" -> FloatingDictionaryCell[" + (i - pointerToCell.OtherDictionarySlot).LowLevelToString() + "] (" + i.LowLevelToString() + " in all) = ");
+
+ cell = ParseAndCreateCell(nativeLayoutInfoLoadContext, ref parser);
+
+ if (i == pointerToCell.OtherDictionarySlot)
+ {
+ // The first cell in the floating portion should always be the version number
+ Debug.Assert(cell is IntPtrCell);
+ floatingVersionInLayout = (int)((IntPtrCell)cell).Value;
+ }
+
+ dictionary[i - pointerToCell.OtherDictionarySlot] = cell;
+ }
+
+ for (uint i = pointerToCell.OtherDictionarySlot; i < count; i++)
+ dictionary[i - pointerToCell.OtherDictionarySlot].Prepare(typeBuilder);
+
+ return dictionary;
+ }
+
#if SUPPORTS_NATIVE_METADATA_TYPE_LOADING
/// <summary>
/// Build an array of GenericDictionaryCell from a NativeParser stream that has the appropriate metadata
diff --git a/src/System.Private.TypeLoader/src/Resources/Strings.resx b/src/System.Private.TypeLoader/src/Resources/Strings.resx
index 02df9452b..949e8adc2 100644
--- a/src/System.Private.TypeLoader/src/Resources/Strings.resx
+++ b/src/System.Private.TypeLoader/src/Resources/Strings.resx
@@ -126,4 +126,7 @@
<data name="FileNotFound_AssemblyNotFound" xml:space="preserve">
<value>Cannot load assembly '{0}'. No metadata found for this assembly.</value>
</data>
-</root> \ No newline at end of file
+ <data name="FileLoadException_RefDefMismatch" xml:space="preserve">
+ <value>Cannot load assembly '{0}'. The assembly exists but its version {1} is lower than the requested version {2}.</value>
+ </data>
+</root>