public static DependencyList GetGenericMethodsHashtableDependenciesForMethod(NodeFactory factory, MethodDesc method) { Debug.Assert(method.HasInstantiation && !method.IsCanonicalMethod(CanonicalFormKind.Any)); DependencyList dependencies = new DependencyList(); // Method's containing type IEETypeNode containingTypeNode = factory.NecessaryTypeSymbol(method.OwningType); dependencies.Add(new DependencyListEntry(containingTypeNode, "GenericMethodsHashtable entry containing type")); // Method's instantiation arguments for (int i = 0; i < method.Instantiation.Length; i++) { IEETypeNode argNode = factory.NecessaryTypeSymbol(method.Instantiation[i]); dependencies.Add(new DependencyListEntry(argNode, "GenericMethodsHashtable entry instantiation argument")); } // Method name and signature NativeLayoutVertexNode nameAndSig = factory.NativeLayout.MethodNameAndSignatureVertex(method.GetTypicalMethodDefinition()); NativeLayoutSavedVertexNode placedNameAndSig = factory.NativeLayout.PlacedSignatureVertex(nameAndSig); dependencies.Add(new DependencyListEntry(placedNameAndSig, "GenericMethodsHashtable entry signature")); ISymbolNode dictionaryNode = factory.MethodGenericDictionary(method); dependencies.Add(new DependencyListEntry(dictionaryNode, "GenericMethodsHashtable entry dictionary")); return(dependencies); }
public override void EncodeData(ref ObjectDataBuilder objData, NodeFactory factory, bool relocsOnly) { TargetArchitecture targetArchitecture = factory.Target.Architecture; if (targetArchitecture == TargetArchitecture.ARM) { objData.EmitPointerReloc(factory.InitialInterfaceDispatchStub); } else { objData.EmitPointerReloc(factory.ExternSymbol("RhpInitialDynamicInterfaceDispatch")); } IEETypeNode interfaceType = factory.NecessaryTypeSymbol(_targetMethod.OwningType); if (interfaceType.RepresentsIndirectionCell) { objData.EmitReloc(interfaceType, RelocType.IMAGE_REL_BASED_RELPTR32, (int)InterfaceDispatchCellCachePointerFlags.CachePointerIsIndirectedInterfaceRelativePointer); } else { objData.EmitReloc(interfaceType, RelocType.IMAGE_REL_BASED_RELPTR32, (int)InterfaceDispatchCellCachePointerFlags.CachePointerIsInterfaceRelativePointer); } if (objData.TargetPointerSize == 8) { // IMAGE_REL_BASED_RELPTR is a 32-bit relocation. However, the cell needs a full pointer // width there since a pointer to the cache will be written into the cell. Emit additional // 32 bits on targets whose pointer size is 64 bit. objData.EmitInt(0); } }
public override Vertex WriteVertex(NodeFactory factory) { IEETypeNode eetypeNode = factory.NecessaryTypeSymbol(_type); uint typeIndex = factory.MetadataManager.NativeLayoutInfo.ExternalReferences.GetIndex(eetypeNode); return(GetNativeWriter(factory).GetExternalTypeSignature(typeIndex)); }
public void AddWellKnownType(IEETypeNode node) { if (_wellKnownTypeNodes == null) { _wellKnownTypeNodes = new List<IEETypeNode>(); } _wellKnownTypeNodes.Add(node); }
public void AddWellKnownType(IEETypeNode node) { if (_wellKnownTypeNodes == null) { _wellKnownTypeNodes = new List <IEETypeNode>(); } _wellKnownTypeNodes.Add(node); }
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { // This node does not trigger generation of other nodes. if (relocsOnly) { return(new ObjectData(Array.Empty <byte>(), Array.Empty <Relocation>(), 1, new ISymbolNode[] { this })); } var writer = new NativeWriter(); var reflectionBlockTypeMapHashTable = new VertexHashtable(); Section hashTableSection = writer.NewSection(); hashTableSection.Place(reflectionBlockTypeMapHashTable); foreach (var type in factory.MetadataManager.GetTypesWithEETypes()) { if (!type.IsTypeDefinition) { continue; } var mdType = type as MetadataType; if (mdType == null) { continue; } if (!factory.MetadataManager.IsReflectionBlocked(mdType)) { continue; } if (!factory.CompilationModuleGroup.ContainsType(mdType)) { continue; } // Go with a necessary type symbol. It will be upgraded to a constructed one if a constructed was emitted. IEETypeNode typeSymbol = factory.NecessaryTypeSymbol(type); Vertex vertex = writer.GetUnsignedConstant(_externalReferences.GetIndex(typeSymbol)); int hashCode = typeSymbol.Type.GetHashCode(); reflectionBlockTypeMapHashTable.Append((uint)hashCode, hashTableSection.Place(vertex)); } MemoryStream ms = new MemoryStream(); writer.Save(ms); byte[] hashTableBytes = ms.ToArray(); _endSymbol.SetSymbolOffset(hashTableBytes.Length); return(new ObjectData(hashTableBytes, Array.Empty <Relocation>(), 1, new ISymbolNode[] { this, _endSymbol })); }
public override Vertex WriteVertex(NodeFactory factory) { Vertex containingType = GetContainingTypeVertex(factory); Vertex methodSig = _methodSig.WriteVertex(factory); Vertex methodNameAndSig = GetNativeWriter(factory).GetMethodNameAndSigSignature(_method.Name, methodSig); Vertex[] args = null; MethodFlags flags = 0; if (_method.HasInstantiation) { Debug.Assert(_instantiationArgsSig == null || (_instantiationArgsSig != null && _method.Instantiation.Length == _instantiationArgsSig.Length)); flags |= MethodFlags.HasInstantiation; args = new Vertex[_method.Instantiation.Length]; for (int i = 0; i < args.Length; i++) { if ((_flags & MethodEntryFlags.CreateInstantiatedSignature) != 0) { IEETypeNode eetypeNode = factory.NecessaryTypeSymbol(_method.Instantiation[i]); uint typeIndex = factory.MetadataManager.NativeLayoutInfo.ExternalReferences.GetIndex(eetypeNode); args[i] = GetNativeWriter(factory).GetExternalTypeSignature(typeIndex); } else { args[i] = _instantiationArgsSig[i].WriteVertex(factory); } } } uint fptrReferenceId = 0; if ((_flags & MethodEntryFlags.SaveEntryPoint) != 0) { flags |= MethodFlags.HasFunctionPointer; bool getUnboxingStub = _method.OwningType.IsValueType && !_method.Signature.IsStatic; IMethodNode methodEntryPointNode = factory.MethodEntrypoint(_method, getUnboxingStub); fptrReferenceId = factory.MetadataManager.NativeLayoutInfo.ExternalReferences.GetIndex(methodEntryPointNode); if (getUnboxingStub) { flags |= MethodFlags.IsUnboxingStub; } if (_method.IsCanonicalMethod(CanonicalFormKind.Universal)) { flags |= MethodFlags.FunctionPointerIsUSG; } } return(GetNativeWriter(factory).GetMethodSignature((uint)flags, fptrReferenceId, containingType, methodNameAndSig, args)); }
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { ObjectDataBuilder objData = new ObjectDataBuilder(factory, relocsOnly); // The interface dispatch cell has an alignment requirement of 2 * [Pointer size] as part of the // synchronization mechanism of the two values in the runtime. objData.RequireInitialAlignment(_targetMethod.Context.Target.PointerSize * 2); objData.AddSymbol(this); TargetArchitecture targetArchitecture = factory.Target.Architecture; if (targetArchitecture == TargetArchitecture.ARM || targetArchitecture == TargetArchitecture.ARMEL) { objData.EmitPointerReloc(factory.InitialInterfaceDispatchStub); } else { objData.EmitPointerReloc(factory.ExternSymbol("RhpInitialDynamicInterfaceDispatch")); } IEETypeNode interfaceType = factory.NecessaryTypeSymbol(_targetMethod.OwningType); if (interfaceType.RepresentsIndirectionCell) { objData.EmitReloc(interfaceType, RelocType.IMAGE_REL_BASED_RELPTR32, (int)InterfaceDispatchCellCachePointerFlags.CachePointerIsIndirectedInterfaceRelativePointer); } else { objData.EmitReloc(interfaceType, RelocType.IMAGE_REL_BASED_RELPTR32, (int)InterfaceDispatchCellCachePointerFlags.CachePointerIsInterfaceRelativePointer); } if (objData.TargetPointerSize == 8) { // IMAGE_REL_BASED_RELPTR is a 32-bit relocation. However, the cell needs a full pointer // width there since a pointer to the cache will be written into the cell. Emit additional // 32 bits on targets whose pointer size is 64 bit. objData.EmitInt(0); } // End the run of dispatch cells objData.EmitZeroPointer(); // Avoid consulting VTable slots until they're guaranteed complete during final data emission if (!relocsOnly) { objData.EmitNaturalInt(VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, _targetMethod)); } return(objData.ToObjectData()); }
private Vertex GetContainingTypeVertex(NodeFactory factory) { if ((_flags & MethodEntryFlags.CreateInstantiatedSignature) != 0) { IEETypeNode eetypeNode = factory.NecessaryTypeSymbol(_method.OwningType); uint typeIndex = factory.MetadataManager.NativeLayoutInfo.ExternalReferences.GetIndex(eetypeNode); return(GetNativeWriter(factory).GetExternalTypeSignature(typeIndex)); } else { return(_containingTypeSig.WriteVertex(factory)); } }
public void SetDispatchMapIndex(NodeFactory factory, int index) { _dispatchMapTableIndex = index; IEETypeNode eeTypeNode = factory.ConstructedTypeSymbol(_type); if (eeTypeNode is ImportedEETypeSymbolNode) { Debug.Assert(_type == factory.TypeSystemContext.GetWellKnownType(WellKnownType.String)); eeTypeNode = factory.ConstructedClonedTypeSymbol(_type); } ((EETypeNode)eeTypeNode).SetDispatchMapIndex(_dispatchMapTableIndex); }
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { // This node does not trigger generation of other nodes. if (relocsOnly) { return(new ObjectData(Array.Empty <byte>(), Array.Empty <Relocation>(), 1, new ISymbolNode[] { this })); } var writer = new NativeWriter(); var typeMapHashTable = new VertexHashtable(); Section hashTableSection = writer.NewSection(); hashTableSection.Place(typeMapHashTable); foreach (var mappingEntry in factory.MetadataManager.GetTypeDefinitionMapping()) { if (!factory.CompilationModuleGroup.ContainsType(mappingEntry.Entity)) { continue; } // Types that don't have EETypes don't need mapping table entries because there's no risk of them // not unifying to the same System.Type at runtime. if (!factory.MetadataManager.TypeGeneratesEEType(mappingEntry.Entity)) { continue; } // Go with a necessary type symbol. It will be upgraded to a constructed one if a constructed was emitted. IEETypeNode typeSymbol = factory.NecessaryTypeSymbol(mappingEntry.Entity); Vertex vertex = writer.GetTuple( writer.GetUnsignedConstant(_externalReferences.GetIndex(typeSymbol)), writer.GetUnsignedConstant((uint)mappingEntry.MetadataHandle) ); int hashCode = typeSymbol.Type.GetHashCode(); typeMapHashTable.Append((uint)hashCode, hashTableSection.Place(vertex)); } MemoryStream ms = new MemoryStream(); writer.Save(ms); byte[] hashTableBytes = ms.ToArray(); _endSymbol.SetSymbolOffset(hashTableBytes.Length); return(new ObjectData(hashTableBytes, Array.Empty <Relocation>(), 1, new ISymbolNode[] { this, _endSymbol })); }
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { // This node does not trigger generation of other nodes. if (relocsOnly) { return(new ObjectData(Array.Empty <byte>(), Array.Empty <Relocation>(), 1, new ISymbolDefinitionNode[] { this })); } var writer = new NativeWriter(); var typeMapHashTable = new VertexHashtable(); Section hashTableSection = writer.NewSection(); hashTableSection.Place(typeMapHashTable); foreach (var type in factory.MetadataManager.GetTypesWithConstructedEETypes()) { if (!type.IsSzArray) { continue; } var arrayType = (ArrayType)type; // This optimization is not compatible with canInlineTypeCheck on JIT/EE interface returning // CORINFO_INLINE_TYPECHECK_PASS unconditionally. // // If we're generating a template for this type, we can skip generating the hashtable entry // since the type loader can just create this type at runtime if something needs it. It's // okay to have multiple EETypes for the same array type. // var canonArrayType = arrayType.ConvertToCanonForm(CanonicalFormKind.Specific); // if (arrayType != canonArrayType && factory.NativeLayout.TemplateTypeLayout(canonArrayType).Marked) // continue; // Look at the constructed type symbol. If a constructed type wasn't emitted, then the array map entry isn't valid for use IEETypeNode arrayTypeSymbol = factory.ConstructedTypeSymbol(arrayType); Vertex vertex = writer.GetUnsignedConstant(_externalReferences.GetIndex(arrayTypeSymbol)); int hashCode = arrayType.GetHashCode(); typeMapHashTable.Append((uint)hashCode, hashTableSection.Place(vertex)); } byte[] hashTableBytes = writer.Save(); _endSymbol.SetSymbolOffset(hashTableBytes.Length); return(new ObjectData(hashTableBytes, Array.Empty <Relocation>(), 1, new ISymbolDefinitionNode[] { this, _endSymbol })); }
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { // This node does not trigger generation of other nodes. if (relocsOnly) { return(new ObjectData(Array.Empty <byte>(), Array.Empty <Relocation>(), 1, new ISymbolDefinitionNode[] { this })); } var writer = new NativeWriter(); var typeMapHashTable = new VertexHashtable(); Section hashTableSection = writer.NewSection(); hashTableSection.Place(typeMapHashTable); foreach (var arrayType in factory.MetadataManager.GetArrayTypeMapping()) { if (!arrayType.IsSzArray) { continue; } if (!factory.MetadataManager.TypeGeneratesEEType(arrayType)) { continue; } if (!arrayType.ElementType.IsValueType) { continue; } // Go with a necessary type symbol. It will be upgraded to a constructed one if a constructed was emitted. IEETypeNode arrayTypeSymbol = factory.NecessaryTypeSymbol(arrayType); Vertex vertex = writer.GetUnsignedConstant(_externalReferences.GetIndex(arrayTypeSymbol)); int hashCode = arrayType.GetHashCode(); typeMapHashTable.Append((uint)hashCode, hashTableSection.Place(vertex)); } byte[] hashTableBytes = writer.Save(); _endSymbol.SetSymbolOffset(hashTableBytes.Length); return(new ObjectData(hashTableBytes, Array.Empty <Relocation>(), 1, new ISymbolDefinitionNode[] { this, _endSymbol })); }
public override ISymbolNode GetTarget(NodeFactory factory, Instantiation typeInstantiation, Instantiation methodInstantiation, GenericDictionaryNode dictionary) { // We are getting a constructed type symbol because this might be something passed to newobj. TypeDesc instantiatedType = _type.InstantiateSignature(typeInstantiation, methodInstantiation); IEETypeNode typeNode = factory.ConstructedTypeSymbol(instantiatedType); if (typeNode.RepresentsIndirectionCell) { // Imported eetype needs another indirection. Setting the lowest bit to indicate that. Debug.Assert(LookupResultReferenceType(factory) == GenericLookupResultReferenceType.ConditionalIndirect); return(factory.Indirection(typeNode, 1)); } else { return(typeNode); } }
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { // This node does not trigger generation of other nodes. if (relocsOnly) { return(new ObjectData(Array.Empty <byte>(), Array.Empty <Relocation>(), 1, new ISymbolDefinitionNode[] { this })); } var writer = new NativeWriter(); var typeMapHashTable = new VertexHashtable(); Section hashTableSection = writer.NewSection(); hashTableSection.Place(typeMapHashTable); foreach (var type in factory.MetadataManager.GetTypesWithConstructedEETypes()) { if (!type.IsSzArray) { continue; } var arrayType = (ArrayType)type; if (!arrayType.ElementType.IsValueType) { continue; } // Look at the constructed type symbol. If a constructed type wasn't emitted, then the array map entry isn't valid for use IEETypeNode arrayTypeSymbol = factory.ConstructedTypeSymbol(arrayType); Vertex vertex = writer.GetUnsignedConstant(_externalReferences.GetIndex(arrayTypeSymbol)); int hashCode = arrayType.GetHashCode(); typeMapHashTable.Append((uint)hashCode, hashTableSection.Place(vertex)); } byte[] hashTableBytes = writer.Save(); _endSymbol.SetSymbolOffset(hashTableBytes.Length); return(new ObjectData(hashTableBytes, Array.Empty <Relocation>(), 1, new ISymbolDefinitionNode[] { this, _endSymbol })); }
private static IEETypeNode GetEETypeNode(NodeFactory factory) { DefType systemStringType = factory.TypeSystemContext.GetWellKnownType(WellKnownType.String); // // The GC requires a direct reference to frozen objects' EETypes. If System.String will be compiled into a separate // binary, it must be cloned into this one. // IEETypeNode stringSymbol = factory.ConstructedTypeSymbol(systemStringType); if (stringSymbol.RepresentsIndirectionCell) { return(factory.ConstructedClonedTypeSymbol(systemStringType)); } else { return(stringSymbol); } }
private void BuildMethodLists(IEnumerable <DependencyNode> nodes) { _methodLists = new Dictionary <TypeDesc, List <MethodDesc> >(); foreach (var node in nodes) { if (node is CppMethodCodeNode) { CppMethodCodeNode methodCodeNode = (CppMethodCodeNode)node; var method = methodCodeNode.Method; var type = method.OwningType; List <MethodDesc> methodList; if (!_methodLists.TryGetValue(type, out methodList)) { GetCppSignatureTypeName(type); methodList = new List <MethodDesc>(); _methodLists.Add(type, methodList); } methodList.Add(method); } else if (node is IEETypeNode) { IEETypeNode eeTypeNode = (IEETypeNode)node; if (eeTypeNode.Type.IsGenericDefinition) { // TODO: CppWriter can't handle generic type definition EETypes } else { GetCppSignatureTypeName(eeTypeNode.Type); } } } }
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { // This node does not trigger generation of other nodes. if (relocsOnly) { return(new ObjectData(Array.Empty <byte>(), Array.Empty <Relocation>(), 1, new ISymbolDefinitionNode[] { this })); } // Ensure the native layout blob has been saved factory.MetadataManager.NativeLayoutInfo.SaveNativeLayoutInfoWriter(factory); var writer = new NativeWriter(); var typeMapHashTable = new VertexHashtable(); Section hashTableSection = writer.NewSection(); hashTableSection.Place(typeMapHashTable); // Get a list of all methods that have a method body and metadata from the metadata manager. foreach (var mappingEntry in factory.MetadataManager.GetMethodMapping(factory)) { MethodDesc method = mappingEntry.Entity; // The current format requires us to have an EEType for the owning type. We might want to lift this. if (!factory.MetadataManager.TypeGeneratesEEType(method.OwningType)) { continue; } // We have a method body, we have a metadata token, but we can't get an invoke stub. Bail. if (!factory.MetadataManager.IsReflectionInvokable(method)) { continue; } InvokeTableFlags flags = 0; if (method.HasInstantiation) { flags |= InvokeTableFlags.IsGenericMethod; } if (method.GetCanonMethodTarget(CanonicalFormKind.Specific).RequiresInstArg()) { flags |= InvokeTableFlags.RequiresInstArg; } if (method.IsDefaultConstructor) { flags |= InvokeTableFlags.IsDefaultConstructor; } if (ReflectionVirtualInvokeMapNode.NeedsVirtualInvokeInfo(method)) { flags |= InvokeTableFlags.HasVirtualInvoke; } if (!method.IsAbstract) { flags |= InvokeTableFlags.HasEntrypoint; } if (mappingEntry.MetadataHandle != 0) { flags |= InvokeTableFlags.HasMetadataHandle; } if (!factory.MetadataManager.HasReflectionInvokeStubForInvokableMethod(method)) { flags |= InvokeTableFlags.NeedsParameterInterpretation; } if (method.IsCanonicalMethod(CanonicalFormKind.Universal)) { flags |= InvokeTableFlags.IsUniversalCanonicalEntry; } // TODO: native signature for P/Invokes and NativeCallable methods if (method.IsRawPInvoke() || method.IsNativeCallable) { continue; } // Grammar of an entry in the hash table: // Flags + DeclaringType + MetadataHandle/NameAndSig + Entrypoint + DynamicInvokeMethod + [NumGenericArgs + GenericArgs] Vertex vertex = writer.GetUnsignedConstant((uint)flags); if ((flags & InvokeTableFlags.HasMetadataHandle) != 0) { // Only store the offset portion of the metadata handle to get better integer compression vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant((uint)(mappingEntry.MetadataHandle & MetadataManager.MetadataOffsetMask))); } else { var nameAndSig = factory.NativeLayout.PlacedSignatureVertex(factory.NativeLayout.MethodNameAndSignatureVertex(method.GetTypicalMethodDefinition())); vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant((uint)nameAndSig.SavedVertex.VertexOffset)); } // Go with a necessary type symbol. It will be upgraded to a constructed one if a constructed was emitted. IEETypeNode owningTypeSymbol = factory.NecessaryTypeSymbol(method.OwningType); vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant(_externalReferences.GetIndex(owningTypeSymbol))); if ((flags & InvokeTableFlags.HasEntrypoint) != 0) { bool useUnboxingStub = method.OwningType.IsValueType && !method.Signature.IsStatic; vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant(_externalReferences.GetIndex( factory.MethodEntrypoint(method.GetCanonMethodTarget(CanonicalFormKind.Specific), useUnboxingStub)))); } if ((flags & InvokeTableFlags.NeedsParameterInterpretation) == 0) { MethodDesc canonInvokeStubMethod = factory.MetadataManager.GetCanonicalReflectionInvokeStub(method); if (canonInvokeStubMethod.IsSharedByGenericInstantiations) { vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant(((uint)factory.MetadataManager.DynamicInvokeTemplateData.GetIdForMethod(canonInvokeStubMethod) << 1) | 1)); } else { vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant(_externalReferences.GetIndex(factory.MethodEntrypoint(canonInvokeStubMethod)) << 1)); } } if ((flags & InvokeTableFlags.IsGenericMethod) != 0) { if ((flags & InvokeTableFlags.IsUniversalCanonicalEntry) != 0) { var nameAndSigGenericMethod = factory.NativeLayout.PlacedSignatureVertex(factory.NativeLayout.MethodNameAndSignatureVertex(method)); vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant((uint)nameAndSigGenericMethod.SavedVertex.VertexOffset)); } else if ((flags & InvokeTableFlags.RequiresInstArg) == 0 || (flags & InvokeTableFlags.HasEntrypoint) == 0) { VertexSequence args = new VertexSequence(); for (int i = 0; i < method.Instantiation.Length; i++) { uint argId = _externalReferences.GetIndex(factory.NecessaryTypeSymbol(method.Instantiation[i])); args.Append(writer.GetUnsignedConstant(argId)); } vertex = writer.GetTuple(vertex, args); } else { uint dictionaryId = _externalReferences.GetIndex(factory.MethodGenericDictionary(method)); vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant(dictionaryId)); } } int hashCode = method.GetCanonMethodTarget(CanonicalFormKind.Specific).OwningType.GetHashCode(); typeMapHashTable.Append((uint)hashCode, hashTableSection.Place(vertex)); } byte[] hashTableBytes = writer.Save(); _endSymbol.SetSymbolOffset(hashTableBytes.Length); return(new ObjectData(hashTableBytes, Array.Empty <Relocation>(), 1, new ISymbolDefinitionNode[] { this, _endSymbol })); }
private void OutputTypeNode(IEETypeNode typeNode, NodeFactory factory, CppGenerationBuffer forwardDefinitions, CppGenerationBuffer typeDefinitions, CppGenerationBuffer methodTable) { if (_emittedTypes == null) { _emittedTypes = new HashSet<TypeDesc>(); } TypeDesc nodeType = typeNode.Type; if (nodeType.IsPointer || nodeType.IsByRef || _emittedTypes.Contains(nodeType)) return; _emittedTypes.Add(nodeType); // Create Namespaces string mangledName = GetCppTypeName(nodeType); int nesting = 0; int current = 0; forwardDefinitions.AppendLine(); for (;;) { int sep = mangledName.IndexOf("::", current); if (sep < 0) break; if (sep != 0) { // Case of a name not starting with :: forwardDefinitions.Append("namespace " + mangledName.Substring(current, sep - current) + " { "); typeDefinitions.Append("namespace " + mangledName.Substring(current, sep - current) + " { "); typeDefinitions.Indent(); nesting++; } current = sep + 2; } forwardDefinitions.Append("class " + mangledName.Substring(current) + ";"); // type definition typeDefinitions.Append("class " + mangledName.Substring(current)); if (!nodeType.IsValueType) { // Don't emit inheritance if base type has not been marked for emission if (nodeType.BaseType != null && _emittedTypes.Contains(nodeType.BaseType)) { typeDefinitions.Append(" : public " + GetCppTypeName(nodeType.BaseType)); } } typeDefinitions.Append(" {"); typeDefinitions.AppendLine(); typeDefinitions.Append("public:"); typeDefinitions.Indent(); // TODO: Enable once the dependencies are tracked for arrays // if (((DependencyNode)_compilation.NodeFactory.ConstructedTypeSymbol(t)).Marked) if (!nodeType.IsPointer && !nodeType.IsByRef) { typeDefinitions.AppendLine(); typeDefinitions.Append("static MethodTable * __getMethodTable();"); } if (typeNode is ConstructedEETypeNode) { OutputTypeFields(typeDefinitions, nodeType); IReadOnlyList<MethodDesc> virtualSlots = _compilation.NodeFactory.VTable(nodeType).Slots; int baseSlots = 0; var baseType = nodeType.BaseType; while (baseType != null) { IReadOnlyList<MethodDesc> baseVirtualSlots = _compilation.NodeFactory.VTable(baseType).Slots; if (baseVirtualSlots != null) baseSlots += baseVirtualSlots.Count; baseType = baseType.BaseType; } for (int slot = 0; slot < virtualSlots.Count; slot++) { MethodDesc virtualMethod = virtualSlots[slot]; typeDefinitions.AppendLine(); typeDefinitions.Append(GetCodeForVirtualMethod(virtualMethod, baseSlots + slot)); } if (nodeType.IsDelegate) { typeDefinitions.AppendLine(); typeDefinitions.Append(GetCodeForDelegate(nodeType)); } if (nodeType.HasStaticConstructor) { _statics.AppendLine(); _statics.Append("bool __cctor_" + GetCppTypeName(nodeType).Replace("::", "__") + ";"); } List<MethodDesc> methodList; if (_methodLists.TryGetValue(nodeType, out methodList)) { foreach (var m in methodList) { typeDefinitions.AppendLine(); AppendCppMethodDeclaration(typeDefinitions, m, false); } } } typeDefinitions.AppendEmptyLine(); typeDefinitions.Append("};"); typeDefinitions.AppendEmptyLine(); typeDefinitions.Exdent(); while (nesting > 0) { forwardDefinitions.Append("};"); typeDefinitions.Append("};"); typeDefinitions.Exdent(); nesting--; } typeDefinitions.AppendEmptyLine(); // declare method table if (!nodeType.IsPointer && !nodeType.IsByRef) { methodTable.Append(GetCodeForObjectNode(typeNode as ObjectNode, factory)); methodTable.AppendEmptyLine(); } }
private void OutputTypeNode(IEETypeNode typeNode, NodeFactory factory, CppGenerationBuffer forwardDefinitions, CppGenerationBuffer typeDefinitions, CppGenerationBuffer methodTable) { if (_emittedTypes == null) { _emittedTypes = new HashSet <TypeDesc>(); } TypeDesc nodeType = typeNode.Type; if (_emittedTypes.Contains(nodeType)) { return; } _emittedTypes.Add(nodeType); // Create Namespaces string mangledName = _compilation.NameMangler.GetMangledTypeName(nodeType); int nesting = 0; int current = 0; forwardDefinitions.AppendLine(); for (;;) { int sep = mangledName.IndexOf("::", current); if (sep < 0) { break; } if (sep != 0) { // Case of a name not starting with :: forwardDefinitions.Append("namespace " + mangledName.Substring(current, sep - current) + " { "); typeDefinitions.Append("namespace " + mangledName.Substring(current, sep - current) + " { "); typeDefinitions.Indent(); nesting++; } current = sep + 2; } forwardDefinitions.Append("class " + mangledName.Substring(current) + ";"); // type definition typeDefinitions.Append("class " + mangledName.Substring(current)); if (!nodeType.IsValueType) { // Don't emit inheritance if base type has not been marked for emission if (nodeType.BaseType != null && _emittedTypes.Contains(nodeType.BaseType)) { typeDefinitions.Append(" : public " + GetCppTypeName(nodeType.BaseType)); } } typeDefinitions.Append(" {"); typeDefinitions.AppendLine(); typeDefinitions.Append("public:"); typeDefinitions.Indent(); // TODO: Enable once the dependencies are tracked for arrays // if (((DependencyNode)_compilation.NodeFactory.ConstructedTypeSymbol(t)).Marked) { typeDefinitions.AppendLine(); typeDefinitions.Append("static MethodTable * __getMethodTable();"); } if (typeNode is ConstructedEETypeNode) { OutputTypeFields(typeDefinitions, nodeType); IReadOnlyList <MethodDesc> virtualSlots = _compilation.NodeFactory.VTable(nodeType).Slots; int baseSlots = 0; var baseType = nodeType.BaseType; while (baseType != null) { IReadOnlyList <MethodDesc> baseVirtualSlots = _compilation.NodeFactory.VTable(baseType).Slots; if (baseVirtualSlots != null) { baseSlots += baseVirtualSlots.Count; } baseType = baseType.BaseType; } for (int slot = 0; slot < virtualSlots.Count; slot++) { MethodDesc virtualMethod = virtualSlots[slot]; typeDefinitions.AppendLine(); typeDefinitions.Append(GetCodeForVirtualMethod(virtualMethod, baseSlots + slot)); } if (nodeType.IsDelegate) { typeDefinitions.AppendLine(); typeDefinitions.Append(GetCodeForDelegate(nodeType)); } } if (nodeType.HasStaticConstructor) { _statics.AppendLine(); _statics.Append("bool __cctor_" + GetCppTypeName(nodeType).Replace("::", "__") + ";"); } List <MethodDesc> methodList; if (_methodLists.TryGetValue(nodeType, out methodList)) { foreach (var m in methodList) { typeDefinitions.AppendLine(); AppendCppMethodDeclaration(typeDefinitions, m, false); } } typeDefinitions.AppendEmptyLine(); typeDefinitions.Append("};"); typeDefinitions.AppendEmptyLine(); typeDefinitions.Exdent(); while (nesting > 0) { forwardDefinitions.Append("};"); typeDefinitions.Append("};"); typeDefinitions.Exdent(); nesting--; } typeDefinitions.AppendEmptyLine(); // declare method table methodTable.Append(GetCodeForObjectNode(typeNode as ObjectNode, factory)); methodTable.AppendEmptyLine(); }
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { // This node does not trigger generation of other nodes. if (relocsOnly) { return(new ObjectData(Array.Empty <byte>(), Array.Empty <Relocation>(), 1, new ISymbolNode[] { this })); } // Ensure the native layout data has been saved, in order to get valid Vertex offsets for the signature Vertices factory.MetadataManager.NativeLayoutInfo.SaveNativeLayoutInfoWriter(factory); NativeWriter nativeWriter = new NativeWriter(); VertexHashtable hashtable = new VertexHashtable(); Section nativeSection = nativeWriter.NewSection(); nativeSection.Place(hashtable); foreach (var dictionaryNode in factory.MetadataManager.GetCompiledGenericDictionaries()) { MethodGenericDictionaryNode methodDictionary = dictionaryNode as MethodGenericDictionaryNode; if (methodDictionary == null) { continue; } MethodDesc method = methodDictionary.OwningMethod; Debug.Assert(method.HasInstantiation && !method.IsCanonicalMethod(CanonicalFormKind.Any)); Vertex fullMethodSignature; { // Method's containing type IEETypeNode containingTypeNode = factory.NecessaryTypeSymbol(method.OwningType); Vertex containingType = nativeWriter.GetUnsignedConstant(_externalReferences.GetIndex(containingTypeNode)); // Method's instantiation arguments VertexSequence arguments = new VertexSequence(); for (int i = 0; i < method.Instantiation.Length; i++) { IEETypeNode argNode = factory.NecessaryTypeSymbol(method.Instantiation[i]); arguments.Append(nativeWriter.GetUnsignedConstant(_externalReferences.GetIndex(argNode))); } // Method name and signature NativeLayoutVertexNode nameAndSig = factory.NativeLayout.MethodNameAndSignatureVertex(method.GetTypicalMethodDefinition()); NativeLayoutSavedVertexNode placedNameAndSig = factory.NativeLayout.PlacedSignatureVertex(nameAndSig); Vertex placedNameAndSigVertexOffset = nativeWriter.GetUnsignedConstant((uint)placedNameAndSig.SavedVertex.VertexOffset); fullMethodSignature = nativeWriter.GetTuple(containingType, placedNameAndSigVertexOffset, arguments); } // Method's dictionary pointer Vertex dictionaryVertex = nativeWriter.GetUnsignedConstant(_externalReferences.GetIndex(dictionaryNode)); Vertex entry = nativeWriter.GetTuple(dictionaryVertex, fullMethodSignature); hashtable.Append((uint)method.GetHashCode(), nativeSection.Place(entry)); } byte[] streamBytes = nativeWriter.Save(); _endSymbol.SetSymbolOffset(streamBytes.Length); return(new ObjectData(streamBytes, Array.Empty <Relocation>(), 1, new ISymbolNode[] { this, _endSymbol })); }
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { // This node does not trigger generation of other nodes. if (relocsOnly) { return(new ObjectData(Array.Empty <byte>(), Array.Empty <Relocation>(), 1, new ISymbolNode[] { this })); } var writer = new NativeWriter(); var typeMapHashTable = new VertexHashtable(); Section hashTableSection = writer.NewSection(); hashTableSection.Place(typeMapHashTable); // Get a list of all methods that have a method body and metadata from the metadata manager. foreach (var mappingEntry in factory.MetadataManager.GetMethodMapping()) { MethodDesc method = mappingEntry.Entity; // The current format requires us to have an EEType for the owning type. We might want to lift this. if (!factory.MetadataManager.TypeGeneratesEEType(method.OwningType)) { continue; } // We have a method body, we have a metadata token, but we can't get an invoke stub. Bail. if (!factory.MetadataManager.HasReflectionInvokeStub(method)) { continue; } InvokeTableFlags flags = 0; if (method.HasInstantiation) { flags |= InvokeTableFlags.IsGenericMethod; } if (method.GetCanonMethodTarget(CanonicalFormKind.Specific).RequiresInstArg()) { flags |= InvokeTableFlags.RequiresInstArg; } // TODO: better check for default public(!) constructor if (method.IsConstructor && method.Signature.Length == 0) { flags |= InvokeTableFlags.IsDefaultConstructor; } // TODO: HasVirtualInvoke if (!method.IsAbstract) { flags |= InvokeTableFlags.HasEntrypoint; } // Once we have a true multi module compilation story, we'll need to start emitting entries where this is not set. flags |= InvokeTableFlags.HasMetadataHandle; // TODO: native signature for P/Invokes and NativeCallable methods if (method.IsRawPInvoke() || method.IsNativeCallable) { continue; } // Grammar of an entry in the hash table: // Flags + DeclaringType + MetadataHandle/NameAndSig + Entrypoint + DynamicInvokeMethod + [NumGenericArgs + GenericArgs] Vertex vertex = writer.GetUnsignedConstant((uint)flags); if ((flags & InvokeTableFlags.HasMetadataHandle) != 0) { // Only store the offset portion of the metadata handle to get better integer compression vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant((uint)(mappingEntry.MetadataHandle & MetadataGeneration.MetadataOffsetMask))); } else { // TODO: no MD handle case } // Go with a necessary type symbol. It will be upgraded to a constructed one if a constructed was emitted. IEETypeNode owningTypeSymbol = factory.NecessaryTypeSymbol(method.OwningType); vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant(_externalReferences.GetIndex(owningTypeSymbol))); if ((flags & InvokeTableFlags.HasEntrypoint) != 0) { vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant(_externalReferences.GetIndex( factory.MethodEntrypoint(method.GetCanonMethodTarget(CanonicalFormKind.Specific))))); } // TODO: data to generate the generic dictionary with the type loader MethodDesc invokeStubMethod = factory.MetadataManager.GetReflectionInvokeStub(method); MethodDesc canonInvokeStubMethod = invokeStubMethod.GetCanonMethodTarget(CanonicalFormKind.Specific); if (invokeStubMethod != canonInvokeStubMethod) { vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant(_externalReferences.GetIndex(factory.FatFunctionPointer(invokeStubMethod), FatFunctionPointerConstants.Offset) << 1)); } else { vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant(_externalReferences.GetIndex(factory.MethodEntrypoint(invokeStubMethod)) << 1)); } if ((flags & InvokeTableFlags.IsGenericMethod) != 0) { if ((flags & InvokeTableFlags.RequiresInstArg) == 0 || (flags & InvokeTableFlags.HasEntrypoint) == 0) { VertexSequence args = new VertexSequence(); for (int i = 0; i < method.Instantiation.Length; i++) { uint argId = _externalReferences.GetIndex(factory.NecessaryTypeSymbol(method.Instantiation[i])); args.Append(writer.GetUnsignedConstant(argId)); } vertex = writer.GetTuple(vertex, args); } else { uint dictionaryId = _externalReferences.GetIndex(factory.MethodGenericDictionary(method)); vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant(dictionaryId)); } } int hashCode = method.GetCanonMethodTarget(CanonicalFormKind.Specific).OwningType.GetHashCode(); typeMapHashTable.Append((uint)hashCode, hashTableSection.Place(vertex)); } MemoryStream ms = new MemoryStream(); writer.Save(ms); byte[] hashTableBytes = ms.ToArray(); _endSymbol.SetSymbolOffset(hashTableBytes.Length); return(new ObjectData(hashTableBytes, Array.Empty <Relocation>(), 1, new ISymbolNode[] { this, _endSymbol })); }