public override int GetSlotForEntry(GenericLookupResult entry) { int index = Array.IndexOf(_layout, entry); Debug.Assert(index >= 0); return(index); }
public int Compare(GenericLookupResult x, GenericLookupResult y) { if (x == y) { return(0); } int codeX = x.ClassCode; int codeY = y.ClassCode; if (codeX == codeY) { Debug.Assert(x.GetType() == y.GetType()); int result = x.CompareToImpl(y, _comparer); // We did a reference equality check above so an "Equal" result is not expected Debug.Assert(result != 0); return(result); } else { Debug.Assert(x.GetType() != y.GetType()); return(codeX > codeY ? -1 : 1); } }
public ReadyToRunGenericHelperNode(NodeFactory factory, ReadyToRunHelperId helperId, object target, TypeSystemEntity dictionaryOwner) { _id = helperId; _dictionaryOwner = dictionaryOwner; _target = target; _lookupSignature = GetLookupSignature(factory, helperId, target); }
public void DeferFloatingGenericLookup(GenericLookupResult lookupResult) { if (_floatingGenericLookupResults == null) { _floatingGenericLookupResults = new HashSet <GenericLookupResult>(); } _floatingGenericLookupResults.Add(lookupResult); }
public override void EnsureEntry(GenericLookupResult entry) { int index = Array.IndexOf(_layout, entry); if (index == -1) { // Using EnsureEntry to add a slot to a PrecomputedDictionaryLayoutNode is not supported throw new NotSupportedException(); } }
protected override int CompareToImpl(GenericLookupResult other, TypeSystemComparer comparer) { var otherEntry = (MethodEntryGenericLookupResult)other; int result = (_isUnboxingThunk ? 1 : 0) - (otherEntry._isUnboxingThunk ? 1 : 0); if (result != 0) { return(result); } return(comparer.Compare(_method, otherEntry._method)); }
protected override int CompareToImpl(GenericLookupResult other, TypeSystemComparer comparer) { var otherEntry = (CallingConventionConverterLookupResult)other; int result = (int)(_callingConventionConverter.ConverterKind - otherEntry._callingConventionConverter.ConverterKind); if (result != 0) { return(result); } return(comparer.Compare(_callingConventionConverter.Signature, otherEntry._callingConventionConverter.Signature)); }
public virtual int GetSlotForEntry(GenericLookupResult entry) { if (_layout == null) { ComputeLayout(); } int index = Array.IndexOf(_layout, entry); Debug.Assert(index >= 0); return(index); }
public GenericLookupDescriptor(TypeSystemEntity canonicalOwner, GenericLookupResult signature) { // Owner should be a canonical type or canonical method Debug.Assert(( canonicalOwner is TypeDesc && ((TypeDesc)canonicalOwner).IsCanonicalSubtype(CanonicalFormKind.Any)) || (canonicalOwner is MethodDesc && ((MethodDesc)canonicalOwner).HasInstantiation && ((MethodDesc)canonicalOwner).IsSharedByGenericInstantiations)); CanonicalOwner = canonicalOwner; Signature = signature; }
private void ComputeLayout() { // TODO: deterministic ordering GenericLookupResult[] layout = new GenericLookupResult[_entries.Count]; int index = 0; foreach (GenericLookupResult entry in EntryHashTable.Enumerator.Get(_entries)) { layout[index++] = entry; } // Only publish after the full layout is computed. Races are fine. _layout = layout; }
public override int GetSlotForEntry(GenericLookupResult entry) { int index = Array.IndexOf(_layout, entry); // This entry wasn't precomputed. If this is an optimized build with scanner, it might suggest // the scanner didn't see the need for this. There is a discrepancy between scanning and compiling. // This is a fatal error to prevent bad codegen. if (index < 0) { throw new InvalidOperationException($"{OwningMethodOrType}: {entry}"); } return(index); }
private void ComputeLayout() { GenericLookupResult[] layout = new GenericLookupResult[_entries.Count]; int index = 0; foreach (GenericLookupResult entry in EntryHashTable.Enumerator.Get(_entries)) { layout[index++] = entry; } var comparer = new GenericLookupResult.Comparer(new TypeSystemComparer()); Array.Sort(layout, comparer.Compare); // Only publish after the full layout is computed. Races are fine. _layout = layout; }
protected void EmitDictionaryLookup(NodeFactory factory, ref X64Emitter encoder, Register context, Register result, GenericLookupResult lookup, bool relocsOnly) { // INVARIANT: must not trash context register // Find the generic dictionary slot int dictionarySlot = 0; if (!relocsOnly) { // The concrete slot won't be known until we're emitting data - don't ask for it in relocsOnly. dictionarySlot = factory.GenericDictionaryLayout(_dictionaryOwner).GetSlotForEntry(lookup); } // Load the generic dictionary cell AddrMode loadEntry = new AddrMode( context, null, dictionarySlot * factory.Target.PointerSize, 0, AddrModeSize.Int64); encoder.EmitMOV(result, ref loadEntry); }
public override int GetSlotForEntry(GenericLookupResult entry) { int index; lock (thisLock) { if (!_entryslots.TryGetValue(entry, out index)) { _layout.Add(entry); index = _layout.Count - 1; _entryslots.Add(entry, index); } } Debug.Assert(index >= 0); return(index); }
protected override int CompareToImpl(GenericLookupResult other, TypeSystemComparer comparer) { var otherResult = (ConstrainedMethodUseLookupResult)other; int result = (_directCall ? 1 : 0) - (otherResult._directCall ? 1 : 0); if (result != 0) { return(result); } result = comparer.Compare(_constraintType, otherResult._constraintType); if (result != 0) { return(result); } return(comparer.Compare(_constrainedMethod, otherResult._constrainedMethod)); }
public override int GetSlotForEntry(GenericLookupResult entry) { if (_layout == null) { ComputeLayout(); } int index = Array.IndexOf(_layout, entry); // We never called EnsureEntry on this during compilation? // This is a fatal error to prevent bad codegen. if (index < 0) { throw new InvalidOperationException($"{OwningMethodOrType}: {entry}"); } return(index); }
public override IEnumerable <CombinedDependencyListEntry> GetConditionalStaticDependencies(NodeFactory factory) { if (!factory.MetadataManager.SupportsReflection) { return(Array.Empty <CombinedDependencyListEntry>()); } List <CombinedDependencyListEntry> conditionalDependencies = new List <CombinedDependencyListEntry>(); NativeLayoutSavedVertexNode templateLayout; if (_dictionaryOwner is MethodDesc) { templateLayout = factory.NativeLayout.TemplateMethodLayout((MethodDesc)_dictionaryOwner); conditionalDependencies.Add(new CombinedDependencyListEntry(_lookupSignature.TemplateDictionaryNode(factory), templateLayout, "Type loader template")); } else { templateLayout = factory.NativeLayout.TemplateTypeLayout((TypeDesc)_dictionaryOwner); conditionalDependencies.Add(new CombinedDependencyListEntry(_lookupSignature.TemplateDictionaryNode(factory), templateLayout, "Type loader template")); } if (_id == ReadyToRunHelperId.GetGCStaticBase || _id == ReadyToRunHelperId.GetThreadStaticBase) { // If the type has a lazy static constructor, we also need the non-GC static base to be available as // a template dictionary node. TypeDesc type = (TypeDesc)_target; Debug.Assert(templateLayout != null); if (factory.TypeSystemContext.HasLazyStaticConstructor(type)) { GenericLookupResult nonGcRegionLookup = factory.GenericLookup.TypeNonGCStaticBase(type); conditionalDependencies.Add(new CombinedDependencyListEntry(nonGcRegionLookup.TemplateDictionaryNode(factory), templateLayout, "Type loader template")); } } return(conditionalDependencies); }
public override void EnsureEntry(GenericLookupResult lookupResult) => throw new NotImplementedException();
protected void EmitDictionaryLookup(NodeFactory factory, ref X64Emitter encoder, Register context, Register result, GenericLookupResult lookup, bool relocsOnly) { // INVARIANT: must not trash context register // Find the generic dictionary slot int dictionarySlot = 0; if (!relocsOnly) { // The concrete slot won't be known until we're emitting data - don't ask for it in relocsOnly. dictionarySlot = factory.GenericDictionaryLayout(_dictionaryOwner).GetSlotForEntry(lookup); } // Load the generic dictionary cell AddrMode loadEntry = new AddrMode( context, null, dictionarySlot * factory.Target.PointerSize, 0, AddrModeSize.Int64); encoder.EmitMOV(result, ref loadEntry); // If there's any invalid entries, we need to test for them // // Only do this in relocsOnly to make it easier to weed out bugs - the _hasInvalidEntries // flag can change over the course of compilation and the bad slot helper dependency // should be reported by someone else - the system should not rely on it coming from here. if (!relocsOnly && _hasInvalidEntries) { encoder.EmitCompareToZero(result); encoder.EmitJE(GetBadSlotHelper(factory)); } switch (lookup.LookupResultReferenceType(factory)) { case GenericLookupResultReferenceType.Indirect: // Do another indirection loadEntry = new AddrMode(result, null, 0, 0, AddrModeSize.Int64); encoder.EmitMOV(result, ref loadEntry); break; case GenericLookupResultReferenceType.ConditionalIndirect: // Test result, 0x1 // JEQ L1 // mov result, [result-1] // L1: throw new NotImplementedException(); default: break; } }
protected sealed override void EmitCode(NodeFactory factory, ref X64Emitter encoder, bool relocsOnly) { // First load the generic context into the context register. EmitLoadGenericContext(factory, ref encoder, relocsOnly); Register contextRegister = GetContextRegister(ref encoder); switch (_id) { case ReadyToRunHelperId.GetNonGCStaticBase: { Debug.Assert(contextRegister == encoder.TargetRegister.Arg0); MetadataType target = (MetadataType)_target; if (!factory.TypeSystemContext.HasLazyStaticConstructor(target)) { EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg0, encoder.TargetRegister.Result, _lookupSignature, relocsOnly); encoder.EmitRET(); } else { EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg0, encoder.TargetRegister.Arg0, _lookupSignature, relocsOnly); encoder.EmitMOV(encoder.TargetRegister.Result, encoder.TargetRegister.Arg0); // We need to trigger the cctor before returning the base. It is stored at the beginning of the non-GC statics region. int cctorContextSize = NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target); AddrMode initialized = new AddrMode(encoder.TargetRegister.Arg0, null, factory.Target.PointerSize - cctorContextSize, 0, AddrModeSize.Int32); encoder.EmitCMP(ref initialized, 1); encoder.EmitRETIfEqual(); AddrMode loadCctor = new AddrMode(encoder.TargetRegister.Arg0, null, -cctorContextSize, 0, AddrModeSize.Int64); encoder.EmitLEA(encoder.TargetRegister.Arg0, ref loadCctor); encoder.EmitMOV(encoder.TargetRegister.Arg1, encoder.TargetRegister.Result); encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnNonGCStaticBase)); } } break; case ReadyToRunHelperId.GetGCStaticBase: { Debug.Assert(contextRegister == encoder.TargetRegister.Arg0); MetadataType target = (MetadataType)_target; EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg0, encoder.TargetRegister.Result, _lookupSignature, relocsOnly); AddrMode loadFromResult = new AddrMode(encoder.TargetRegister.Result, null, 0, 0, AddrModeSize.Int64); encoder.EmitMOV(encoder.TargetRegister.Result, ref loadFromResult); encoder.EmitMOV(encoder.TargetRegister.Result, ref loadFromResult); if (!factory.TypeSystemContext.HasLazyStaticConstructor(target)) { encoder.EmitRET(); } else { // We need to trigger the cctor before returning the base. It is stored at the beginning of the non-GC statics region. GenericLookupResult nonGcRegionLookup = factory.GenericLookup.TypeNonGCStaticBase(target); EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg0, encoder.TargetRegister.Arg0, nonGcRegionLookup, relocsOnly); int cctorContextSize = NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target); AddrMode initialized = new AddrMode(encoder.TargetRegister.Arg0, null, factory.Target.PointerSize - cctorContextSize, 0, AddrModeSize.Int32); encoder.EmitCMP(ref initialized, 1); encoder.EmitRETIfEqual(); encoder.EmitMOV(encoder.TargetRegister.Arg1, encoder.TargetRegister.Result); AddrMode loadCctor = new AddrMode(encoder.TargetRegister.Arg0, null, -cctorContextSize, 0, AddrModeSize.Int64); encoder.EmitLEA(encoder.TargetRegister.Arg0, ref loadCctor); encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnGCStaticBase)); } } break; case ReadyToRunHelperId.GetThreadStaticBase: { Debug.Assert(contextRegister == encoder.TargetRegister.Arg0); MetadataType target = (MetadataType)_target; // Look up the index cell EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg0, encoder.TargetRegister.Arg1, _lookupSignature, relocsOnly); ISymbolNode helperEntrypoint; if (factory.TypeSystemContext.HasLazyStaticConstructor(target)) { // There is a lazy class constructor. We need the non-GC static base because that's where the // class constructor context lives. GenericLookupResult nonGcRegionLookup = factory.GenericLookup.TypeNonGCStaticBase(target); EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg0, encoder.TargetRegister.Arg2, nonGcRegionLookup, relocsOnly); int cctorContextSize = NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target); AddrMode loadCctor = new AddrMode(encoder.TargetRegister.Arg2, null, -cctorContextSize, 0, AddrModeSize.Int64); encoder.EmitLEA(encoder.TargetRegister.Arg2, ref loadCctor); helperEntrypoint = factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnThreadStaticBase); } else { helperEntrypoint = factory.HelperEntrypoint(HelperEntrypoint.GetThreadStaticBaseForType); } // First arg: address of the TypeManager slot that provides the helper with // information about module index and the type manager instance (which is used // for initialization on first access). AddrMode loadFromArg1 = new AddrMode(encoder.TargetRegister.Arg1, null, 0, 0, AddrModeSize.Int64); encoder.EmitMOV(encoder.TargetRegister.Arg0, ref loadFromArg1); // Second arg: index of the type in the ThreadStatic section of the modules AddrMode loadFromArg1AndDelta = new AddrMode(encoder.TargetRegister.Arg1, null, factory.Target.PointerSize, 0, AddrModeSize.Int64); encoder.EmitMOV(encoder.TargetRegister.Arg1, ref loadFromArg1AndDelta); encoder.EmitJMP(helperEntrypoint); } break; case ReadyToRunHelperId.DelegateCtor: { // This is a weird helper. Codegen populated Arg0 and Arg1 with the values that the constructor // method expects. Codegen also passed us the generic context in Arg2. // We now need to load the delegate target method into Arg2 (using a dictionary lookup) // and the optional 4th parameter, and call the ctor. Debug.Assert(contextRegister == encoder.TargetRegister.Arg2); var target = (DelegateCreationInfo)_target; EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg2, encoder.TargetRegister.Arg2, _lookupSignature, relocsOnly); if (target.Thunk != null) { Debug.Assert(target.Constructor.Method.Signature.Length == 3); encoder.EmitLEAQ(encoder.TargetRegister.Arg3, target.Thunk); } else { Debug.Assert(target.Constructor.Method.Signature.Length == 2); } encoder.EmitJMP(target.Constructor); } break; // These are all simple: just get the thing from the dictionary and we're done case ReadyToRunHelperId.TypeHandle: case ReadyToRunHelperId.MethodHandle: case ReadyToRunHelperId.FieldHandle: case ReadyToRunHelperId.MethodDictionary: case ReadyToRunHelperId.MethodEntry: case ReadyToRunHelperId.VirtualDispatchCell: case ReadyToRunHelperId.DefaultConstructor: case ReadyToRunHelperId.ObjectAllocator: case ReadyToRunHelperId.TypeHandleForCasting: { EmitDictionaryLookup(factory, ref encoder, contextRegister, encoder.TargetRegister.Result, _lookupSignature, relocsOnly); encoder.EmitRET(); } break; default: throw new NotImplementedException(); } }
protected void EmitDictionaryLookup(NodeFactory factory, ref X64Emitter encoder, Register context, Register result, GenericLookupResult lookup, bool relocsOnly) { // INVARIANT: must not trash context register // Find the generic dictionary slot int dictionarySlot = 0; if (!relocsOnly) { // The concrete slot won't be known until we're emitting data - don't ask for it in relocsOnly. dictionarySlot = factory.GenericDictionaryLayout(_dictionaryOwner).GetSlotForEntry(lookup); } // Load the generic dictionary cell AddrMode loadEntry = new AddrMode( context, null, dictionarySlot * factory.Target.PointerSize, 0, AddrModeSize.Int64); encoder.EmitMOV(result, ref loadEntry); switch (lookup.LookupResultReferenceType(factory)) { case GenericLookupResultReferenceType.Indirect: // Do another indirection loadEntry = new AddrMode(result, null, 0, 0, AddrModeSize.Int64); encoder.EmitMOV(result, ref loadEntry); break; case GenericLookupResultReferenceType.ConditionalIndirect: // Test result, 0x1 // JEQ L1 // mov result, [result-1] // L1: throw new NotImplementedException(); default: break; } }
public abstract int GetSlotForEntry(GenericLookupResult entry);
protected sealed override void EmitCode(NodeFactory factory, ref X64Emitter encoder, bool relocsOnly) { // First load the generic context into Arg0. EmitLoadGenericContext(factory, ref encoder, relocsOnly); switch (_id) { case ReadyToRunHelperId.GetNonGCStaticBase: { MetadataType target = (MetadataType)_target; if (!factory.TypeSystemContext.HasLazyStaticConstructor(target)) { EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg0, encoder.TargetRegister.Result, _lookupSignature, relocsOnly); encoder.EmitRET(); } else { EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg0, encoder.TargetRegister.Arg0, _lookupSignature, relocsOnly); encoder.EmitMOV(encoder.TargetRegister.Result, encoder.TargetRegister.Arg0); // We need to trigger the cctor before returning the base. It is stored at the beginning of the non-GC statics region. int cctorContextSize = NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target); AddrMode initialized = new AddrMode(encoder.TargetRegister.Arg0, null, factory.Target.PointerSize - cctorContextSize, 0, AddrModeSize.Int32); encoder.EmitCMP(ref initialized, 1); encoder.EmitRETIfEqual(); AddrMode loadCctor = new AddrMode(encoder.TargetRegister.Arg0, null, -cctorContextSize, 0, AddrModeSize.Int64); encoder.EmitLEA(encoder.TargetRegister.Arg0, ref loadCctor); encoder.EmitMOV(encoder.TargetRegister.Arg1, encoder.TargetRegister.Result); encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnNonGCStaticBase)); } } break; case ReadyToRunHelperId.GetGCStaticBase: { MetadataType target = (MetadataType)_target; EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg0, encoder.TargetRegister.Result, _lookupSignature, relocsOnly); AddrMode loadFromResult = new AddrMode(encoder.TargetRegister.Result, null, 0, 0, AddrModeSize.Int64); encoder.EmitMOV(encoder.TargetRegister.Result, ref loadFromResult); encoder.EmitMOV(encoder.TargetRegister.Result, ref loadFromResult); if (!factory.TypeSystemContext.HasLazyStaticConstructor(target)) { encoder.EmitRET(); } else { // We need to trigger the cctor before returning the base. It is stored at the beginning of the non-GC statics region. GenericLookupResult nonGcRegionLookup = factory.GenericLookup.TypeNonGCStaticBase(target); EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg0, encoder.TargetRegister.Arg0, nonGcRegionLookup, relocsOnly); int cctorContextSize = NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target); AddrMode initialized = new AddrMode(encoder.TargetRegister.Arg0, null, factory.Target.PointerSize - cctorContextSize, 0, AddrModeSize.Int32); encoder.EmitCMP(ref initialized, 1); encoder.EmitRETIfEqual(); encoder.EmitMOV(encoder.TargetRegister.Arg1, encoder.TargetRegister.Result); AddrMode loadCctor = new AddrMode(encoder.TargetRegister.Arg0, null, -cctorContextSize, 0, AddrModeSize.Int64); encoder.EmitLEA(encoder.TargetRegister.Arg0, ref loadCctor); encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnGCStaticBase)); } } break; case ReadyToRunHelperId.GetThreadStaticBase: { MetadataType target = (MetadataType)_target; // Look up the index cell EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg0, encoder.TargetRegister.Arg1, _lookupSignature, relocsOnly); ISymbolNode helperEntrypoint; if (factory.TypeSystemContext.HasLazyStaticConstructor(target)) { // There is a lazy class constructor. We need the non-GC static base because that's where the // class constructor context lives. GenericLookupResult nonGcRegionLookup = factory.GenericLookup.TypeNonGCStaticBase(target); EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg0, encoder.TargetRegister.Arg2, nonGcRegionLookup, relocsOnly); int cctorContextSize = NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target); AddrMode loadCctor = new AddrMode(encoder.TargetRegister.Arg2, null, -cctorContextSize, 0, AddrModeSize.Int64); encoder.EmitLEA(encoder.TargetRegister.Arg2, ref loadCctor); helperEntrypoint = factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnThreadStaticBase); } else { helperEntrypoint = factory.HelperEntrypoint(HelperEntrypoint.GetThreadStaticBaseForType); } // First arg: address of the TypeManager slot that provides the helper with // information about module index and the type manager instance (which is used // for initialization on first access). AddrMode loadFromArg1 = new AddrMode(encoder.TargetRegister.Arg1, null, 0, 0, AddrModeSize.Int64); encoder.EmitMOV(encoder.TargetRegister.Arg0, ref loadFromArg1); // Second arg: index of the type in the ThreadStatic section of the modules AddrMode loadFromArg1AndDelta = new AddrMode(encoder.TargetRegister.Arg1, null, factory.Target.PointerSize, 0, AddrModeSize.Int64); encoder.EmitMOV(encoder.TargetRegister.Arg1, ref loadFromArg1AndDelta); encoder.EmitJMP(helperEntrypoint); } break; // These are all simple: just get the thing from the dictionary and we're done case ReadyToRunHelperId.TypeHandle: case ReadyToRunHelperId.MethodHandle: case ReadyToRunHelperId.FieldHandle: case ReadyToRunHelperId.MethodDictionary: case ReadyToRunHelperId.VirtualCall: case ReadyToRunHelperId.ResolveVirtualFunction: case ReadyToRunHelperId.MethodEntry: { EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg0, encoder.TargetRegister.Result, _lookupSignature, relocsOnly); encoder.EmitRET(); } break; default: throw new NotImplementedException(); } }
public override int GetSlotForEntry(GenericLookupResult entry) => throw new NotImplementedException();
protected sealed override void EmitCode(NodeFactory factory, ref X64Emitter encoder, bool relocsOnly) { // First load the generic context into Arg0. EmitLoadGenericContext(factory, ref encoder, relocsOnly); switch (_id) { case ReadyToRunHelperId.GetNonGCStaticBase: { MetadataType target = (MetadataType)_target; if (!factory.TypeSystemContext.HasLazyStaticConstructor(target)) { EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg0, encoder.TargetRegister.Result, _lookupSignature, relocsOnly); encoder.EmitRET(); } else { EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg0, encoder.TargetRegister.Arg0, _lookupSignature, relocsOnly); // We need to trigger the cctor before returning the base. It is stored at the beginning of the non-GC statics region. int cctorContextSize = NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target); AddrMode loadBase = new AddrMode(encoder.TargetRegister.Arg0, null, cctorContextSize, 0, AddrModeSize.Int64); encoder.EmitLEA(encoder.TargetRegister.Result, ref loadBase); AddrMode initialized = new AddrMode(encoder.TargetRegister.Arg0, null, factory.Target.PointerSize, 0, AddrModeSize.Int32); encoder.EmitCMP(ref initialized, 1); encoder.EmitRETIfEqual(); encoder.EmitMOV(encoder.TargetRegister.Arg1, encoder.TargetRegister.Result); encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnNonGCStaticBase)); } } break; case ReadyToRunHelperId.GetGCStaticBase: { MetadataType target = (MetadataType)_target; EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg0, encoder.TargetRegister.Result, _lookupSignature, relocsOnly); AddrMode loadFromResult = new AddrMode(encoder.TargetRegister.Result, null, 0, 0, AddrModeSize.Int64); encoder.EmitMOV(encoder.TargetRegister.Result, ref loadFromResult); encoder.EmitMOV(encoder.TargetRegister.Result, ref loadFromResult); if (!factory.TypeSystemContext.HasLazyStaticConstructor(target)) { encoder.EmitRET(); } else { // We need to trigger the cctor before returning the base. It is stored at the beginning of the non-GC statics region. GenericLookupResult nonGcRegionLookup = factory.GenericLookup.TypeNonGCStaticBase(target); EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg0, encoder.TargetRegister.Arg0, nonGcRegionLookup, relocsOnly); AddrMode initialized = new AddrMode(encoder.TargetRegister.Arg0, null, factory.Target.PointerSize, 0, AddrModeSize.Int32); encoder.EmitCMP(ref initialized, 1); encoder.EmitRETIfEqual(); encoder.EmitMOV(encoder.TargetRegister.Arg1, encoder.TargetRegister.Result); encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnGCStaticBase)); } } break; // These are all simple: just get the thing from the dictionary and we're done case ReadyToRunHelperId.TypeHandle: case ReadyToRunHelperId.MethodDictionary: case ReadyToRunHelperId.VirtualCall: case ReadyToRunHelperId.ResolveVirtualFunction: case ReadyToRunHelperId.MethodEntry: { EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg0, encoder.TargetRegister.Result, _lookupSignature, relocsOnly); encoder.EmitRET(); } break; default: throw new NotImplementedException(); } }
private LLVMValueRef OutputCodeForDictionaryLookup(LLVMBuilderRef builder, NodeFactory factory, ReadyToRunGenericHelperNode node, GenericLookupResult lookup, LLVMValueRef ctx, string gepName) { // Find the generic dictionary slot int dictionarySlot = factory.GenericDictionaryLayout(node.DictionaryOwner).GetSlotForEntry(lookup); int offset = dictionarySlot * factory.Target.PointerSize; // Load the generic dictionary cell LLVMValueRef retGep = builder.BuildGEP(ctx, new[] { LLVMValueRef.CreateConstInt(LLVMTypeRef.Int32, (ulong)offset, false) }, "retGep"); LLVMValueRef castGep = builder.BuildBitCast(retGep, LLVMTypeRef.CreatePointer(LLVMTypeRef.CreatePointer(LLVMTypeRef.Int8, 0), 0), "ptrPtr"); LLVMValueRef retRef = builder.BuildLoad(castGep, gepName); switch (lookup.LookupResultReferenceType(factory)) { case GenericLookupResultReferenceType.Indirect: var ptrPtr = builder.BuildBitCast(retRef, LLVMTypeRef.CreatePointer(LLVMTypeRef.CreatePointer(LLVMTypeRef.Int8, 0), 0), "ptrPtr"); retRef = builder.BuildLoad(ptrPtr, "indLoad"); break; case GenericLookupResultReferenceType.ConditionalIndirect: throw new NotImplementedException(); default: break; } return(retRef); }
public void EnsureEntry(GenericLookupResult entry) { Debug.Assert(_layout == null, "Trying to add entry but layout already computed"); _entries.AddOrGetExisting(entry); }
protected void EmitDictionaryLookup(NodeFactory factory, ref ARM64Emitter encoder, Register context, Register result, GenericLookupResult lookup, bool relocsOnly) { throw new NotImplementedException(); }
private void GetCodeForReadyToRunGenericHelper(WebAssemblyCodegenCompilation compilation, ReadyToRunGenericHelperNode node, NodeFactory factory) { LLVMBuilderRef builder = compilation.Module.Context.CreateBuilder(); var args = new List <LLVMTypeRef>(); MethodDesc delegateCtor = null; if (node.Id == ReadyToRunHelperId.DelegateCtor) { DelegateCreationInfo target = (DelegateCreationInfo)node.Target; delegateCtor = target.Constructor.Method; bool isStatic = delegateCtor.Signature.IsStatic; int argCount = delegateCtor.Signature.Length; if (!isStatic) { argCount++; } for (int i = 0; i < argCount; i++) { TypeDesc argType; if (i == 0 && !isStatic) { argType = delegateCtor.OwningType; } else { argType = delegateCtor.Signature[i - (isStatic ? 0 : 1)]; } args.Add(ILImporter.GetLLVMTypeForTypeDesc(argType)); } } LLVMValueRef helperFunc = Module.GetNamedFunction(node.GetMangledName(factory.NameMangler)); if (helperFunc.Handle == IntPtr.Zero) { throw new Exception("if the function is requested here, it should have been created earlier"); } var helperBlock = helperFunc.AppendBasicBlock("genericHelper"); builder.PositionAtEnd(helperBlock); var importer = new ILImporter(builder, compilation, Module, helperFunc, delegateCtor); LLVMValueRef ctx; string gepName; if (node is ReadyToRunGenericLookupFromTypeNode) { // Locate the VTable slot that points to the dictionary int vtableSlot = VirtualMethodSlotHelper.GetGenericDictionarySlot(factory, (TypeDesc)node.DictionaryOwner); int pointerSize = factory.Target.PointerSize; // Load the dictionary pointer from the VTable int slotOffset = EETypeNode.GetVTableOffset(pointerSize) + (vtableSlot * pointerSize); var slotGep = builder.BuildGEP(helperFunc.GetParam(1), new[] { LLVMValueRef.CreateConstInt(LLVMTypeRef.Int32, (ulong)slotOffset, false) }, "slotGep"); var slotGepPtrPtr = builder.BuildPointerCast(slotGep, LLVMTypeRef.CreatePointer(LLVMTypeRef.CreatePointer(LLVMTypeRef.Int8, 0), 0), "slotGepPtrPtr"); ctx = builder.BuildLoad(slotGepPtrPtr, "dictGep"); gepName = "typeNodeGep"; } else { ctx = helperFunc.GetParam(1); gepName = "paramGep"; } LLVMValueRef resVar = OutputCodeForDictionaryLookup(builder, factory, node, node.LookupSignature, ctx, gepName); switch (node.Id) { case ReadyToRunHelperId.GetNonGCStaticBase: { MetadataType target = (MetadataType)node.Target; if (compilation.TypeSystemContext.HasLazyStaticConstructor(target)) { importer.OutputCodeForTriggerCctor(target, resVar); } } break; case ReadyToRunHelperId.GetGCStaticBase: { MetadataType target = (MetadataType)node.Target; var ptrPtrPtr = builder.BuildBitCast(resVar, LLVMTypeRef.CreatePointer(LLVMTypeRef.CreatePointer(LLVMTypeRef.CreatePointer(LLVMTypeRef.Int8, 0), 0), 0), "ptrPtrPtr"); resVar = builder.BuildLoad(builder.BuildLoad(ptrPtrPtr, "ind1"), "ind2"); if (compilation.TypeSystemContext.HasLazyStaticConstructor(target)) { GenericLookupResult nonGcRegionLookup = factory.GenericLookup.TypeNonGCStaticBase(target); var nonGcStaticsBase = OutputCodeForDictionaryLookup(builder, factory, node, nonGcRegionLookup, ctx, "lazyGep"); importer.OutputCodeForTriggerCctor(target, nonGcStaticsBase); } } break; case ReadyToRunHelperId.GetThreadStaticBase: { MetadataType target = (MetadataType)node.Target; if (compilation.TypeSystemContext.HasLazyStaticConstructor(target)) { GenericLookupResult nonGcRegionLookup = factory.GenericLookup.TypeNonGCStaticBase(target); var threadStaticBase = OutputCodeForDictionaryLookup(builder, factory, node, nonGcRegionLookup, ctx, "tsGep"); importer.OutputCodeForTriggerCctor(target, threadStaticBase); } resVar = importer.OutputCodeForGetThreadStaticBaseForType(resVar).ValueAsType(LLVMTypeRef.CreatePointer(LLVMTypeRef.Int8, 0), builder); } break; case ReadyToRunHelperId.DelegateCtor: { DelegateCreationInfo target = (DelegateCreationInfo)node.Target; MethodDesc constructor = target.Constructor.Method; var fatPtr = ILImporter.MakeFatPointer(builder, resVar, compilation); importer.OutputCodeForDelegateCtorInit(builder, helperFunc, constructor, fatPtr); } break; // These are all simple: just get the thing from the dictionary and we're done case ReadyToRunHelperId.TypeHandle: case ReadyToRunHelperId.MethodHandle: case ReadyToRunHelperId.FieldHandle: case ReadyToRunHelperId.MethodDictionary: case ReadyToRunHelperId.MethodEntry: case ReadyToRunHelperId.VirtualDispatchCell: case ReadyToRunHelperId.DefaultConstructor: break; default: throw new NotImplementedException(); } if (node.Id != ReadyToRunHelperId.DelegateCtor) { builder.BuildRet(resVar); } else { builder.BuildRetVoid(); } }
protected sealed override void EmitCode(NodeFactory factory, ref ARMEmitter encoder, bool relocsOnly) { // First load the generic context into the context register. EmitLoadGenericContext(factory, ref encoder, relocsOnly); Register contextRegister = GetContextRegister(ref encoder); switch (_id) { case ReadyToRunHelperId.GetNonGCStaticBase: { Debug.Assert(contextRegister == encoder.TargetRegister.Arg0); EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg0, encoder.TargetRegister.Result, _lookupSignature, relocsOnly); MetadataType target = (MetadataType)_target; if (!factory.TypeSystemContext.HasLazyStaticConstructor(target)) { encoder.EmitRET(); } else { // We need to trigger the cctor before returning the base. It is stored at the beginning of the non-GC statics region. int cctorContextSize = NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target); encoder.EmitLDR(encoder.TargetRegister.Arg1, encoder.TargetRegister.Arg0, ((short)(factory.Target.PointerSize - cctorContextSize))); encoder.EmitCMP(encoder.TargetRegister.Arg1, ((byte)1)); encoder.EmitRETIfEqual(); encoder.EmitMOV(encoder.TargetRegister.Arg1, encoder.TargetRegister.Result); encoder.EmitSUB(encoder.TargetRegister.Arg0, ((byte)(cctorContextSize))); encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnNonGCStaticBase)); } } break; case ReadyToRunHelperId.GetGCStaticBase: { Debug.Assert(contextRegister == encoder.TargetRegister.Arg0); encoder.EmitMOV(encoder.TargetRegister.Arg1, encoder.TargetRegister.Arg0); EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg0, encoder.TargetRegister.Result, _lookupSignature, relocsOnly); encoder.EmitLDR(encoder.TargetRegister.Result, encoder.TargetRegister.Result); encoder.EmitLDR(encoder.TargetRegister.Result, encoder.TargetRegister.Result); MetadataType target = (MetadataType)_target; if (!factory.TypeSystemContext.HasLazyStaticConstructor(target)) { encoder.EmitRET(); } else { // We need to trigger the cctor before returning the base. It is stored at the beginning of the non-GC statics region. GenericLookupResult nonGcRegionLookup = factory.GenericLookup.TypeNonGCStaticBase(target); EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg1, encoder.TargetRegister.Arg2, nonGcRegionLookup, relocsOnly); int cctorContextSize = NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target); encoder.EmitLDR(encoder.TargetRegister.Arg3, encoder.TargetRegister.Arg2, ((short)(factory.Target.PointerSize - cctorContextSize))); encoder.EmitCMP(encoder.TargetRegister.Arg3, 1); encoder.EmitRETIfEqual(); encoder.EmitMOV(encoder.TargetRegister.Arg1, encoder.TargetRegister.Result); encoder.EmitMOV(encoder.TargetRegister.Arg0, encoder.TargetRegister.Arg2); encoder.EmitSUB(encoder.TargetRegister.Arg0, cctorContextSize); encoder.EmitJMP(factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnGCStaticBase)); } } break; case ReadyToRunHelperId.GetThreadStaticBase: { Debug.Assert(contextRegister == encoder.TargetRegister.Arg0); MetadataType target = (MetadataType)_target; // Look up the index cell EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg0, encoder.TargetRegister.Arg1, _lookupSignature, relocsOnly); ISymbolNode helperEntrypoint; if (factory.TypeSystemContext.HasLazyStaticConstructor(target)) { // There is a lazy class constructor. We need the non-GC static base because that's where the // class constructor context lives. GenericLookupResult nonGcRegionLookup = factory.GenericLookup.TypeNonGCStaticBase(target); EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg0, encoder.TargetRegister.Arg2, nonGcRegionLookup, relocsOnly); int cctorContextSize = NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.Target, target); encoder.EmitSUB(encoder.TargetRegister.Arg2, cctorContextSize); helperEntrypoint = factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnThreadStaticBase); } else { helperEntrypoint = factory.HelperEntrypoint(HelperEntrypoint.GetThreadStaticBaseForType); } // First arg: address of the TypeManager slot that provides the helper with // information about module index and the type manager instance (which is used // for initialization on first access). encoder.EmitLDR(encoder.TargetRegister.Arg0, encoder.TargetRegister.Arg1); // Second arg: index of the type in the ThreadStatic section of the modules encoder.EmitLDR(encoder.TargetRegister.Arg1, encoder.TargetRegister.Arg1, factory.Target.PointerSize); encoder.EmitJMP(helperEntrypoint); } break; case ReadyToRunHelperId.DelegateCtor: { ARMDebug.EmitNYIAssert(factory, ref encoder, "DelegateCtor EmitCode is not implemented"); /* *** ***NOT TESTED!!! *** ***// This is a weird helper. Codegen populated Arg0 and Arg1 with the values that the constructor ***// method expects. Codegen also passed us the generic context in Arg2. ***// We now need to load the delegate target method into Arg2 (using a dictionary lookup) ***// and the optional 4th parameter, and call the ctor. *** ***Debug.Assert(contextRegister == encoder.TargetRegister.Arg2); *** ***var target = (DelegateCreationInfo)_target; *** ***EmitDictionaryLookup(factory, ref encoder, encoder.TargetRegister.Arg2, encoder.TargetRegister.Arg2, _lookupSignature, relocsOnly); *** ***if (target.Thunk != null) ***{ ***Debug.Assert(target.Constructor.Method.Signature.Length == 3); ***encoder.EmitMOV(encoder.TargetRegister.Arg3, target.Thunk); ***} ***else ***{ ***Debug.Assert(target.Constructor.Method.Signature.Length == 2); ***} *** ***encoder.EmitJMP(target.Constructor); */ }