/// <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); else if (node is EETypeOptionalFieldsNode) optionalFields.Append(GetCodeForObjectNode(node as EETypeOptionalFieldsNode, factory)); } Out.Write(forwardDefinitions.ToString()); Out.Write(typeDefinitions.ToString()); Out.Write(methodTables.ToString()); Out.Write(optionalFields.ToString()); }
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 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(); }
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 String GetCodeForVirtualMethod(MethodDesc method, int slot) { var sb = new CppGenerationBuffer(); sb.Indent(); if (method.OwningType.IsInterface) { AppendSlotTypeDef(sb, method); sb.Indent(); sb.AppendLine(); sb.Append("static uint16_t"); sb.Append(" __getslot__"); sb.Append(GetCppMethodName(method)); sb.Append("(void * pThis)"); sb.AppendLine(); sb.Append("{"); sb.Indent(); sb.AppendLine(); sb.Append("return "); sb.Append(slot); sb.Append(";"); sb.AppendLine(); } else { AppendSlotTypeDef(sb, method); sb.Indent(); 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("};"); sb.Exdent(); return 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(); }
public void OutputCode(IEnumerable<DependencyNode> nodes, NodeFactory factory) { BuildMethodLists(nodes); 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); } Out.Dispose(); }
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>()); } }
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 = 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 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 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(); } }
private void OutputMainMethodStub(MethodDesc entrypoint) { var sb = new CppGenerationBuffer(); 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("::System_Private_CoreLib::Internal::Runtime::CompilerHelpers::StartupCodeHelpers::InitializeModules((intptr_t)RtRHeaderWrapper(), 2);"); 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 void OutputCode(IEnumerable<DependencyNode> nodes, NodeFactory factory) { BuildMethodLists(nodes); 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); } // Try to locate the entrypoint method MethodDesc entrypoint = null; foreach (var alias in factory.NodeAliases) if (alias.Value == MainMethodRootProvider.ManagedEntryPointMethodName) entrypoint = ((IMethodNode)alias.Key).Method; if (entrypoint != null) { OutputMainMethodStub(entrypoint); } Out.Dispose(); }
private void ImportCall(ILOpcode opcode, int token) { bool callViaSlot = false; bool delegateInvoke = false; DelegateInfo delegateInfo = null; bool mdArrayCreate = false; MethodDesc method = (MethodDesc)_methodIL.GetObject(token); if (method.IsIntrinsic) { if (ImportIntrinsicCall(method)) return; } TypeDesc constrained = null; if (opcode != ILOpcode.newobj) { if ((_pendingPrefix & Prefix.Constrained) != 0 && opcode == ILOpcode.callvirt) { _pendingPrefix &= ~Prefix.Constrained; constrained = _constrained; // TODO: throw new NotImplementedException(); } } TypeDesc owningType = method.OwningType; TypeDesc retType = null; { if (opcode == ILOpcode.newobj) retType = owningType; if (opcode == ILOpcode.newobj) { if (owningType.IsString) { // String constructors actually look like regular method calls method = method.GetStringInitializer(); opcode = ILOpcode.call; // WORKAROUND: the static method expects an extra arg // Annoyingly, it needs to be before all the others if (_stackTop >= _stack.Length) Array.Resize(ref _stack, 2 * _stackTop + 3); for (int i = _stackTop - 1; i > _stackTop - method.Signature.Length; i--) _stack[i + 1] = _stack[i]; _stackTop++; _stack[_stackTop - method.Signature.Length] = new StackValue { Kind = StackValueKind.ObjRef, Value = new Value("0") }; } else if (owningType.IsArray) { mdArrayCreate = true; } else if (owningType.IsDelegate) { delegateInfo = _compilation.GetDelegateCtor((MethodDesc)_stack[_stackTop - 1].Value.Aux); method = delegateInfo.Ctor; } } else if (owningType.IsDelegate) { if (method.Name == "Invoke") { opcode = ILOpcode.call; delegateInvoke = true; } } } if (opcode == ILOpcode.callvirt) { // TODO: Null checks if (method.IsVirtual) { // TODO: Full resolution of virtual methods if (!method.IsNewSlot) throw new NotImplementedException(); // TODO: Interface calls if (method.OwningType.IsInterface) throw new NotImplementedException(); _dependencies.Add(_nodeFactory.VirtualMethodUse(method)); callViaSlot = true; } } if (!callViaSlot && !delegateInvoke && !mdArrayCreate) AddMethodReference(method); if (opcode == ILOpcode.newobj) AddTypeReference(retType, true); var methodSignature = method.Signature; if (retType == null) retType = methodSignature.ReturnType; string temp = null; StackValueKind retKind = StackValueKind.Unknown; var needNewLine = false; if (!retType.IsVoid) { retKind = GetStackValueKind(retType); temp = NewTempName(); AppendLine(); Append(GetStackValueKindCPPTypeName(retKind, retType)); Append(" "); Append(temp); if (retType.IsValueType && opcode == ILOpcode.newobj) { Append(";"); needNewLine = true; } else { Append(" = "); if (retType.IsPointer) { Append("(intptr_t)"); } } } else { needNewLine = true; } if (opcode == ILOpcode.newobj && !mdArrayCreate) { if (!retType.IsValueType) { // We do not reset needNewLine since we still need for the next statement. if (needNewLine) AppendLine(); Append("__allocate_object("); Append(_writer.GetCppTypeName(retType)); Append("::__getMethodTable())"); AppendSemicolon(); needNewLine = true; if (delegateInfo != null && delegateInfo.ShuffleThunk != null) { AddMethodReference(delegateInfo.ShuffleThunk); _stack[_stackTop - 2].Value.Name = temp; var sb = new CppGenerationBuffer(); AppendLine(); sb.Append("(intptr_t)&"); sb.Append(_writer.GetCppTypeName(delegateInfo.ShuffleThunk.OwningType)); sb.Append("::"); sb.Append(_writer.GetCppMethodName(delegateInfo.ShuffleThunk)); Push(StackValueKind.NativeInt, new Value(sb.ToString()), null); } } } if (needNewLine) AppendLine(); if (callViaSlot || delegateInvoke) { Append("(*"); Append(_writer.GetCppTypeName(method.OwningType)); Append("::"); Append(delegateInvoke ? "__invoke__" : "__getslot__"); Append(_writer.GetCppMethodName(method)); Append("("); Append(_stack[_stackTop - (methodSignature.Length + 1)].Value.Name); Append("))"); if (delegateInvoke) { _stack[_stackTop - (methodSignature.Length + 1)].Value.Name = "((" + _writer.GetCppSignatureTypeName(GetWellKnownType(WellKnownType.MulticastDelegate)) + ")" + _stack[_stackTop - (methodSignature.Length + 1)].Value.Name + ")->m_firstParameter"; } } else if (mdArrayCreate) { Append("RhNewMDArray"); } else { Append(_writer.GetCppTypeName(method.OwningType)); Append("::"); Append(_writer.GetCppMethodName(method)); } TypeDesc thisArgument = null; Append("("); if (mdArrayCreate) { Append(_writer.GetCppTypeName(method.OwningType)); Append("::__getMethodTable(), "); Append(IntToString(((ArrayType)method.OwningType).Rank)); Append(", "); } else if (opcode == ILOpcode.newobj) { Append("("); if (retType.IsValueType) { Append(_writer.GetCppSignatureTypeName(retType.MakeByRefType())); Append(")"); Append("&" + temp); } else { Append(_writer.GetCppSignatureTypeName(retType)); Append(")"); Append(temp); } if (methodSignature.Length > 0) Append(", "); } else { if (!methodSignature.IsStatic) { thisArgument = owningType; if (thisArgument.IsValueType) thisArgument = thisArgument.MakeByRefType(); } } PassCallArguments(methodSignature, thisArgument); Append(")"); if (temp != null) Push(retKind, new Value(temp), retType); AppendSemicolon(); }
private void ImportCall(ILOpcode opcode, int token) { bool callViaSlot = false; bool delegateInvoke = false; DelegateCreationInfo delegateInfo = null; bool mdArrayCreate = false; MethodDesc method = (MethodDesc)_methodIL.GetObject(token); if (method.IsIntrinsic) { if (ImportIntrinsicCall(method)) return; } TypeDesc constrained = null; if (opcode != ILOpcode.newobj) { if ((_pendingPrefix & Prefix.Constrained) != 0 && opcode == ILOpcode.callvirt) { _pendingPrefix &= ~Prefix.Constrained; constrained = _constrained; bool forceUseRuntimeLookup; MethodDesc directMethod = constrained.GetClosestMetadataType().TryResolveConstraintMethodApprox(method.OwningType, method, out forceUseRuntimeLookup); if (directMethod == null || forceUseRuntimeLookup) throw new NotImplementedException(); method = directMethod; opcode = ILOpcode.call; } } TypeDesc owningType = method.OwningType; TypeDesc retType = null; { if (opcode == ILOpcode.newobj) retType = owningType; if (opcode == ILOpcode.newobj) { if (owningType.IsString) { // String constructors actually look like regular method calls method = method.GetStringInitializer(); opcode = ILOpcode.call; // WORKAROUND: the static method expects an extra arg // Annoyingly, it needs to be before all the others _stack.InsertAt(new ExpressionEntry(StackValueKind.ObjRef, "0"), _stack.Top - method.Signature.Length + 1); } else if (owningType.IsArray) { mdArrayCreate = true; } else if (owningType.IsDelegate) { delegateInfo = _compilation.GetDelegateCtor(owningType, ((LdTokenEntry<MethodDesc>)_stack.Peek()).LdToken); method = delegateInfo.Constructor.Method; } } else if (owningType.IsDelegate) { if (method.Name == "Invoke") { opcode = ILOpcode.call; delegateInvoke = true; } } } if (opcode == ILOpcode.callvirt) { // TODO: Null checks if (method.IsVirtual) { // TODO: Full resolution of virtual methods if (!method.IsNewSlot) throw new NotImplementedException(); // TODO: Interface calls if (method.OwningType.IsInterface) throw new NotImplementedException(); _dependencies.Add(_nodeFactory.VirtualMethodUse(method)); callViaSlot = true; } } if (!callViaSlot && !delegateInvoke && !mdArrayCreate) AddMethodReference(method); if (opcode == ILOpcode.newobj) AddTypeReference(retType, true); var methodSignature = method.Signature; if (retType == null) retType = methodSignature.ReturnType; string temp = null; StackValueKind retKind = StackValueKind.Unknown; var needNewLine = false; if (!retType.IsVoid) { retKind = GetStackValueKind(retType); temp = NewTempName(); AppendLine(); Append(GetStackValueKindCPPTypeName(retKind, retType)); Append(" "); Append(temp); if (retType.IsValueType && opcode == ILOpcode.newobj) { Append(";"); needNewLine = true; } else { Append(" = "); if (retType.IsPointer) { Append("(intptr_t)"); } } } else { needNewLine = true; } if (opcode == ILOpcode.newobj && !mdArrayCreate) { if (!retType.IsValueType) { // We do not reset needNewLine since we still need for the next statement. if (needNewLine) AppendLine(); Append("__allocate_object("); Append(_writer.GetCppTypeName(retType)); Append("::__getMethodTable())"); AppendSemicolon(); needNewLine = true; if (delegateInfo != null && delegateInfo.Thunk != null) { MethodDesc thunkMethod = delegateInfo.Thunk.Method; AddMethodReference(thunkMethod); // Update stack with new name. ((ExpressionEntry) _stack[_stack.Top - 2]).Name = temp; var sb = new CppGenerationBuffer(); AppendLine(); sb.Append("(intptr_t)&"); sb.Append(_writer.GetCppTypeName(thunkMethod.OwningType)); sb.Append("::"); sb.Append(_writer.GetCppMethodName(thunkMethod)); PushExpression(StackValueKind.NativeInt, sb.ToString()); } } } if (needNewLine) AppendLine(); if (callViaSlot || delegateInvoke) { // While waiting for C# return by ref, get this reference and insert it back // if it is a delegate invoke. ExpressionEntry v = (ExpressionEntry) _stack[_stack.Top - (methodSignature.Length + 1)]; Append("(*"); Append(_writer.GetCppTypeName(method.OwningType)); Append("::"); Append(delegateInvoke ? "__invoke__" : "__getslot__"); Append(_writer.GetCppMethodName(method)); Append("("); Append(v); Append("))"); if (delegateInvoke) { v.Name = "((" + _writer.GetCppSignatureTypeName(GetWellKnownType(WellKnownType.MulticastDelegate)) + ")" + v.Name + ")->m_firstParameter"; } } else if (mdArrayCreate) { Append("RhNewMDArray"); } else { Append(_writer.GetCppTypeName(method.OwningType)); Append("::"); Append(_writer.GetCppMethodName(method)); } TypeDesc thisArgument = null; Append("("); if (mdArrayCreate) { Append(_writer.GetCppTypeName(method.OwningType)); Append("::__getMethodTable(), "); Append(((ArrayType)method.OwningType).Rank.ToStringInvariant()); Append(", "); } else if (opcode == ILOpcode.newobj) { Append("("); if (retType.IsValueType) { Append(_writer.GetCppSignatureTypeName(retType.MakeByRefType())); Append(")"); Append("&" + temp); } else { Append(_writer.GetCppSignatureTypeName(retType)); Append(")"); Append(temp); } if (methodSignature.Length > 0) Append(", "); } else { if (!methodSignature.IsStatic) { thisArgument = owningType; if (thisArgument.IsValueType) thisArgument = thisArgument.MakeByRefType(); } } PassCallArguments(methodSignature, thisArgument); Append(")"); if (temp != null) { Debug.Assert(retKind != StackValueKind.Unknown, "Valid return type"); PushExpression(retKind, temp, retType); } AppendSemicolon(); }
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, (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()); sb.Clear(); Out.Dispose(); }
/// <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()); } }
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 = 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 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()); }
public void CompileMethod(CppMethodCodeNode methodCodeNodeNeedingCode) { MethodDesc method = methodCodeNodeNeedingCode.Method; _compilation.Log.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 { var ilImporter = new ILImporter(_compilation, this, method, methodIL); CompilerTypeSystemContext typeSystemContext = _compilation.TypeSystemContext; MethodDebugInformation debugInfo = _compilation.GetDebugInfo(methodIL); if (!_compilation.Options.NoLineNumbers) { 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.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 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 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(); }
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 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(); }
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 ISymbolNode) { offset = (node as ISymbolNode).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(); // 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(); }
private void ImportCall(ILOpcode opcode, int token) { bool callViaSlot = false; bool delegateInvoke = false; bool callViaInterfaceDispatch = false; DelegateCreationInfo delegateInfo = null; MethodDesc method = (MethodDesc)_methodIL.GetObject(token); if (method.IsIntrinsic) { if (ImportIntrinsicCall(method)) return; } TypeDesc constrained = null; if (opcode != ILOpcode.newobj) { if ((_pendingPrefix & Prefix.Constrained) != 0 && opcode == ILOpcode.callvirt) { _pendingPrefix &= ~Prefix.Constrained; constrained = _constrained; bool forceUseRuntimeLookup; MethodDesc directMethod = constrained.GetClosestDefType().TryResolveConstraintMethodApprox(method.OwningType, method, out forceUseRuntimeLookup); if (forceUseRuntimeLookup) throw new NotImplementedException(); if (directMethod != null) { method = directMethod; opcode = ILOpcode.call; } else { // Dereference "this" int thisPosition = _stack.Top - (method.Signature.Length + 1); string tempName = NewTempName(); Append(GetStackValueKindCPPTypeName(StackValueKind.ObjRef)); Append(" "); Append(tempName); Append(" = *("); Append(GetStackValueKindCPPTypeName(StackValueKind.ObjRef)); Append("*)"); Append(_stack[thisPosition]); AppendSemicolon(); _stack[thisPosition] = new ExpressionEntry(StackValueKind.ObjRef, tempName); } } } TypeDesc owningType = method.OwningType; TypeDesc retType = null; { if (opcode == ILOpcode.newobj) { retType = owningType; if (owningType.IsString) { // String constructors actually look like regular method calls method = method.GetStringInitializer(); opcode = ILOpcode.call; } else if (owningType.IsArray) { ImportNewObjArray(owningType, method); return; } else if (owningType.IsDelegate) { delegateInfo = _compilation.GetDelegateCtor(owningType, ((LdTokenEntry<MethodDesc>)_stack.Peek()).LdToken); method = delegateInfo.Constructor.Method; } } else if (owningType.IsDelegate) { if (method.Name == "Invoke") { opcode = ILOpcode.call; delegateInvoke = true; } } } if (opcode == ILOpcode.callvirt) { // TODO: Null checks if (method.IsVirtual) { // TODO: Full resolution of virtual methods if (!method.IsNewSlot) throw new NotImplementedException(); if (method.OwningType.IsInterface) callViaInterfaceDispatch = true; else callViaSlot = true; _dependencies.Add(_nodeFactory.VirtualMethodUse(method)); } } if (!callViaSlot && !delegateInvoke && !callViaInterfaceDispatch) AddMethodReference(method); if (opcode == ILOpcode.newobj) AddTypeReference(retType, true); var methodSignature = method.Signature; if (retType == null) retType = methodSignature.ReturnType; string temp = null; StackValueKind retKind = StackValueKind.Unknown; var needNewLine = false; if (callViaInterfaceDispatch) { _dependencies.Add(_nodeFactory.ReadyToRunHelper(ReadyToRunHelperId.VirtualCall, method)); ExpressionEntry v = (ExpressionEntry)_stack[_stack.Top - (methodSignature.Length + 1)]; string typeDefName = _writer.GetCppMethodName(method); _writer.AppendSignatureTypeDef(_builder, typeDefName, method.Signature, method.OwningType); string functionPtr = NewTempName(); AppendEmptyLine(); Append("void*"); Append(functionPtr); Append(" = (void*) (("); Append(typeDefName); // Call method to find implementation address Append(") System_Private_CoreLib::System::Runtime::DispatchResolve::FindInterfaceMethodImplementationTarget("); // Get EEType of current object (interface implementation) Append("::System_Private_CoreLib::System::Object::get_EEType((::System_Private_CoreLib::System::Object*)"); Append(v.Name); Append(")"); Append(", "); // Get EEType of interface Append("((::System_Private_CoreLib::Internal::Runtime::EEType *)("); Append(_writer.GetCppTypeName(method.OwningType)); Append("::__getMethodTable()))"); Append(", "); // Get slot of implementation Append("(uint16_t)"); Append("("); Append(_writer.GetCppTypeName(method.OwningType)); Append("::"); Append("__getslot__"); Append(_writer.GetCppMethodName(method)); Append("("); Append(v.Name); Append("))"); Append("));"); PushExpression(StackValueKind.ByRef, functionPtr); } if (!retType.IsVoid) { retKind = GetStackValueKind(retType); temp = NewTempName(); AppendLine(); Append(GetStackValueKindCPPTypeName(retKind, retType)); Append(" "); Append(temp); if (retType.IsValueType && opcode == ILOpcode.newobj) { Append(";"); needNewLine = true; } else { Append(" = "); if (retType.IsPointer) { Append("(intptr_t)"); } } } else { needNewLine = true; } AddTypeReference(method.OwningType, true); if (opcode == ILOpcode.newobj) { if (!retType.IsValueType) { // We do not reset needNewLine since we still need for the next statement. if (needNewLine) AppendLine(); Append("__allocate_object("); Append(_writer.GetCppTypeName(retType)); Append("::__getMethodTable())"); AppendSemicolon(); needNewLine = true; if (delegateInfo != null && delegateInfo.Thunk != null) { MethodDesc thunkMethod = delegateInfo.Thunk.Method; AddMethodReference(thunkMethod); // Update stack with new name. ((ExpressionEntry)_stack[_stack.Top - 2]).Name = temp; var sb = new CppGenerationBuffer(); AppendLine(); sb.Append("(intptr_t)&"); sb.Append(_writer.GetCppTypeName(thunkMethod.OwningType)); sb.Append("::"); sb.Append(_writer.GetCppMethodName(thunkMethod)); PushExpression(StackValueKind.NativeInt, sb.ToString()); } } } if (needNewLine) AppendLine(); if (callViaSlot || delegateInvoke) { ExpressionEntry v = (ExpressionEntry)_stack[_stack.Top - (methodSignature.Length + 1)]; Append("(*"); Append(_writer.GetCppTypeName(method.OwningType)); Append("::"); Append(delegateInvoke ? "__invoke__" : "__getslot__"); Append(_writer.GetCppMethodName(method)); Append("("); Append(v); Append("))"); if (delegateInvoke) { v.Name = "((" + _writer.GetCppSignatureTypeName(GetWellKnownType(WellKnownType.MulticastDelegate)) + ")" + v.Name + ")->m_firstParameter"; } } else if (callViaInterfaceDispatch) { Append("(("); Append(_writer.GetCppMethodName(method)); Append(")"); ExpressionEntry v = (ExpressionEntry)_stack.Pop(); Append(v); Append(")"); } else { Append(_writer.GetCppTypeName(method.OwningType)); Append("::"); Append(_writer.GetCppMethodName(method)); } TypeDesc thisArgument = null; Append("("); if (opcode == ILOpcode.newobj) { Append("("); if (retType.IsValueType) { Append(_writer.GetCppSignatureTypeName(retType.MakeByRefType())); Append(")"); Append("&" + temp); } else { Append(_writer.GetCppSignatureTypeName(retType)); Append(")"); Append(temp); } if (methodSignature.Length > 0) Append(", "); } else { if (!methodSignature.IsStatic) { thisArgument = owningType; if (thisArgument.IsValueType) thisArgument = thisArgument.MakeByRefType(); } } PassCallArguments(methodSignature, thisArgument); Append(")"); if (temp != null) { Debug.Assert(retKind != StackValueKind.Unknown, "Valid return type"); PushExpression(retKind, temp, retType); } AppendSemicolon(); }
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))); } else if (reloc.Target is EETypeNode && node is EETypeNode) { relocCode.Append(GetCppMethodDeclarationName((reloc.Target as EETypeNode).Type, "__getMethodTable")); 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(); 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 ImportLoadString(int token) { string str = (string)_methodIL.GetObject(token); PushTemp(StackValueKind.ObjRef, GetWellKnownType(WellKnownType.String)); var escaped = new CppGenerationBuffer(); foreach (char c in str) { switch (c) { case '\\': escaped.Append("\\\\"); break; case '\r': escaped.Append("\\r"); break; case '\n': escaped.Append("\\n"); break; case '\t': escaped.Append("\\t"); break; default: // TODO: handle all characters < 32 escaped.Append(c); break; } } Append("__load_string_literal(\""); Append(escaped.ToString()); Append("\")"); AppendSemicolon(); }
/// <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()); 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 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(); }