Generic lookup fixes (#6798)
1) Add new form of generic lookup for generic non-GC static base. 2) Fix previously missing generic lookup for fields. 2) Fix treatment of generic fields according to CoreCLR. Thanks Tomas
This commit is contained in:
Родитель
ffce8c20d4
Коммит
5346e8d329
|
@ -30,6 +30,7 @@ namespace ILCompiler.DependencyAnalysis
|
|||
// The following helpers are used for generic lookups only
|
||||
TypeHandle,
|
||||
NecessaryTypeHandle,
|
||||
DeclaringTypeHandle,
|
||||
MethodHandle,
|
||||
FieldHandle,
|
||||
MethodDictionary,
|
||||
|
|
|
@ -20,6 +20,8 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
|
|||
|
||||
private readonly MethodWithToken _methodArgument;
|
||||
|
||||
private readonly FieldDesc _fieldArgument;
|
||||
|
||||
private readonly GenericContext _methodContext;
|
||||
|
||||
private readonly SignatureContext _signatureContext;
|
||||
|
@ -29,6 +31,7 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
|
|||
ReadyToRunFixupKind fixupKind,
|
||||
TypeDesc typeArgument,
|
||||
MethodWithToken methodArgument,
|
||||
FieldDesc fieldArgument,
|
||||
GenericContext methodContext,
|
||||
SignatureContext signatureContext)
|
||||
{
|
||||
|
@ -36,6 +39,7 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
|
|||
_fixupKind = fixupKind;
|
||||
_typeArgument = typeArgument;
|
||||
_methodArgument = methodArgument;
|
||||
_fieldArgument = fieldArgument;
|
||||
_methodContext = methodContext;
|
||||
_signatureContext = signatureContext;
|
||||
}
|
||||
|
@ -86,6 +90,10 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
|
|||
isUnboxingStub: false,
|
||||
isInstantiatingStub: true);
|
||||
}
|
||||
else if (_fieldArgument != null)
|
||||
{
|
||||
dataBuilder.EmitFieldSignature(_fieldArgument, _signatureContext);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
|
|
|
@ -448,42 +448,57 @@ namespace ILCompiler.DependencyAnalysis
|
|||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected override ISymbolNode CreateGenericLookupFromDictionaryNode(ReadyToRunGenericHelperKey helperKey)
|
||||
private ILCompiler.DependencyAnalysis.ReadyToRun.ReadyToRunHelper GetGenericStaticHelper(ReadyToRunHelperId helperId)
|
||||
{
|
||||
switch (helperKey.HelperId)
|
||||
ILCompiler.DependencyAnalysis.ReadyToRun.ReadyToRunHelper r2rHelper;
|
||||
|
||||
switch (helperId)
|
||||
{
|
||||
case ReadyToRunHelperId.GetGCStaticBase:
|
||||
return new DelayLoadHelperImport(
|
||||
this,
|
||||
HelperImports,
|
||||
ILCompiler.DependencyAnalysis.ReadyToRun.ReadyToRunHelper.READYTORUN_HELPER_GenericGcStaticBase,
|
||||
new TypeFixupSignature(
|
||||
ReadyToRunFixupKind.READYTORUN_FIXUP_Invalid,
|
||||
(TypeDesc)helperKey.Target,
|
||||
InputModuleContext));
|
||||
r2rHelper = ILCompiler.DependencyAnalysis.ReadyToRun.ReadyToRunHelper.READYTORUN_HELPER_GenericGcStaticBase;
|
||||
break;
|
||||
|
||||
case ReadyToRunHelperId.GetNonGCStaticBase:
|
||||
r2rHelper = ILCompiler.DependencyAnalysis.ReadyToRun.ReadyToRunHelper.READYTORUN_HELPER_GenericNonGcStaticBase;
|
||||
break;
|
||||
|
||||
case ReadyToRunHelperId.GetThreadStaticBase:
|
||||
r2rHelper = ILCompiler.DependencyAnalysis.ReadyToRun.ReadyToRunHelper.READYTORUN_HELPER_GenericGcTlsBase;
|
||||
break;
|
||||
|
||||
case ReadyToRunHelperId.GetThreadNonGcStaticBase:
|
||||
r2rHelper = ILCompiler.DependencyAnalysis.ReadyToRun.ReadyToRunHelper.READYTORUN_HELPER_GenericNonGcTlsBase;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
return r2rHelper;
|
||||
}
|
||||
|
||||
protected override ISymbolNode CreateGenericLookupFromDictionaryNode(ReadyToRunGenericHelperKey helperKey)
|
||||
{
|
||||
return new DelayLoadHelperImport(
|
||||
this,
|
||||
HelperImports,
|
||||
GetGenericStaticHelper(helperKey.HelperId),
|
||||
new TypeFixupSignature(
|
||||
ReadyToRunFixupKind.READYTORUN_FIXUP_Invalid,
|
||||
(TypeDesc)helperKey.Target,
|
||||
InputModuleContext));
|
||||
}
|
||||
|
||||
protected override ISymbolNode CreateGenericLookupFromTypeNode(ReadyToRunGenericHelperKey helperKey)
|
||||
{
|
||||
switch (helperKey.HelperId)
|
||||
{
|
||||
case ReadyToRunHelperId.GetGCStaticBase:
|
||||
return new DelayLoadHelperImport(
|
||||
this,
|
||||
HelperImports,
|
||||
ILCompiler.DependencyAnalysis.ReadyToRun.ReadyToRunHelper.READYTORUN_HELPER_GenericGcStaticBase,
|
||||
new TypeFixupSignature(
|
||||
ReadyToRunFixupKind.READYTORUN_FIXUP_Invalid,
|
||||
(TypeDesc)helperKey.Target,
|
||||
InputModuleContext));
|
||||
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
return new DelayLoadHelperImport(
|
||||
this,
|
||||
HelperImports,
|
||||
GetGenericStaticHelper(helperKey.HelperId),
|
||||
new TypeFixupSignature(
|
||||
ReadyToRunFixupKind.READYTORUN_FIXUP_Invalid,
|
||||
(TypeDesc)helperKey.Target,
|
||||
InputModuleContext));
|
||||
}
|
||||
|
||||
private Dictionary<string, SectionStartNode> _sectionStartNodes = new Dictionary<string, SectionStartNode>();
|
||||
|
|
|
@ -647,7 +647,7 @@ namespace ILCompiler.DependencyAnalysis
|
|||
if (!_delegateCtors.TryGetValue(ctorKey, out ISymbolNode ctorNode))
|
||||
{
|
||||
IMethodNode targetMethodNode = _codegenNodeFactory.MethodEntrypoint(
|
||||
targetMethod,
|
||||
targetMethod,
|
||||
constrainedType: null,
|
||||
originalMethod: null,
|
||||
methodToken: methodToken,
|
||||
|
@ -697,6 +697,7 @@ namespace ILCompiler.DependencyAnalysis
|
|||
public readonly ReadyToRunFixupKind FixupKind;
|
||||
public readonly TypeDesc TypeArgument;
|
||||
public readonly MethodWithToken MethodArgument;
|
||||
public readonly FieldDesc FieldArgument;
|
||||
public readonly GenericContext MethodContext;
|
||||
|
||||
public GenericLookupKey(
|
||||
|
@ -704,12 +705,14 @@ namespace ILCompiler.DependencyAnalysis
|
|||
ReadyToRunFixupKind fixupKind,
|
||||
TypeDesc typeArgument,
|
||||
MethodWithToken methodArgument,
|
||||
FieldDesc fieldArgument,
|
||||
GenericContext methodContext)
|
||||
{
|
||||
LookupKind = lookupKind;
|
||||
FixupKind = fixupKind;
|
||||
TypeArgument = typeArgument;
|
||||
MethodArgument = methodArgument;
|
||||
FieldArgument = fieldArgument;
|
||||
MethodContext = methodContext;
|
||||
}
|
||||
|
||||
|
@ -719,6 +722,7 @@ namespace ILCompiler.DependencyAnalysis
|
|||
FixupKind == other.FixupKind &&
|
||||
RuntimeDeterminedTypeHelper.Equals(TypeArgument, other.TypeArgument) &&
|
||||
RuntimeDeterminedTypeHelper.Equals(MethodArgument?.Method ?? null, other.MethodArgument?.Method ?? null) &&
|
||||
RuntimeDeterminedTypeHelper.Equals(FieldArgument, other.FieldArgument) &&
|
||||
MethodContext.Equals(other.MethodContext);
|
||||
}
|
||||
|
||||
|
@ -733,6 +737,7 @@ namespace ILCompiler.DependencyAnalysis
|
|||
(int)FixupKind +
|
||||
(TypeArgument != null ? 31 * RuntimeDeterminedTypeHelper.GetHashCode(TypeArgument) : 0) +
|
||||
(MethodArgument != null ? 31 * RuntimeDeterminedTypeHelper.GetHashCode(MethodArgument.Method) : 0) +
|
||||
(FieldArgument != null ? 31 * RuntimeDeterminedTypeHelper.GetHashCode(FieldArgument) : 0) +
|
||||
MethodContext.GetHashCode());
|
||||
}
|
||||
}
|
||||
|
@ -788,6 +793,14 @@ namespace ILCompiler.DependencyAnalysis
|
|||
methodContext,
|
||||
signatureContext);
|
||||
|
||||
case ReadyToRunHelperId.FieldHandle:
|
||||
return GenericLookupFieldHelper(
|
||||
runtimeLookupKind,
|
||||
ReadyToRunFixupKind.READYTORUN_FIXUP_FieldHandle,
|
||||
(FieldDesc)helperArgument,
|
||||
methodContext,
|
||||
signatureContext);
|
||||
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
@ -800,7 +813,7 @@ namespace ILCompiler.DependencyAnalysis
|
|||
GenericContext methodContext,
|
||||
SignatureContext signatureContext)
|
||||
{
|
||||
GenericLookupKey key = new GenericLookupKey(runtimeLookupKind, fixupKind, typeArgument, methodArgument: null, methodContext);
|
||||
GenericLookupKey key = new GenericLookupKey(runtimeLookupKind, fixupKind, typeArgument, methodArgument: null, fieldArgument: null, methodContext);
|
||||
ISymbolNode node;
|
||||
if (!_genericLookupHelpers.TryGetValue(key, out node))
|
||||
{
|
||||
|
@ -808,7 +821,28 @@ namespace ILCompiler.DependencyAnalysis
|
|||
_codegenNodeFactory,
|
||||
_codegenNodeFactory.HelperImports,
|
||||
ILCompiler.DependencyAnalysis.ReadyToRun.ReadyToRunHelper.READYTORUN_HELPER_DelayLoad_Helper,
|
||||
new GenericLookupSignature(runtimeLookupKind, fixupKind, typeArgument, methodArgument: null, methodContext, signatureContext));
|
||||
new GenericLookupSignature(runtimeLookupKind, fixupKind, typeArgument, methodArgument: null, fieldArgument: null, methodContext, signatureContext));
|
||||
_genericLookupHelpers.Add(key, node);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
private ISymbolNode GenericLookupFieldHelper(
|
||||
CORINFO_RUNTIME_LOOKUP_KIND runtimeLookupKind,
|
||||
ReadyToRunFixupKind fixupKind,
|
||||
FieldDesc fieldArgument,
|
||||
GenericContext methodContext,
|
||||
SignatureContext signatureContext)
|
||||
{
|
||||
GenericLookupKey key = new GenericLookupKey(runtimeLookupKind, fixupKind, typeArgument: null, methodArgument: null, fieldArgument: fieldArgument, methodContext);
|
||||
ISymbolNode node;
|
||||
if (!_genericLookupHelpers.TryGetValue(key, out node))
|
||||
{
|
||||
node = new DelayLoadHelperImport(
|
||||
_codegenNodeFactory,
|
||||
_codegenNodeFactory.HelperImports,
|
||||
ILCompiler.DependencyAnalysis.ReadyToRun.ReadyToRunHelper.READYTORUN_HELPER_DelayLoad_Helper,
|
||||
new GenericLookupSignature(runtimeLookupKind, fixupKind, typeArgument: null, methodArgument: null, fieldArgument: fieldArgument, methodContext, signatureContext));
|
||||
_genericLookupHelpers.Add(key, node);
|
||||
}
|
||||
return node;
|
||||
|
@ -821,7 +855,7 @@ namespace ILCompiler.DependencyAnalysis
|
|||
GenericContext methodContext,
|
||||
SignatureContext signatureContext)
|
||||
{
|
||||
GenericLookupKey key = new GenericLookupKey(runtimeLookupKind, fixupKind, typeArgument: null, methodArgument, methodContext);
|
||||
GenericLookupKey key = new GenericLookupKey(runtimeLookupKind, fixupKind, typeArgument: null, methodArgument, fieldArgument: null, methodContext);
|
||||
ISymbolNode node;
|
||||
if (!_genericLookupHelpers.TryGetValue(key, out node))
|
||||
{
|
||||
|
@ -829,7 +863,7 @@ namespace ILCompiler.DependencyAnalysis
|
|||
_codegenNodeFactory,
|
||||
_codegenNodeFactory.HelperImports,
|
||||
ILCompiler.DependencyAnalysis.ReadyToRun.ReadyToRunHelper.READYTORUN_HELPER_DelayLoad_Helper,
|
||||
new GenericLookupSignature(runtimeLookupKind, fixupKind, typeArgument: null, methodArgument, methodContext, signatureContext));
|
||||
new GenericLookupSignature(runtimeLookupKind, fixupKind, typeArgument: null, methodArgument, fieldArgument: null, methodContext, signatureContext));
|
||||
_genericLookupHelpers.Add(key, node);
|
||||
}
|
||||
return node;
|
||||
|
|
|
@ -109,6 +109,17 @@ namespace ILCompiler
|
|||
return true;
|
||||
}
|
||||
|
||||
public static bool Equals(FieldDesc field1, FieldDesc field2)
|
||||
{
|
||||
if (field1 == null || field2 == null)
|
||||
{
|
||||
return field1 == null && field2 == null;
|
||||
}
|
||||
return field1.Name == field2.Name &&
|
||||
RuntimeDeterminedTypeHelper.Equals(field1.OwningType, field2.OwningType) &&
|
||||
RuntimeDeterminedTypeHelper.Equals(field1.FieldType, field2.FieldType);
|
||||
}
|
||||
|
||||
public static int GetHashCode(Instantiation instantiation)
|
||||
{
|
||||
int hashcode = unchecked(instantiation.Length << 24);
|
||||
|
@ -136,6 +147,11 @@ namespace ILCompiler
|
|||
method.GetTypicalMethodDefinition().GetHashCode() + 31 * GetHashCode(method.Instantiation)));
|
||||
}
|
||||
|
||||
public static int GetHashCode(FieldDesc field)
|
||||
{
|
||||
return unchecked(GetHashCode(field.OwningType) + 97 * GetHashCode(field.FieldType) + 31 * field.Name.GetHashCode());
|
||||
}
|
||||
|
||||
public static void WriteTo(Instantiation instantiation, Utf8StringBuilder sb)
|
||||
{
|
||||
sb.Append("<");
|
||||
|
|
|
@ -99,47 +99,49 @@ namespace Internal.JitInterface
|
|||
if (_compilation.NeedsRuntimeLookup(helperId, entity))
|
||||
{
|
||||
lookup.lookupKind.needsRuntimeLookup = true;
|
||||
|
||||
lookup.runtimeLookup.signature = null;
|
||||
|
||||
MethodDesc contextMethod = methodFromContext(pResolvedToken.tokenContext);
|
||||
|
||||
// Do not bother computing the runtime lookup if we are inlining. The JIT is going
|
||||
// to abort the inlining attempt anyway.
|
||||
if (contextMethod != MethodBeingCompiled)
|
||||
return;
|
||||
|
||||
GenericDictionaryLookup genericLookup = _compilation.ComputeGenericLookup(contextMethod, helperId, entity);
|
||||
|
||||
if (genericLookup.UseHelper)
|
||||
if (contextMethod != _methodCodeNode.Method)
|
||||
{
|
||||
lookup.runtimeLookup.indirections = CORINFO.USEHELPER;
|
||||
lookup.lookupKind.runtimeLookupFlags = (ushort)genericLookup.HelperId;
|
||||
lookup.lookupKind.runtimeLookupArgs = (void*)ObjectToHandle(genericLookup.HelperObject);
|
||||
return;
|
||||
}
|
||||
|
||||
// There is a pathological case where invalid IL refereces __Canon type directly, but there is no dictionary available to store the lookup.
|
||||
// All callers of ComputeRuntimeLookupForSharedGenericToken have to filter out this case. We can't do much about it here.
|
||||
Debug.Assert(contextMethod.IsSharedByGenericInstantiations);
|
||||
|
||||
if (contextMethod.RequiresInstMethodDescArg())
|
||||
{
|
||||
lookup.lookupKind.runtimeLookupKind = CORINFO_RUNTIME_LOOKUP_KIND.CORINFO_LOOKUP_METHODPARAM;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (genericLookup.ContextSource == GenericContextSource.MethodParameter)
|
||||
if (contextMethod.RequiresInstMethodTableArg())
|
||||
{
|
||||
lookup.runtimeLookup.helper = CorInfoHelpFunc.CORINFO_HELP_RUNTIMEHANDLE_METHOD;
|
||||
lookup.lookupKind.runtimeLookupKind = CORINFO_RUNTIME_LOOKUP_KIND.CORINFO_LOOKUP_CLASSPARAM;
|
||||
}
|
||||
else
|
||||
{
|
||||
lookup.runtimeLookup.helper = CorInfoHelpFunc.CORINFO_HELP_RUNTIMEHANDLE_CLASS;
|
||||
lookup.lookupKind.runtimeLookupKind = CORINFO_RUNTIME_LOOKUP_KIND.CORINFO_LOOKUP_THISOBJ;
|
||||
}
|
||||
|
||||
lookup.runtimeLookup.indirections = (ushort)genericLookup.NumberOfIndirections;
|
||||
lookup.runtimeLookup.offset0 = (IntPtr)genericLookup[0];
|
||||
if (genericLookup.NumberOfIndirections > 1)
|
||||
lookup.runtimeLookup.offset1 = (IntPtr)genericLookup[1];
|
||||
lookup.runtimeLookup.testForFixup = false; // TODO: this will be needed in true multifile
|
||||
lookup.runtimeLookup.testForNull = false;
|
||||
lookup.runtimeLookup.indirectFirstOffset = false;
|
||||
lookup.runtimeLookup.indirectSecondOffset = false;
|
||||
lookup.lookupKind.runtimeLookupFlags = 0;
|
||||
lookup.lookupKind.runtimeLookupArgs = null;
|
||||
}
|
||||
|
||||
lookup.lookupKind.runtimeLookupKind = GetLookupKindFromContextSource(genericLookup.ContextSource);
|
||||
// Unless we decide otherwise, just do the lookup via a helper function
|
||||
lookup.runtimeLookup.indirections = CORINFO.USEHELPER;
|
||||
|
||||
lookup.lookupKind.runtimeLookupFlags = (ushort)helperId;
|
||||
lookup.lookupKind.runtimeLookupArgs = (void*)ObjectToHandle(entity);
|
||||
|
||||
lookup.runtimeLookup.indirectFirstOffset = false;
|
||||
lookup.runtimeLookup.indirectSecondOffset = false;
|
||||
|
||||
// For R2R compilations, we don't generate the dictionary lookup signatures (dictionary lookups are done in a
|
||||
// different way that is more version resilient... plus we can't have pointers to existing MTs/MDs in the sigs)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -246,36 +248,9 @@ namespace Internal.JitInterface
|
|||
MethodDesc targetMethod = HandleToObject(pTargetMethod.hMethod);
|
||||
TypeDesc delegateTypeDesc = HandleToObject(delegateType);
|
||||
|
||||
if (targetMethod.IsSharedByGenericInstantiations)
|
||||
{
|
||||
// If the method is not exact, fetch it as a runtime determined method.
|
||||
targetMethod = (MethodDesc)GetRuntimeDeterminedObjectForToken(ref pTargetMethod);
|
||||
}
|
||||
|
||||
/* TODO
|
||||
bool isLdvirtftn = pTargetMethod.tokenType == CorInfoTokenKind.CORINFO_TOKENKIND_Ldvirtftn;
|
||||
DelegateCreationInfo delegateInfo = _compilation.GetDelegateCtor(delegateTypeDesc, targetMethod, isLdvirtftn);
|
||||
|
||||
if (delegateInfo.NeedsRuntimeLookup)
|
||||
{
|
||||
pLookup.lookupKind.needsRuntimeLookup = true;
|
||||
|
||||
MethodDesc contextMethod = methodFromContext(pTargetMethod.tokenContext);
|
||||
|
||||
// We should not be inlining these. RyuJIT should have aborted inlining already.
|
||||
Debug.Assert(contextMethod == MethodBeingCompiled);
|
||||
|
||||
pLookup.lookupKind.runtimeLookupKind = GetGenericRuntimeLookupKind(contextMethod);
|
||||
pLookup.lookupKind.runtimeLookupFlags = (ushort)ReadyToRunHelperId.DelegateCtor;
|
||||
pLookup.lookupKind.runtimeLookupArgs = (void*)ObjectToHandle(delegateInfo);
|
||||
}
|
||||
else
|
||||
*/
|
||||
{
|
||||
pLookup.lookupKind.needsRuntimeLookup = false;
|
||||
pLookup.constLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.DelegateCtor(
|
||||
pLookup.lookupKind.needsRuntimeLookup = false;
|
||||
pLookup.constLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.DelegateCtor(
|
||||
delegateTypeDesc, targetMethod, new ModuleToken(_tokenContext, (mdToken)pTargetMethod.token), _signatureContext));
|
||||
}
|
||||
}
|
||||
|
||||
private ISymbolNode GetHelperFtnUncached(CorInfoHelpFunc ftnNum)
|
||||
|
@ -338,6 +313,24 @@ namespace Internal.JitInterface
|
|||
id = ReadyToRunHelper.Ldelema_Ref;
|
||||
break;
|
||||
|
||||
|
||||
case CorInfoHelpFunc.CORINFO_HELP_GETGENERICS_GCSTATIC_BASE:
|
||||
id = ReadyToRunHelper.GenericGcStaticBase;
|
||||
break;
|
||||
|
||||
case CorInfoHelpFunc.CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE:
|
||||
id = ReadyToRunHelper.GenericNonGcStaticBase;
|
||||
break;
|
||||
|
||||
case CorInfoHelpFunc.CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE:
|
||||
id = ReadyToRunHelper.GenericGcTlsBase;
|
||||
break;
|
||||
|
||||
case CorInfoHelpFunc.CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE:
|
||||
id = ReadyToRunHelper.GenericNonGcTlsBase;
|
||||
break;
|
||||
|
||||
|
||||
case CorInfoHelpFunc.CORINFO_HELP_MEMSET:
|
||||
id = ReadyToRunHelper.MemSet;
|
||||
break;
|
||||
|
|
|
@ -1983,6 +1983,21 @@ namespace Internal.JitInterface
|
|||
else if (field.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any))
|
||||
{
|
||||
// The JIT wants to know how to access a static field on a generic type. We need a runtime lookup.
|
||||
#if READYTORUN
|
||||
fieldAccessor = CORINFO_FIELD_ACCESSOR.CORINFO_FIELD_STATIC_GENERICS_STATIC_HELPER;
|
||||
if (field.IsThreadStatic)
|
||||
{
|
||||
pResult->helper = (field.HasGCStaticBase ?
|
||||
CorInfoHelpFunc.CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE:
|
||||
CorInfoHelpFunc.CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE);
|
||||
}
|
||||
else
|
||||
{
|
||||
pResult->helper = (field.HasGCStaticBase ?
|
||||
CorInfoHelpFunc.CORINFO_HELP_GETGENERICS_GCSTATIC_BASE:
|
||||
CorInfoHelpFunc.CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE);
|
||||
}
|
||||
#else
|
||||
fieldAccessor = CORINFO_FIELD_ACCESSOR.CORINFO_FIELD_STATIC_READYTORUN_HELPER;
|
||||
pResult->helper = CorInfoHelpFunc.CORINFO_HELP_READYTORUN_GENERIC_STATIC_BASE;
|
||||
|
||||
|
@ -1998,18 +2013,7 @@ namespace Internal.JitInterface
|
|||
// Find out what kind of base do we need to look up.
|
||||
if (field.IsThreadStatic)
|
||||
{
|
||||
#if READYTORUN
|
||||
if (field.HasGCStaticBase)
|
||||
{
|
||||
helperId = ReadyToRunHelperId.GetThreadStaticBase;
|
||||
}
|
||||
else
|
||||
{
|
||||
helperId = ReadyToRunHelperId.GetThreadNonGcStaticBase;
|
||||
}
|
||||
#else
|
||||
helperId = ReadyToRunHelperId.GetThreadStaticBase;
|
||||
#endif
|
||||
}
|
||||
else if (field.HasGCStaticBase)
|
||||
{
|
||||
|
@ -2036,6 +2040,7 @@ namespace Internal.JitInterface
|
|||
|
||||
pResult->fieldLookup = CreateConstLookupToSymbol(helper);
|
||||
}
|
||||
#endif // READYTORUN
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2553,9 +2558,9 @@ namespace Internal.JitInterface
|
|||
{
|
||||
Debug.Assert(fEmbedParent);
|
||||
|
||||
if (obj is MethodDesc)
|
||||
if (obj is MethodDesc objAsMethod)
|
||||
{
|
||||
target = ((MethodDesc)obj).OwningType;
|
||||
target = objAsMethod.OwningType;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2587,7 +2592,7 @@ namespace Internal.JitInterface
|
|||
}
|
||||
|
||||
Debug.Assert(pResult.compileTimeHandle != null);
|
||||
|
||||
|
||||
ComputeLookup(ref pResolvedToken, target, helperId, ref pResult.lookup);
|
||||
}
|
||||
|
||||
|
|
|
@ -697,6 +697,80 @@ internal class Program
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
class MyGen<T>
|
||||
{
|
||||
public static string GcValue;
|
||||
public static int NonGcValue;
|
||||
[ThreadStatic]
|
||||
public static string TlsGcValue;
|
||||
[ThreadStatic]
|
||||
public static int TlsNonGcValue;
|
||||
}
|
||||
|
||||
private static void SetGenericGcStatic<U, V>(string uValue, string vValue)
|
||||
{
|
||||
MyGen<U>.GcValue = uValue;
|
||||
MyGen<V>.GcValue = vValue;
|
||||
}
|
||||
|
||||
private static void SetGenericNonGcStatic<U, V>(int uValue, int vValue)
|
||||
{
|
||||
MyGen<U>.NonGcValue = uValue;
|
||||
MyGen<V>.NonGcValue = vValue;
|
||||
}
|
||||
|
||||
private static void SetGenericTlsGcStatic<U, V>(string uValue, string vValue)
|
||||
{
|
||||
MyGen<U>.TlsGcValue = uValue;
|
||||
MyGen<V>.TlsGcValue = vValue;
|
||||
}
|
||||
|
||||
private static void SetGenericTlsNonGcStatic<U, V>(int uValue, int vValue)
|
||||
{
|
||||
MyGen<U>.TlsNonGcValue = uValue;
|
||||
MyGen<V>.TlsNonGcValue = vValue;
|
||||
}
|
||||
|
||||
private static bool SharedGenericGcStaticTest()
|
||||
{
|
||||
string objectValue = "Hello";
|
||||
string stringValue = "World";
|
||||
SetGenericGcStatic<object, string>(objectValue, stringValue);
|
||||
Console.WriteLine("Object GC value: {0}, expected {1}", MyGen<object>.GcValue, objectValue);
|
||||
Console.WriteLine("String GC value: {0}, expected {1}", MyGen<string>.GcValue, stringValue);
|
||||
return MyGen<object>.GcValue == objectValue && MyGen<string>.GcValue == stringValue;
|
||||
}
|
||||
|
||||
private static bool SharedGenericNonGcStaticTest()
|
||||
{
|
||||
int objectValue = 42;
|
||||
int stringValue = 666;
|
||||
SetGenericNonGcStatic<object, string>(objectValue, stringValue);
|
||||
Console.WriteLine("Object non-GC value: {0}, expected {1}", MyGen<object>.NonGcValue, objectValue);
|
||||
Console.WriteLine("String non-GC value: {0}, expected {1}", MyGen<string>.NonGcValue, stringValue);
|
||||
return MyGen<object>.NonGcValue == objectValue && MyGen<string>.NonGcValue == stringValue;
|
||||
}
|
||||
|
||||
private static bool SharedGenericTlsGcStaticTest()
|
||||
{
|
||||
string objectValue = "Cpaot";
|
||||
string stringValue = "Rules";
|
||||
SetGenericTlsGcStatic<object, string>(objectValue, stringValue);
|
||||
Console.WriteLine("Object TLS GC value: {0}, expected {1}", MyGen<object>.TlsGcValue, objectValue);
|
||||
Console.WriteLine("String TLS GC value: {0}, expected {1}", MyGen<string>.TlsGcValue, stringValue);
|
||||
return MyGen<object>.TlsGcValue == objectValue && MyGen<string>.TlsGcValue == stringValue;
|
||||
}
|
||||
|
||||
private static bool SharedGenericTlsNonGcStaticTest()
|
||||
{
|
||||
int objectValue = 1234;
|
||||
int stringValue = 5678;
|
||||
SetGenericTlsNonGcStatic<object, string>(objectValue, stringValue);
|
||||
Console.WriteLine("Object TLS non-GC value: {0}, expected {1}", MyGen<object>.TlsNonGcValue, objectValue);
|
||||
Console.WriteLine("String TLS non-GC value: {0}, expected {1}", MyGen<string>.TlsNonGcValue, stringValue);
|
||||
return MyGen<object>.TlsNonGcValue == objectValue && MyGen<string>.TlsNonGcValue == stringValue;
|
||||
}
|
||||
|
||||
static bool RVAFieldTest()
|
||||
{
|
||||
|
@ -764,6 +838,10 @@ internal class Program
|
|||
RunTest("VectorTest", VectorTest());
|
||||
RunTest("EnumHashValueTest", EnumHashValueTest());
|
||||
RunTest("RVAFieldTest", RVAFieldTest());
|
||||
RunTest("SharedGenericGcStaticTest", SharedGenericGcStaticTest());
|
||||
RunTest("SharedGenericNonGcStaticTest", SharedGenericNonGcStaticTest());
|
||||
RunTest("SharedGenericTlsGcStaticTest", SharedGenericTlsGcStaticTest());
|
||||
RunTest("SharedGenericTlsNonGcStaticTest", SharedGenericTlsNonGcStaticTest());
|
||||
|
||||
Console.WriteLine($@"{_passedTests.Count} tests pass:");
|
||||
foreach (string testName in _passedTests)
|
||||
|
|
Загрузка…
Ссылка в новой задаче