diff --git a/src/ILCompiler.Compiler/src/CppCodeGen/CppWriter.cs b/src/ILCompiler.Compiler/src/CppCodeGen/CppWriter.cs index 6cfc8a350f8..c5dd6a3ca7e 100644 --- a/src/ILCompiler.Compiler/src/CppCodeGen/CppWriter.cs +++ b/src/ILCompiler.Compiler/src/CppCodeGen/CppWriter.cs @@ -729,189 +729,197 @@ private String GetCodeForVirtualMethod(MethodDesc method, int slot) return sb.ToString(); } - private void AppendVirtualSlots(CppGenerationBuffer sb, TypeDesc implType, TypeDesc declType) + private String GetCodeForNode(DependencyNode node, NodeFactory factory) { - var baseType = declType.BaseType; - if (baseType != null) - AppendVirtualSlots(sb, implType, baseType); + // virtual slots + var nodeData = (node as ObjectNode).GetData(factory, false); - IReadOnlyList virtualSlots = _compilation.NodeFactory.VTable(declType).Slots; - for (int i = 0; i < virtualSlots.Count; i++) - { - MethodDesc declMethod = virtualSlots[i]; - MethodDesc implMethod = implType.GetClosestDefType().FindVirtualFunctionTargetMethodOnObjectType(declMethod); + CppGenerationBuffer nodeCode = new CppGenerationBuffer(); - sb.AppendLine(); - if (implMethod.IsAbstract) - { - sb.Append("NULL,"); - } - else - { - sb.Append("(void*)&"); - sb.Append(GetCppMethodDeclarationName(implMethod.OwningType, GetCppMethodName(implMethod))); - sb.Append(","); - } - } - } + /* Create list of byte data. Used to divide contents between reloc and byte data + * First val - isReloc + * Second val - size of byte data if first value of tuple is false + */ - private String GetCodeForType(TypeDesc type) - { - var sb = new CppGenerationBuffer(); + List> nodeDataDivs = new List>(); + byte[] actualData = new byte[nodeData.Data.Length]; + Relocation[] relocs = nodeData.Relocs; - int totalSlots = 0; + int nextRelocOffset = -1; + int nextRelocIndex = -1; + int lastByteIndex = 0; - TypeDesc t = type; - while (t != null) + if (relocs.Length > 0) { - IReadOnlyList virtualSlots = _compilation.NodeFactory.VTable(t).Slots; - totalSlots += virtualSlots.Count; - t = t.BaseType; + nextRelocOffset = relocs[0].Offset; + nextRelocIndex = 0; } - UInt16 flags = 0; - try + int i = 0; + + int j = 0; + CppGenerationBuffer nodeDataDecl = new CppGenerationBuffer(); + int offset = 0; + if (node is ISymbolNode) { - flags = EETypeBuilderHelpers.ComputeFlags(type); + offset = (node as ISymbolNode).Offset; + i = offset; + lastByteIndex = offset; } - catch + while (i < nodeData.Data.Length) { - // TODO: Handling of missing dependencies - flags = 0; - } + if (i == nextRelocOffset) + { + Relocation reloc = relocs[nextRelocIndex]; - sb.Append("MethodTable * "); - sb.Append(GetCppMethodDeclarationName(type, "__getMethodTable")); - sb.Append("()"); - sb.AppendLine(); - sb.Append("{"); - sb.Indent(); + int size = _compilation.TypeSystemContext.Target.PointerSize; + // Make sure we've gotten the correct size for the reloc + System.Diagnostics.Debug.Assert(reloc.RelocType == (size == 8 ? RelocType.IMAGE_REL_BASED_DIR64 : RelocType.IMAGE_REL_BASED_HIGHLOW)); - sb.AppendLine(); - sb.Append("static struct {"); - sb.Indent(); - // sb.Append(GCDesc); - sb.AppendLine(); - sb.Append("RawEEType EEType;"); - if (totalSlots != 0) - { - sb.AppendLine(); - sb.Append("void * slots["); - sb.Append(totalSlots); - sb.Append("];"); - } - sb.Exdent(); - sb.AppendLine(); - sb.Append("} mt = {"); - sb.Indent(); - // gcdesc - if (type.IsString) - { - // String has non-standard layout - sb.AppendLine(); - sb.Append("{"); - sb.Indent(); - sb.AppendLine(); - sb.Append("sizeof(uint16_t),"); - sb.AppendLine(); - sb.Append("0x"); // EEType::_usComponentSize - sb.Append(flags.ToStringInvariant("x4")); // EEType::_usFlags - sb.Append(","); - sb.AppendLine(); - sb.Append("2 * sizeof(void*) + sizeof(int32_t) + 2,"); // EEType::_uBaseSize - } - else - if (type.IsSzArray) - { - sb.AppendLine(); - sb.Append("{"); - sb.Indent(); - sb.AppendLine(); - sb.Append("sizeof("); - sb.Append(GetCppSignatureTypeName(((ArrayType)type).ElementType)); // EEType::_usComponentSize - sb.Append("),"); - sb.AppendLine(); - sb.Append("0x"); - sb.Append(flags.ToStringInvariant("x4")); // EEType::_usFlags - sb.Append(","); - sb.AppendLine(); - sb.Append("3 * sizeof(void*),"); // EEType::_uBaseSize + // Update nextRelocIndex/Offset + if (++nextRelocIndex < relocs.Length) + { + nextRelocOffset = relocs[nextRelocIndex].Offset; + } + nodeDataDivs.Add(new Tuple(true, size)); + i += size; + lastByteIndex = i; + } + else + { + actualData[j] = nodeData.Data[i]; + i++; + j++; + if (i + 1 == nextRelocOffset || i + 1 == nodeData.Data.Length) + { + nodeDataDivs.Add(new Tuple(false, (i + 1) - lastByteIndex)); + } + } } - else - if (type.IsArray) + + nodeCode.Append("MethodTable * "); + if (node is EETypeNode) { - sb.AppendLine(); - sb.Append("{"); - sb.Indent(); - sb.AppendLine(); - sb.Append("sizeof("); - sb.Append(GetCppSignatureTypeName(((ArrayType)type).ElementType)); // EEType::_usComponentSize - sb.Append("),"); - sb.AppendLine(); - sb.Append("0x"); - sb.Append(flags.ToStringInvariant("x4")); // EEType::_usFlags - sb.Append(","); - sb.AppendLine(); - sb.Append("3 * sizeof(void*) + "); // EEType::_uBaseSize - sb.Append(((ArrayType)type).Rank.ToStringInvariant()); - sb.Append("* sizeof(int32_t) * 2,"); + nodeCode.Append(GetCppMethodDeclarationName((node as EETypeNode).Type, "__getMethodTable")); } else { - // sizeof(void*) == size of object header - sb.AppendLine(); - sb.Append("{"); - sb.Indent(); - sb.AppendLine(); - sb.Append("0,"); - sb.AppendLine(); - sb.Append("0x"); // EEType::_usComponentSize - sb.Append(flags.ToStringInvariant("x")); // EEType::_usFlags - sb.Append(","); - sb.AppendLine(); - sb.Append("AlignBaseSize(sizeof(void*)+sizeof("); // EEType::_uBaseSize - sb.Append(GetCppTypeName(type)); - sb.Append(")),"); + nodeCode.Append(node.GetName()); } + nodeCode.Append("()"); + nodeCode.AppendLine(); + nodeCode.Append("{"); + nodeCode.Indent(); + nodeCode.AppendLine(); + nodeCode.Append("static struct {"); - sb.AppendLine(); + nodeCode.AppendLine(); + nodeCode.Append(GetCodeForNodeStruct(nodeDataDivs, node)); - // base type - if (type.IsArray) + nodeCode.AppendLine(); + nodeCode.Append("} mt = {"); + nodeCode.Append(GetCodeForNodeData(nodeDataDivs, relocs, actualData, node)); + + nodeCode.Append("};"); + nodeCode.AppendLine(); + nodeCode.Append("return (MethodTable *)&mt;"); + nodeCode.Exdent(); + nodeCode.AppendLine(); + nodeCode.Append("}"); + + return nodeCode.ToString(); + + + } + private String GetCodeForNodeData(List> nodeDataDivs, Relocation[] relocs, byte[] byteData, DependencyNode node) + { + CppGenerationBuffer nodeDataDecl = new CppGenerationBuffer(); + int relocCounter = 0; + int divisionStartIndex = 0; + nodeDataDecl.Indent(); + nodeDataDecl.AppendLine(); + + for (int i = 0; i < nodeDataDivs.Count; i++) { - sb.Append(GetCppMethodDeclarationName(((ArrayType)type).ElementType, "__getMethodTable")); - sb.Append("()"); + nodeDataDecl.Indent(); + + if (nodeDataDivs[i].Item1) + { + Relocation reloc = relocs[relocCounter]; + if (reloc.Target is CppMethodCodeNode) + { + var method = reloc.Target as CppMethodCodeNode; + + nodeDataDecl.Append("(void*)&"); + nodeDataDecl.Append(GetCppMethodDeclarationName(method.Method.OwningType, GetCppMethodName(method.Method))); + nodeDataDecl.Append(","); + } + else if (reloc.Target is EETypeNode && node is EETypeNode && _emittedTypes.Contains((reloc.Target as EETypeNode).Type)) + { + nodeDataDecl.Append(GetCppMethodDeclarationName((reloc.Target as EETypeNode).Type, "__getMethodTable")); + nodeDataDecl.Append("(),"); + } + else + { + // TODO Add support for other relocs + nodeDataDecl.Append("NULL,"); + } + relocCounter++; + } + else + { + nodeDataDecl.Append(GetFormattedByteArray(byteData, divisionStartIndex, divisionStartIndex + nodeDataDivs[i].Item2)); + nodeDataDecl.Append(","); + divisionStartIndex += nodeDataDivs[i].Item2; + + } + nodeDataDecl.AppendLine(); + nodeDataDecl.Exdent(); + + } - else + return nodeDataDecl.ToString(); + + } + private String GetCodeForNodeStruct(List> nodeDataDivs, DependencyNode node) + { + CppGenerationBuffer nodeStructDecl = new CppGenerationBuffer(); + int relocCounter = 1; + int i = 0; + nodeStructDecl.Indent(); + + for (i = 0; i < nodeDataDivs.Count; i++) { - var baseType = type.BaseType; - if (baseType != null) + Tuple div = nodeDataDivs[i]; + if (div.Item1) { - sb.Append(GetCppMethodDeclarationName(type.BaseType, "__getMethodTable")); - sb.Append("()"); + nodeStructDecl.Append("void* reloc"); + nodeStructDecl.Append(relocCounter); + nodeStructDecl.Append(";"); + relocCounter++; } else { - sb.Append("NULL"); + nodeStructDecl.Append("unsigned char data"); + nodeStructDecl.Append((i + 1) - relocCounter); + nodeStructDecl.Append("["); + nodeStructDecl.Append(div.Item2); + nodeStructDecl.Append("];"); + } + nodeStructDecl.AppendLine(); } - sb.Exdent(); - sb.AppendLine(); - sb.Append("},"); + nodeStructDecl.Exdent(); - // virtual slots - if (!type.IsGenericDefinition && ((DependencyNode)_compilation.NodeFactory.ConstructedTypeSymbol(type)).Marked) - AppendVirtualSlots(sb, type, type); - - sb.Exdent(); - sb.AppendLine(); - sb.Append("};"); - sb.AppendLine(); - sb.Append("return (MethodTable *)&mt.EEType;"); - sb.Exdent(); - sb.AppendLine(); + return nodeStructDecl.ToString(); + } + private String GetFormattedByteArray(byte[] array, int startIndex, int endIndex) + { + CppGenerationBuffer sb = new CppGenerationBuffer(); + sb.Append("{"); + sb.Append("0x"); + sb.Append(BitConverter.ToString(array, startIndex, endIndex - startIndex).Replace("-", ",0x")); sb.Append("}"); - return sb.ToString(); } @@ -966,6 +974,7 @@ public void OutputNodes(IEnumerable nodes, MethodDesc entrypoint CppGenerationBuffer forwardDefinitions = new CppGenerationBuffer(); CppGenerationBuffer typeDefinitions = new CppGenerationBuffer(); CppGenerationBuffer methodTables = new CppGenerationBuffer(); + CppGenerationBuffer optionalFields = new CppGenerationBuffer(); DependencyNodeIterator nodeIterator = new DependencyNodeIterator(nodes); // Output well-known types to avoid build errors @@ -973,16 +982,20 @@ public void OutputNodes(IEnumerable nodes, MethodDesc entrypoint { foreach (var wellKnownTypeNode in _wellKnownTypeNodes) { - if (wellKnownTypeNode is EETypeNode) - OutputTypeNode((EETypeNode)wellKnownTypeNode, forwardDefinitions, typeDefinitions, methodTables); + OutputTypeNode(wellKnownTypeNode, factory, forwardDefinitions, typeDefinitions, methodTables); } } // Iterate through nodes foreach (var node in nodeIterator.GetNodes()) { if (node is EETypeNode && !_emittedTypes.Contains(((EETypeNode)node).Type)) + OutputTypeNode(node as EETypeNode, factory, forwardDefinitions, typeDefinitions, methodTables); - OutputTypeNode(node as EETypeNode, forwardDefinitions, typeDefinitions, methodTables); + else if (node is CppMethodCodeNode) + OutputMethodNode(node as CppMethodCodeNode, implementation); + + else if (node is EETypeOptionalFieldsNode) + optionalFields.Append(GetCodeForNode(node, factory)); } definitions.Append(forwardDefinitions.ToString()); @@ -991,14 +1004,8 @@ public void OutputNodes(IEnumerable nodes, MethodDesc entrypoint typeDefinitions.Clear(); definitions.Append(methodTables.ToString()); methodTables.Clear(); - - // Declaration and implementation are output separately. Would be better to avoid looping through code twice. - - foreach (var node in nodeIterator.GetNodes()) - { - if (node is CppMethodCodeNode) - OutputMethodCode(node as CppMethodCodeNode, implementation); - } + definitions.Append(optionalFields.ToString()); + optionalFields.Clear(); } /// @@ -1006,7 +1013,7 @@ public void OutputNodes(IEnumerable nodes, MethodDesc entrypoint /// /// The code node to be output /// The buffer in which to write out the C++ code - private void OutputMethodCode(CppMethodCodeNode methodCodeNode, CppGenerationBuffer methodImplementations) + private void OutputMethodNode(CppMethodCodeNode methodCodeNode, CppGenerationBuffer methodImplementations) { methodImplementations.AppendLine(); methodImplementations.Append(methodCodeNode.CppCode); @@ -1033,7 +1040,7 @@ private void OutputMethodCode(CppMethodCodeNode methodCodeNode, CppGenerationBuf methodImplementations.Append("}"); } } - private void OutputTypeNode(EETypeNode typeNode, CppGenerationBuffer forwardDefinitions, CppGenerationBuffer typeDefinitions, CppGenerationBuffer methodTable) + private void OutputTypeNode(IEETypeNode typeNode, NodeFactory factory, CppGenerationBuffer forwardDefinitions, CppGenerationBuffer typeDefinitions, CppGenerationBuffer methodTable) { if (_emittedTypes == null) { @@ -1049,10 +1056,10 @@ private void OutputTypeNode(EETypeNode typeNode, CppGenerationBuffer forwardDefi // Create Namespaces string mangledName = GetCppTypeName(nodeType); + int nesting = 0; int current = 0; - forwardDefinitions.AppendLine(); for (;;) { @@ -1128,9 +1135,6 @@ private void OutputTypeNode(EETypeNode typeNode, CppGenerationBuffer forwardDefi if (nodeType.HasStaticConstructor) { - typeDefinitions.AppendLine(); - typeDefinitions.Append("bool __cctor_" + GetCppTypeName(nodeType).Replace("::", "__") + ";"); - _statics.AppendLine(); _statics.Append("bool __cctor_" + GetCppTypeName(nodeType).Replace("::", "__") + ";"); } @@ -1161,18 +1165,11 @@ private void OutputTypeNode(EETypeNode typeNode, CppGenerationBuffer forwardDefi // declare method table if (!nodeType.IsPointer && !nodeType.IsByRef) { - methodTable.Append(GetCodeForType(nodeType)); + methodTable.Append(GetCodeForNode(typeNode as DependencyNode, factory)); methodTable.AppendEmptyLine(); } } - private string GenerateMethodCode() - { - var methodCode = new CppGenerationBuffer(); - - return methodCode.ToString(); - } - public void OutputCode(IEnumerable nodes, MethodDesc entrypoint, NodeFactory factory) { var sb = new CppGenerationBuffer(); diff --git a/src/ILCompiler.Compiler/src/CppCodeGen/DependencyNodeIterator.cs b/src/ILCompiler.Compiler/src/CppCodeGen/DependencyNodeIterator.cs index 2ad6ca7ac4a..0020210f609 100644 --- a/src/ILCompiler.Compiler/src/CppCodeGen/DependencyNodeIterator.cs +++ b/src/ILCompiler.Compiler/src/CppCodeGen/DependencyNodeIterator.cs @@ -36,7 +36,7 @@ public DependencyNodeIterator(IEnumerable nodes) } } // Assume ordering doesn't matter - else if (node is CppMethodCodeNode) _nodes.Add(node); + else _nodes.Add(node); } foreach (var node in _typeToNodeMap.Values) diff --git a/src/Native/Bootstrap/common.h b/src/Native/Bootstrap/common.h index 95477f1bc0b..1aa9679e310 100644 --- a/src/Native/Bootstrap/common.h +++ b/src/Native/Bootstrap/common.h @@ -70,6 +70,7 @@ struct RawEEType uint16_t m_usNumVtableSlots; uint16_t m_usNumInterfaces; uint32_t m_uHashCode; + void* m_pIndirectionModule; }; struct ReversePInvokeFrame