public void OutputCode(IEnumerable <DependencyNode> nodes, MethodDesc entrypoint, NodeFactory factory) { BuildMethodLists(nodes); ExpandTypes(); Out.WriteLine("#include \"common.h\""); Out.WriteLine("#include \"CppCodeGen.h\""); Out.WriteLine(); _statics = new CppGenerationBuffer(); _statics.Indent(); _gcStatics = new CppGenerationBuffer(); _gcStatics.Indent(); _threadStatics = new CppGenerationBuffer(); _threadStatics.Indent(); _gcThreadStatics = new CppGenerationBuffer(); _gcThreadStatics.Indent(); OutputNodes(nodes, factory); Out.Write("struct {"); Out.Write(_statics.ToString()); Out.Write("} __statics;"); Out.Write("struct {"); Out.Write(_gcStatics.ToString()); Out.Write("} __gcStatics;"); Out.Write("struct {"); Out.Write(_gcStatics.ToString()); Out.Write("} __gcThreadStatics;"); OutputExternCSignatures(); foreach (var node in nodes) { if (node is CppMethodCodeNode) { OutputMethodNode(node as CppMethodCodeNode); } } if (entrypoint != null) { OutputMainMethodStub(entrypoint); } Out.Dispose(); }
private String GetCodeForNodeData(List <NodeDataSection> nodeDataSections, Relocation[] relocs, byte[] byteData, DependencyNode node, int offset, NodeFactory factory) { CppGenerationBuffer nodeDataDecl = new CppGenerationBuffer(); int relocCounter = 0; int divisionStartIndex = offset; nodeDataDecl.Indent(); nodeDataDecl.Indent(); nodeDataDecl.AppendLine(); for (int i = 0; i < nodeDataSections.Count; i++) { if (nodeDataSections[i].SectionType == NodeDataSectionType.Relocation) { Relocation reloc = relocs[relocCounter]; nodeDataDecl.Append(GetCodeForReloc(reloc, node, factory)); nodeDataDecl.Append(","); relocCounter++; } else { AppendFormattedByteArray(nodeDataDecl, byteData, divisionStartIndex, divisionStartIndex + nodeDataSections[i].SectionSize); nodeDataDecl.Append(","); } divisionStartIndex += nodeDataSections[i].SectionSize; nodeDataDecl.AppendLine(); } return(nodeDataDecl.ToString()); }
private String GetCodeForVirtualMethod(MethodDesc method, int slot) { var sb = new CppGenerationBuffer(); AppendSlotTypeDef(sb, method); sb.AppendLine(); sb.Append("static __slot__"); sb.Append(GetCppMethodName(method)); sb.Append(" __getslot__"); sb.Append(GetCppMethodName(method)); sb.Append("(void * pThis)"); sb.AppendLine(); sb.Append("{"); sb.Indent(); sb.AppendLine(); sb.Append(" return (__slot__"); sb.Append(GetCppMethodName(method)); sb.Append(")*((void **)(*((RawEEType **)pThis) + 1) + "); sb.Append(slot.ToStringInvariant()); sb.Append(");"); sb.Exdent(); sb.AppendLine(); sb.Append("};"); return(sb.ToString()); }
private String GetCodeForNodeStruct(List <NodeDataSection> nodeDataDivs, DependencyNode node) { CppGenerationBuffer nodeStructDecl = new CppGenerationBuffer(); int relocCounter = 1; int i = 0; nodeStructDecl.Indent(); for (i = 0; i < nodeDataDivs.Count; i++) { NodeDataSection section = nodeDataDivs[i]; if (section.SectionType == NodeDataSectionType.Relocation) { nodeStructDecl.Append("void* reloc"); nodeStructDecl.Append(relocCounter); nodeStructDecl.Append(";"); relocCounter++; } else { nodeStructDecl.Append("unsigned char data"); nodeStructDecl.Append((i + 1) - relocCounter); nodeStructDecl.Append("["); nodeStructDecl.Append(section.SectionSize); nodeStructDecl.Append("];"); } nodeStructDecl.AppendLine(); } nodeStructDecl.Exdent(); return(nodeStructDecl.ToString()); }
/// <summary> /// Output C++ code for a given codeNode /// </summary> /// <param name="methodCodeNode">The code node to be output</param> /// <param name="methodImplementations">The buffer in which to write out the C++ code</param> private void OutputMethodNode(CppMethodCodeNode methodCodeNode) { Out.WriteLine(); Out.Write(methodCodeNode.CppCode); var alternateName = _compilation.NodeFactory.GetSymbolAlternateName(methodCodeNode); if (alternateName != null) { CppGenerationBuffer sb = new CppGenerationBuffer(); sb.AppendLine(); AppendCppMethodDeclaration(sb, methodCodeNode.Method, true, alternateName); sb.AppendLine(); sb.Append("{"); sb.Indent(); sb.AppendLine(); if (!methodCodeNode.Method.Signature.ReturnType.IsVoid) { sb.Append("return "); } sb.Append(GetCppMethodDeclarationName(methodCodeNode.Method.OwningType, GetCppMethodName(methodCodeNode.Method))); sb.Append("("); AppendCppMethodCallParamList(sb, methodCodeNode.Method); sb.Append(");"); sb.Exdent(); sb.AppendLine(); sb.Append("}"); Out.Write(sb.ToString()); } }
private String GetCodeForDelegate(TypeDesc delegateType) { var sb = new CppGenerationBuffer(); MethodDesc method = delegateType.GetKnownMethod("Invoke", null); AppendSlotTypeDef(sb, method); sb.AppendLine(); sb.Append("static __slot__"); sb.Append(GetCppMethodName(method)); sb.Append(" __invoke__"); sb.Append(GetCppMethodName(method)); sb.Append("(void * pThis)"); sb.AppendLine(); sb.Append("{"); sb.Indent(); sb.AppendLine(); sb.Append("return (__slot__"); sb.Append(GetCppMethodName(method)); sb.Append(")((("); sb.Append(GetCppSignatureTypeName(_compilation.TypeSystemContext.GetWellKnownType(WellKnownType.MulticastDelegate))); sb.Append(")pThis)->m_functionPointer);"); sb.Exdent(); sb.AppendLine(); sb.Append("};"); return(sb.ToString()); }
private String GetCodeForReloc(Relocation reloc, DependencyNode node, NodeFactory factory) { CppGenerationBuffer relocCode = new CppGenerationBuffer(); if (reloc.Target is CppMethodCodeNode) { var method = reloc.Target as CppMethodCodeNode; relocCode.Append("(void*)&"); relocCode.Append(GetCppMethodDeclarationName(method.Method.OwningType, GetCppMethodName(method.Method), false)); } else if (reloc.Target is EETypeNode && node is EETypeNode) { relocCode.Append(GetCppMethodDeclarationName((reloc.Target as EETypeNode).Type, "__getMethodTable", false)); relocCode.Append("()"); } // Node is either an non-emitted type or a generic composition - both are ignored for CPP codegen else if ((reloc.Target is TypeManagerIndirectionNode || reloc.Target is InterfaceDispatchMapNode || reloc.Target is EETypeOptionalFieldsNode || reloc.Target is GenericCompositionNode) && !(reloc.Target as ObjectNode).ShouldSkipEmittingObjectNode(factory)) { string mangledTargetName = reloc.Target.GetMangledName(factory.NameMangler); bool shouldReplaceNamespaceQualifier = reloc.Target is GenericCompositionNode || reloc.Target is EETypeOptionalFieldsNode; relocCode.Append(shouldReplaceNamespaceQualifier ? mangledTargetName.Replace("::", "_") : mangledTargetName); relocCode.Append("()"); } else if (reloc.Target is ObjectAndOffsetSymbolNode && (reloc.Target as ObjectAndOffsetSymbolNode).Target is ArrayOfEmbeddedPointersNode <InterfaceDispatchMapNode> ) { relocCode.Append("dispatchMapModule"); } else { relocCode.Append("NULL"); } return(relocCode.ToString()); }
private void CompileExternMethod(CppMethodCodeNode methodCodeNodeNeedingCode, string importName) { MethodDesc method = methodCodeNodeNeedingCode.Method; MethodSignature methodSignature = method.Signature; bool slotCastRequired = false; MethodSignature externCSignature; if (_externCSignatureMap.TryGetValue(importName, out externCSignature)) { slotCastRequired = !externCSignature.Equals(methodSignature); } else { _externCSignatureMap.Add(importName, methodSignature); externCSignature = methodSignature; } var sb = new CppGenerationBuffer(); sb.AppendLine(); AppendCppMethodDeclaration(sb, method, true); sb.AppendLine(); sb.Append("{"); sb.Indent(); if (slotCastRequired) { AppendSlotTypeDef(sb, method); } sb.AppendLine(); if (!method.Signature.ReturnType.IsVoid) { sb.Append("return "); } if (slotCastRequired) { sb.Append("((__slot__" + GetCppMethodName(method) + ")"); } sb.Append("::"); sb.Append(importName); if (slotCastRequired) { sb.Append(")"); } sb.Append("("); AppendCppMethodCallParamList(sb, method); sb.Append(");"); sb.Exdent(); sb.AppendLine(); sb.Append("}"); methodCodeNodeNeedingCode.SetCode(sb.ToString(), Array.Empty <Object>()); }
private void OutputMainMethodStub(MethodDesc entrypoint) { var sb = new CppGenerationBuffer(); // Stub for main method sb.AppendLine(); if (_compilation.TypeSystemContext.Target.OperatingSystem == TargetOS.Windows) { sb.Append("int wmain(int argc, wchar_t * argv[]) { "); } else { sb.Append("int main(int argc, char * argv[]) {"); } sb.Indent(); sb.AppendLine(); sb.Append("if (__initialize_runtime() != 0)"); sb.Indent(); sb.AppendLine(); sb.Append("return -1;"); sb.Exdent(); sb.AppendEmptyLine(); sb.AppendLine(); sb.Append("ReversePInvokeFrame frame;"); sb.AppendLine(); sb.Append("__reverse_pinvoke(&frame);"); sb.AppendEmptyLine(); sb.AppendLine(); sb.Append("int ret = "); sb.Append(GetCppMethodDeclarationName(entrypoint.OwningType, GetCppMethodName(entrypoint))); sb.Append("(argc, (intptr_t)argv);"); sb.AppendEmptyLine(); sb.AppendLine(); sb.Append("__reverse_pinvoke_return(&frame);"); sb.AppendLine(); sb.Append("__shutdown_runtime();"); sb.AppendLine(); sb.Append("return ret;"); sb.Exdent(); sb.AppendLine(); sb.Append("}"); Out.Write(sb.ToString()); }
public string GetCppMethodCallParamList(MethodDesc method) { var sb = new CppGenerationBuffer(); var methodSignature = method.Signature; bool hasThis = !methodSignature.IsStatic; int argCount = methodSignature.Length; if (hasThis) { argCount++; } List <string> parameterNames = null; IEnumerable <string> parameters = _compilation.TypeSystemContext.GetParameterNamesForMethod(method); if (parameters != null) { parameterNames = new List <string>(parameters); if (parameterNames.Count != 0) { System.Diagnostics.Debug.Assert(parameterNames.Count == argCount); } else { parameterNames = null; } } for (int i = 0; i < argCount; i++) { if (parameterNames != null) { sb.Append(SanitizeCppVarName(parameterNames[i])); } else { sb.Append("_a"); sb.Append(i.ToStringInvariant()); } if (i != argCount - 1) { sb.Append(", "); } } return(sb.ToString()); }
private String GetCodeForNodeData(List <NodeDataSection> nodeDataSections, Relocation[] relocs, byte[] byteData, DependencyNode node, int offset) { CppGenerationBuffer nodeDataDecl = new CppGenerationBuffer(); int relocCounter = 0; int divisionStartIndex = offset; nodeDataDecl.Indent(); nodeDataDecl.AppendLine(); for (int i = 0; i < nodeDataSections.Count; i++) { nodeDataDecl.Indent(); if (nodeDataSections[i].SectionType == NodeDataSectionType.Relocation) { 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 { AppendFormattedByteArray(nodeDataDecl, byteData, divisionStartIndex, divisionStartIndex + nodeDataSections[i].SectionSize); nodeDataDecl.Append(","); } divisionStartIndex += nodeDataSections[i].SectionSize; nodeDataDecl.AppendLine(); nodeDataDecl.Exdent(); } return(nodeDataDecl.ToString()); }
private void OutputExternCSignatures() { var sb = new CppGenerationBuffer(); foreach (var externC in _externCSignatureMap) { string importName = externC.Key; // TODO: hacky special-case if (importName != "memmove" && importName != "malloc") // some methods are already declared by the CRT headers { sb.AppendLine(); AppendCppMethodDeclaration(sb, null, false, importName, externC.Value); } } Out.Write(sb.ToString()); }
private String GetCodeForReadyToRunHeader(ReadyToRunHeaderNode headerNode, NodeFactory factory) { CppGenerationBuffer rtrHeader = new CppGenerationBuffer(); rtrHeader.Append(GetCodeForObjectNode(headerNode, factory)); rtrHeader.AppendLine(); rtrHeader.Append("void* RtRHeaderWrapper() {"); rtrHeader.Indent(); rtrHeader.AppendLine(); rtrHeader.Append("static struct {"); rtrHeader.AppendLine(); rtrHeader.Append("unsigned char leftPadding[8];"); rtrHeader.AppendLine(); rtrHeader.Append("void* rtrHeader;"); rtrHeader.AppendLine(); rtrHeader.Append("unsigned char rightPadding[8];"); rtrHeader.AppendLine(); rtrHeader.Append("} rtrHeaderWrapper = {"); rtrHeader.Indent(); rtrHeader.AppendLine(); rtrHeader.Append("{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },"); rtrHeader.AppendLine(); rtrHeader.Append("(void*)"); rtrHeader.Append(headerNode.GetMangledName()); rtrHeader.Append("(),"); rtrHeader.AppendLine(); rtrHeader.Append("{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }"); rtrHeader.AppendLine(); rtrHeader.Append("};"); rtrHeader.Exdent(); rtrHeader.AppendLine(); rtrHeader.Append("return (void *)&rtrHeaderWrapper;"); rtrHeader.Exdent(); rtrHeader.AppendLine(); rtrHeader.Append("}"); rtrHeader.AppendLine(); return(rtrHeader.ToString()); }
/// <summary> /// Output C++ code via a given dependency graph /// </summary> /// <param name="nodes">A set of dependency nodes</param> /// <param name="entrypoint">Code entrypoint</param> /// <param name="factory">Associated NodeFactory instance</param> private void OutputNodes(IEnumerable <DependencyNode> nodes, NodeFactory factory) { CppGenerationBuffer forwardDefinitions = new CppGenerationBuffer(); CppGenerationBuffer typeDefinitions = new CppGenerationBuffer(); CppGenerationBuffer methodTables = new CppGenerationBuffer(); CppGenerationBuffer optionalFields = new CppGenerationBuffer(); DependencyNodeIterator nodeIterator = new DependencyNodeIterator(nodes, factory); // Output well-known types to avoid build errors if (_wellKnownTypeNodes != null) { foreach (var wellKnownTypeNode in _wellKnownTypeNodes) { 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); } // TODO: Remove the need for the skip check // https://github.com/dotnet/corert/issues/1826 else if (node is EETypeOptionalFieldsNode && (node as ObjectNode).ShouldSkipEmittingObjectNode(factory)) { optionalFields.Append(GetCodeForObjectNode(node as EETypeOptionalFieldsNode, factory)); } } Out.Write(forwardDefinitions.ToString()); Out.Write(typeDefinitions.ToString()); Out.Write(methodTables.ToString()); Out.Write(optionalFields.ToString()); }
public void CompileMethod(CppMethodCodeNode methodCodeNodeNeedingCode) { MethodDesc method = methodCodeNodeNeedingCode.Method; _compilation.Logger.Writer.WriteLine("Compiling " + method.ToString()); if (method.HasCustomAttribute("System.Runtime", "RuntimeImportAttribute")) { CompileExternMethod(methodCodeNodeNeedingCode, ((EcmaMethod)method).GetRuntimeImportName()); return; } if (method.IsRawPInvoke()) { CompileExternMethod(methodCodeNodeNeedingCode, method.GetPInvokeMethodMetadata().Name ?? method.Name); return; } var methodIL = _compilation.GetMethodIL(method); if (methodIL == null) { return; } // TODO: Remove this code once CppCodegen is able to generate code for the reflection startup path. // The startup path runs before any user code is executed. // For now we replace the startup path with a simple "ret". Reflection won't work, but // programs not using reflection will. if (method.Name == ".cctor") { MetadataType owningType = method.OwningType as MetadataType; if (owningType != null && owningType.Name == "ReflectionExecution" && owningType.Namespace == "Internal.Reflection.Execution") { methodIL = new Internal.IL.Stubs.ILStubMethodIL(method, new byte[] { (byte)ILOpcode.ret }, Array.Empty <LocalVariableDefinition>(), null); } } try { // TODO: hacky special-case if (method.Name == "_ecvt_s") { throw new NotImplementedException(); } var ilImporter = new ILImporter(_compilation, this, method, methodIL); CompilerTypeSystemContext typeSystemContext = _compilation.TypeSystemContext; MethodDebugInformation debugInfo = _compilation.GetDebugInfo(methodIL); if (!_compilation.Options.HasOption(CppCodegenConfigProvider.NoLineNumbersString)) { IEnumerable <ILSequencePoint> sequencePoints = debugInfo.GetSequencePoints(); if (sequencePoints != null) { ilImporter.SetSequencePoints(sequencePoints); } } IEnumerable <ILLocalVariable> localVariables = debugInfo.GetLocalVariables(); if (localVariables != null) { ilImporter.SetLocalVariables(localVariables); } IEnumerable <string> parameters = GetParameterNamesForMethod(method); if (parameters != null) { ilImporter.SetParameterNames(parameters); } ilImporter.Compile(methodCodeNodeNeedingCode); } catch (Exception e) { _compilation.Logger.Writer.WriteLine(e.Message + " (" + method + ")"); var sb = new CppGenerationBuffer(); sb.AppendLine(); AppendCppMethodDeclaration(sb, method, true); sb.AppendLine(); sb.Append("{"); sb.Indent(); sb.AppendLine(); sb.Append("throw 0xC000C000;"); sb.Exdent(); sb.AppendLine(); sb.Append("}"); methodCodeNodeNeedingCode.SetCode(sb.ToString(), Array.Empty <Object>()); } }
private void OutputTypes(bool full) { var sb = new CppGenerationBuffer(); if (full) { _statics = new CppGenerationBuffer(); _statics.Indent(); _gcStatics = new CppGenerationBuffer(); _gcStatics.Indent(); _threadStatics = new CppGenerationBuffer(); _threadStatics.Indent(); _gcThreadStatics = new CppGenerationBuffer(); _gcThreadStatics.Indent(); } _emittedTypes = new HashSet <TypeDesc>(); foreach (var t in _cppSignatureNames.Keys) { if (t.IsByRef || t.IsPointer) { continue; } // Base class types and valuetype instantance field types may be emitted out-of-order to make them // appear before they are used. if (_emittedTypes.Contains(t)) { continue; } OutputType(sb, t, full); } _emittedTypes = null; if (full) { sb.AppendLine(); sb.Append("struct {"); // No need to indent or add a new line as _statics is already properly indented sb.Append(_statics.ToString()); sb.AppendLine(); sb.Append("} __statics;"); // TODO: Register GC statics with GC sb.AppendLine(); sb.Append("struct {"); // No need to indent or add a new line as _gcStatics is already properly indented sb.Append(_gcStatics.ToString()); sb.AppendLine(); sb.Append("} __gcStatics;"); sb.AppendLine(); _statics = null; _gcStatics = null; _threadStatics = null; _gcThreadStatics = null; } Out.Write(sb.ToString()); sb.Clear(); }
public void CompileMethod(CppMethodCodeNode methodCodeNodeNeedingCode) { MethodDesc method = methodCodeNodeNeedingCode.Method; _compilation.Log.WriteLine("Compiling " + method.ToString()); SpecialMethodKind kind = method.DetectSpecialMethodKind(); if (kind != SpecialMethodKind.Unknown) { string specialMethodCode = CompileSpecialMethod(method, kind); methodCodeNodeNeedingCode.SetCode(specialMethodCode, Array.Empty <Object>()); return; } var methodIL = _compilation.GetMethodIL(method); if (methodIL == null) { return; } try { var ilImporter = new ILImporter(_compilation, this, method, methodIL); CompilerTypeSystemContext typeSystemContext = _compilation.TypeSystemContext; if (!_compilation.Options.NoLineNumbers) { IEnumerable <ILSequencePoint> sequencePoints = typeSystemContext.GetSequencePointsForMethod(method); if (sequencePoints != null) { ilImporter.SetSequencePoints(sequencePoints); } } IEnumerable <ILLocalVariable> localVariables = typeSystemContext.GetLocalVariableNamesForMethod(method); if (localVariables != null) { ilImporter.SetLocalVariables(localVariables); } IEnumerable <string> parameters = typeSystemContext.GetParameterNamesForMethod(method); if (parameters != null) { ilImporter.SetParameterNames(parameters); } ilImporter.Compile(methodCodeNodeNeedingCode); } catch (Exception e) { _compilation.Log.WriteLine(e.Message + " (" + method + ")"); var builder = new CppGenerationBuffer(); builder.AppendLine(); builder.Append(GetCppMethodDeclaration(method, true)); builder.AppendLine(); builder.Append("{"); builder.Indent(); builder.AppendLine(); builder.Append("throw 0xC000C000;"); builder.Exdent(); builder.AppendLine(); builder.Append("}"); methodCodeNodeNeedingCode.SetCode(builder.ToString(), Array.Empty <Object>()); } }
private string CompileSpecialMethod(MethodDesc method, SpecialMethodKind kind) { var builder = new CppGenerationBuffer(); switch (kind) { case SpecialMethodKind.PInvoke: case SpecialMethodKind.RuntimeImport: { EcmaMethod ecmaMethod = method as EcmaMethod; string importName = kind == SpecialMethodKind.PInvoke ? method.GetPInvokeMethodMetadata().Name : ecmaMethod.GetAttributeStringValue("System.Runtime", "RuntimeImportAttribute"); if (importName == null) { importName = method.Name; } MethodSignature methodSignature = method.Signature; bool slotCastRequired = false; MethodSignature externCSignature; if (_externCSignatureMap.TryGetValue(importName, out externCSignature)) { slotCastRequired = !externCSignature.Equals(method.Signature); } else { _externCSignatureMap.Add(importName, methodSignature); externCSignature = methodSignature; } builder.AppendLine(); builder.Append(GetCppMethodDeclaration(method, true)); builder.AppendLine(); builder.Append("{"); builder.Indent(); if (slotCastRequired) { AppendSlotTypeDef(builder, method); } builder.AppendLine(); if (!method.Signature.ReturnType.IsVoid) { builder.Append("return "); } if (slotCastRequired) { builder.Append("((__slot__" + GetCppMethodName(method) + ")"); } builder.Append("::"); builder.Append(importName); if (slotCastRequired) { builder.Append(")"); } builder.Append("("); builder.Append(GetCppMethodCallParamList(method)); builder.Append(");"); builder.Exdent(); builder.AppendLine(); builder.Append("}"); return(builder.ToString()); } default: builder.AppendLine(); builder.Append(GetCppMethodDeclaration(method, true)); builder.AppendLine(); builder.Append("{"); builder.Indent(); builder.AppendLine(); builder.Append("throw 0xC000C000;"); builder.Exdent(); builder.AppendLine(); builder.Append("}"); return(builder.ToString()); } }
public void OutputCode(IEnumerable <DependencyNode> nodes, MethodDesc entrypoint) { BuildMethodLists(nodes); ExpandTypes(); Out.WriteLine("#include \"common.h\""); Out.WriteLine("#include \"CppCodeGen.h\""); Out.WriteLine(); Out.Write("/* Forward type definitions */"); OutputTypes(false); Out.WriteLine(); Out.WriteLine(); Out.Write("/* Type definitions */"); OutputTypes(true); var sb = new CppGenerationBuffer(); foreach (var externC in _externCSignatureMap) { string importName = externC.Key; // TODO: hacky special-case if (importName != "memmove" && importName != "malloc") // some methods are already declared by the CRT headers { sb.AppendLine(); sb.Append(GetCppMethodDeclaration(null, false, importName, externC.Value)); } } Out.Write(sb.ToString()); sb.Clear(); foreach (var t in _cppSignatureNames.Keys) { // TODO: Enable once the dependencies are tracked for arrays // if (((DependencyNode)_compilation.NodeFactory.ConstructedTypeSymbol(t)).Marked) if (!t.IsPointer && !t.IsByRef) { sb.AppendLine(); sb.Append(GetCodeForType(t)); } List <MethodDesc> methodList; if (_methodLists.TryGetValue(t, out methodList)) { foreach (var m in methodList) { var methodCodeNode = (CppMethodCodeNode)_compilation.NodeFactory.MethodEntrypoint(m); sb.AppendLine(); sb.Append(methodCodeNode.CppCode); var alternateName = _compilation.NodeFactory.GetSymbolAlternateName(methodCodeNode); if (alternateName != null) { sb.AppendLine(); sb.Append(GetCppMethodDeclaration(m, true, alternateName)); sb.AppendLine(); sb.Append("{"); sb.Indent(); sb.AppendLine(); if (!m.Signature.ReturnType.IsVoid) { sb.Append("return "); } sb.Append(GetCppMethodDeclarationName(m.OwningType, GetCppMethodName(m))); sb.Append("("); sb.Append(GetCppMethodCallParamList(m)); sb.Append(");"); sb.Exdent(); sb.AppendLine(); sb.Append("}"); } } } } Out.Write(sb.ToString()); sb.Clear(); if (entrypoint != null) { // Stub for main method sb.AppendLine(); if (_compilation.TypeSystemContext.Target.OperatingSystem == TargetOS.Windows) { sb.Append("int wmain(int argc, wchar_t * argv[]) { "); } else { sb.Append("int main(int argc, char * argv[]) {"); } sb.Indent(); sb.AppendLine(); sb.Append("if (__initialize_runtime() != 0)"); sb.Indent(); sb.AppendLine(); sb.Append("return -1;"); sb.Exdent(); sb.AppendEmptyLine(); sb.AppendLine(); sb.Append("ReversePInvokeFrame frame;"); sb.AppendLine(); sb.Append("__reverse_pinvoke(&frame);"); sb.AppendEmptyLine(); sb.AppendLine(); sb.Append("int ret = "); sb.Append(GetCppMethodDeclarationName(entrypoint.OwningType, GetCppMethodName(entrypoint))); sb.Append("(argc-1, (intptr_t)(argv+1));"); sb.AppendEmptyLine(); sb.AppendLine(); sb.Append("__reverse_pinvoke_return(&frame);"); sb.AppendLine(); sb.Append("__shutdown_runtime();"); sb.AppendLine(); sb.Append("return ret;"); sb.Exdent(); sb.AppendLine(); sb.Append("}"); } Out.Write(sb.ToString()); sb.Clear(); Out.Dispose(); }
public string GetCppMethodDeclaration(MethodDesc method, bool implementation, string externalMethodName = null, MethodSignature methodSignature = null) { var sb = new CppGenerationBuffer(); if (methodSignature == null) { methodSignature = method.Signature; } if (externalMethodName != null) { sb.Append("extern \"C\" "); } else { if (!implementation) { sb.Append("static "); } } sb.Append(GetCppSignatureTypeName(methodSignature.ReturnType)); sb.Append(" "); if (externalMethodName != null) { sb.Append(externalMethodName); } else { if (implementation) { sb.Append(GetCppMethodDeclarationName(method.OwningType, GetCppMethodName(method))); } else { sb.Append(GetCppMethodName(method)); } } sb.Append("("); bool hasThis = !methodSignature.IsStatic; int argCount = methodSignature.Length; if (hasThis) { argCount++; } List <string> parameterNames = null; if (method != null) { IEnumerable <string> parameters = _compilation.TypeSystemContext.GetParameterNamesForMethod(method); if (parameters != null) { parameterNames = new List <string>(parameters); if (parameterNames.Count != 0) { System.Diagnostics.Debug.Assert(parameterNames.Count == argCount); } else { parameterNames = null; } } } for (int i = 0; i < argCount; i++) { if (hasThis) { if (i == 0) { var thisType = method.OwningType; if (thisType.IsValueType) { thisType = thisType.MakeByRefType(); } sb.Append(GetCppSignatureTypeName(thisType)); } else { sb.Append(GetCppSignatureTypeName(methodSignature[i - 1])); } } else { sb.Append(GetCppSignatureTypeName(methodSignature[i])); } if (implementation) { sb.Append(" "); if (parameterNames != null) { sb.Append(SanitizeCppVarName(parameterNames[i])); } else { sb.Append("_a"); sb.Append(i.ToStringInvariant()); } } if (i != argCount - 1) { sb.Append(", "); } } sb.Append(")"); if (!implementation) { sb.Append(";"); } return(sb.ToString()); }
private String GetCodeForType(TypeDesc type) { var sb = new CppGenerationBuffer(); int totalSlots = 0; TypeDesc t = type; while (t != null) { IReadOnlyList <MethodDesc> virtualSlots = _compilation.NodeFactory.VTable(t).Slots; totalSlots += virtualSlots.Count; t = t.BaseType; } UInt16 flags = 0; try { flags = EETypeBuilderHelpers.ComputeFlags(type); } catch { // TODO: Handling of missing dependencies flags = 0; } sb.Append("MethodTable * "); sb.Append(GetCppMethodDeclarationName(type, "__getMethodTable")); sb.Append("()"); sb.AppendLine(); sb.Append("{"); sb.Indent(); 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 } else if (type.IsArray) { 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,"); } 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(")),"); } sb.AppendLine(); // base type if (type.IsArray) { sb.Append(GetCppMethodDeclarationName(((ArrayType)type).ElementType, "__getMethodTable")); sb.Append("()"); } else { var baseType = type.BaseType; if (baseType != null) { sb.Append(GetCppMethodDeclarationName(type.BaseType, "__getMethodTable")); sb.Append("()"); } else { sb.Append("NULL"); } } sb.Exdent(); sb.AppendLine(); sb.Append("},"); // virtual slots if (((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(); sb.Append("}"); return(sb.ToString()); }
/// <summary> /// Output C++ code via a given dependency graph /// </summary> /// <param name="nodes">A set of dependency nodes</param> /// <param name="entrypoint">Code entrypoint</param> /// <param name="factory">Associated NodeFactory instance</param> /// <param name="definitions">Text buffer in which the type and method definitions will be written</param> /// <param name="implementation">Text buffer in which the method implementations will be written</param> public void OutputNodes(IEnumerable <DependencyNode> nodes, NodeFactory factory) { CppGenerationBuffer dispatchPointers = new CppGenerationBuffer(); CppGenerationBuffer forwardDefinitions = new CppGenerationBuffer(); CppGenerationBuffer typeDefinitions = new CppGenerationBuffer(); CppGenerationBuffer methodTables = new CppGenerationBuffer(); CppGenerationBuffer additionalNodes = new CppGenerationBuffer(); DependencyNodeIterator nodeIterator = new DependencyNodeIterator(nodes); // Number of InterfaceDispatchMapNodes needs to be declared explicitly for Ubuntu and OSX int dispatchMapCount = 0; dispatchPointers.AppendLine(); dispatchPointers.Indent(); //RTR header needs to be declared after all modules have already been output string rtrHeader = string.Empty; // Iterate through nodes foreach (var node in nodeIterator.GetNodes()) { if (node is EETypeNode) { OutputTypeNode(node as EETypeNode, factory, forwardDefinitions, typeDefinitions, methodTables); } else if ((node is EETypeOptionalFieldsNode || node is TypeManagerIndirectionNode || node is GenericCompositionNode) && !(node as ObjectNode).ShouldSkipEmittingObjectNode(factory)) { additionalNodes.Append(GetCodeForObjectNode(node as ObjectNode, factory)); } else if (node is InterfaceDispatchMapNode) { dispatchPointers.Append("(void *)"); dispatchPointers.Append(((ISymbolNode)node).GetMangledName(factory.NameMangler)); dispatchPointers.Append("(),"); dispatchPointers.AppendLine(); dispatchMapCount++; additionalNodes.Append(GetCodeForObjectNode(node as ObjectNode, factory)); } else if (node is ReadyToRunHeaderNode) { rtrHeader = GetCodeForReadyToRunHeader(node as ReadyToRunHeaderNode, factory); } } dispatchPointers.AppendLine(); dispatchPointers.Exdent(); Out.Write(forwardDefinitions.ToString()); Out.Write(typeDefinitions.ToString()); Out.Write(additionalNodes.ToString()); Out.Write(methodTables.ToString()); // Emit pointers to dispatch map nodes, to be used in interface dispatch Out.Write("void * dispatchMapModule["); Out.Write(dispatchMapCount); Out.Write("] = {"); Out.Write(dispatchPointers.ToString()); Out.Write("};"); Out.Write(rtrHeader); }
private String GetCodeForReadyToRunHeader(ReadyToRunHeaderNode headerNode, NodeFactory factory) { CppGenerationBuffer rtrHeader = new CppGenerationBuffer(); int pointerSize = _compilation.TypeSystemContext.Target.PointerSize; rtrHeader.Append(GetCodeForObjectNode(headerNode, factory)); rtrHeader.AppendLine(); rtrHeader.Append("void* RtRHeaderWrapper() {"); rtrHeader.Indent(); rtrHeader.AppendLine(); rtrHeader.Append("static struct {"); rtrHeader.AppendLine(); if (pointerSize == 8) { rtrHeader.Append("unsigned char leftPadding[8];"); } else { rtrHeader.Append("unsigned char leftPadding[4];"); } rtrHeader.AppendLine(); rtrHeader.Append("void* rtrHeader;"); rtrHeader.AppendLine(); if (pointerSize == 8) { rtrHeader.Append("unsigned char rightPadding[8];"); } else { rtrHeader.Append("unsigned char rightPadding[4];"); } rtrHeader.AppendLine(); rtrHeader.Append("} rtrHeaderWrapper = {"); rtrHeader.Indent(); rtrHeader.AppendLine(); if (pointerSize == 8) { rtrHeader.Append("{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },"); } else { rtrHeader.Append("{ 0x00,0x00,0x00,0x00 },"); } rtrHeader.AppendLine(); rtrHeader.Append("(void*)"); rtrHeader.Append(headerNode.GetMangledName(factory.NameMangler)); rtrHeader.Append("(),"); rtrHeader.AppendLine(); if (pointerSize == 8) { rtrHeader.Append("{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }"); } else { rtrHeader.Append("{ 0x00,0x00,0x00,0x00 },"); } rtrHeader.AppendLine(); rtrHeader.Append("};"); rtrHeader.Exdent(); rtrHeader.AppendLine(); rtrHeader.Append("return (void *)&rtrHeaderWrapper;"); rtrHeader.Exdent(); rtrHeader.AppendLine(); rtrHeader.Append("}"); rtrHeader.AppendLine(); return(rtrHeader.ToString()); }
private void OutputTypes(bool full) { var sb = new CppGenerationBuffer(); if (full) { _statics = new CppGenerationBuffer(); _statics.Indent(); _gcStatics = new CppGenerationBuffer(); _gcStatics.Indent(); _threadStatics = new CppGenerationBuffer(); _threadStatics.Indent(); _gcThreadStatics = new CppGenerationBuffer(); _gcThreadStatics.Indent(); } _emittedTypes = new HashSet <TypeDesc>(); foreach (var t in _cppSignatureNames.Keys) { if (t.IsByRef || t.IsPointer) { continue; } // Base class types and valuetype instantance field types may be emitted out-of-order to make them // appear before they are used. if (_emittedTypes.Contains(t)) { continue; } OutputType(sb, t, full); } _emittedTypes = null; if (full) { sb.AppendLine(); sb.Append("struct {"); // No need to indent or add a new line as _statics is already properly indented sb.Append(_statics.ToString()); sb.AppendLine(); sb.Append("} __statics;"); // TODO: Register GC statics with GC sb.AppendLine(); sb.Append("struct {"); // No need to indent or add a new line as _gcStatics is already properly indented sb.Append(_gcStatics.ToString()); sb.AppendLine(); sb.Append("} __gcStatics;"); sb.AppendLine(); // @TODO_SDM: do for real - note: the 'extra' series are just testing the init syntax for 0-length arrays, they should be removed // TODO: preinitialized 0-length arrays are not supported in CLang sb.Append("#ifdef _MSC_VER"); sb.AppendLine(); sb.Append("StaticGcDesc __gcStaticsDescs = { 1, { { sizeof(__gcStatics), 0 }, { 123, 456 }, { 789, 101112 } } };"); sb.AppendLine(); sb.Append("#else"); sb.AppendLine(); sb.Append("StaticGcDesc __gcStaticsDescs;"); sb.AppendLine(); sb.Append("#endif"); sb.AppendLine(); sb.Append("SimpleModuleHeader __module = { &__gcStatics, &__gcStaticsDescs };"); _statics = null; _gcStatics = null; _threadStatics = null; _gcThreadStatics = null; } Out.Write(sb.ToString()); sb.Clear(); }
private String GetCodeForObjectNode(ObjectNode node, NodeFactory factory) { // virtual slots var nodeData = node.GetData(factory, false); CppGenerationBuffer nodeCode = new CppGenerationBuffer(); /* 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 */ List <NodeDataSection> nodeDataSections = new List <NodeDataSection>(); byte[] actualData = new byte[nodeData.Data.Length]; Relocation[] relocs = nodeData.Relocs; int nextRelocOffset = -1; int nextRelocIndex = -1; int lastByteIndex = 0; if (relocs.Length > 0) { nextRelocOffset = relocs[0].Offset; nextRelocIndex = 0; } int i = 0; int offset = 0; CppGenerationBuffer nodeDataDecl = new CppGenerationBuffer(); if (node is ISymbolDefinitionNode) { offset = (node as ISymbolDefinitionNode).Offset; i = offset; lastByteIndex = offset; } while (i < nodeData.Data.Length) { if (i == nextRelocOffset) { Relocation reloc = relocs[nextRelocIndex]; 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)); // Update nextRelocIndex/Offset if (++nextRelocIndex < relocs.Length) { nextRelocOffset = relocs[nextRelocIndex].Offset; } nodeDataSections.Add(new NodeDataSection(NodeDataSectionType.Relocation, size)); i += size; lastByteIndex = i; } else { i++; if (i + 1 == nextRelocOffset || i + 1 == nodeData.Data.Length) { nodeDataSections.Add(new NodeDataSection(NodeDataSectionType.ByteData, (i + 1) - lastByteIndex)); } } } string pointerType = node is EETypeNode ? "MethodTable * " : "void* "; nodeCode.Append(pointerType); if (node is EETypeNode) { nodeCode.Append(GetCppMethodDeclarationName((node as EETypeNode).Type, "__getMethodTable")); } else { string mangledName = ((ISymbolNode)node).GetMangledName(factory.NameMangler); // Rename generic composition and optional fields nodes to avoid name clash with types bool shouldReplaceNamespaceQualifier = node is GenericCompositionNode || node is EETypeOptionalFieldsNode; nodeCode.Append(shouldReplaceNamespaceQualifier ? mangledName.Replace("::", "_") : mangledName); } nodeCode.Append("()"); nodeCode.AppendLine(); nodeCode.Append("{"); nodeCode.Indent(); nodeCode.AppendLine(); nodeCode.Append("static struct {"); nodeCode.AppendLine(); nodeCode.Append(GetCodeForNodeStruct(nodeDataSections, node)); nodeCode.AppendLine(); nodeCode.Append("} mt = {"); nodeCode.Append(GetCodeForNodeData(nodeDataSections, relocs, nodeData.Data, node, offset, factory)); nodeCode.Append("};"); nodeCode.AppendLine(); nodeCode.Append("return ( "); nodeCode.Append(pointerType); nodeCode.Append(")&mt;"); nodeCode.Exdent(); nodeCode.AppendLine(); nodeCode.Append("}"); nodeCode.AppendLine(); return(nodeCode.ToString()); }
public void CompileMethod(CppMethodCodeNode methodCodeNodeNeedingCode) { MethodDesc method = methodCodeNodeNeedingCode.Method; _compilation.Logger.Writer.WriteLine("Compiling " + method.ToString()); if (method.HasCustomAttribute("System.Runtime", "RuntimeImportAttribute")) { CompileExternMethod(methodCodeNodeNeedingCode, ((EcmaMethod)method).GetRuntimeImportName()); return; } if (method.IsRawPInvoke()) { CompileExternMethod(methodCodeNodeNeedingCode, method.GetPInvokeMethodMetadata().Name ?? method.Name); return; } var methodIL = _compilation.GetMethodIL(method); if (methodIL == null) { return; } try { // TODO: hacky special-case if (method.Name == "_ecvt_s") { throw new NotImplementedException(); } var ilImporter = new ILImporter(_compilation, this, method, methodIL); CompilerTypeSystemContext typeSystemContext = _compilation.TypeSystemContext; MethodDebugInformation debugInfo = _compilation.GetDebugInfo(methodIL); if (!_compilation.Options.HasOption(CppCodegenConfigProvider.NoLineNumbersString)) { IEnumerable <ILSequencePoint> sequencePoints = debugInfo.GetSequencePoints(); if (sequencePoints != null) { ilImporter.SetSequencePoints(sequencePoints); } } IEnumerable <ILLocalVariable> localVariables = debugInfo.GetLocalVariables(); if (localVariables != null) { ilImporter.SetLocalVariables(localVariables); } IEnumerable <string> parameters = GetParameterNamesForMethod(method); if (parameters != null) { ilImporter.SetParameterNames(parameters); } ilImporter.Compile(methodCodeNodeNeedingCode); } catch (Exception e) { _compilation.Logger.Writer.WriteLine(e.Message + " (" + method + ")"); var sb = new CppGenerationBuffer(); sb.AppendLine(); AppendCppMethodDeclaration(sb, method, true); sb.AppendLine(); sb.Append("{"); sb.Indent(); sb.AppendLine(); sb.Append("throw 0xC000C000;"); sb.Exdent(); sb.AppendLine(); sb.Append("}"); methodCodeNodeNeedingCode.SetCode(sb.ToString(), Array.Empty <Object>()); } }