Example #1
0
        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>());
            }
        }
Example #2
0
        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();
        }
Example #3
0
 private static void AppendFormattedByteArray(CppGenerationBuffer sb, byte[] array, int startIndex, int endIndex)
 {
     sb.Append("{");
     sb.Append("0x");
     sb.Append(BitConverter.ToString(array, startIndex, endIndex - startIndex).Replace("-", ",0x"));
     sb.Append("}");
 }
Example #4
0
        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();
        }
Example #5
0
        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();
        }
Example #6
0
        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>());
            }
        }
Example #7
0
        private void AppendSlotTypeDef(CppGenerationBuffer sb, MethodDesc method)
        {
            MethodSignature methodSignature = method.Signature;

            TypeDesc thisArgument = null;
            if (!methodSignature.IsStatic)
                thisArgument = method.OwningType;

            AppendSignatureTypeDef(sb, "__slot__" + GetCppMethodName(method), methodSignature, thisArgument);
        }
Example #8
0
        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();
        }
Example #9
0
        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();
        }
Example #10
0
        private void AppendVirtualSlots(CppGenerationBuffer sb, TypeDesc implType, TypeDesc declType)
        {
            var baseType = declType.BaseType;
            if (baseType != null)
                AppendVirtualSlots(sb, implType, baseType);

            IReadOnlyList<MethodDesc> virtualSlots = _compilation.NodeFactory.VTable(declType).Slots;
            for (int i = 0; i < virtualSlots.Count; i++)
            {
                MethodDesc declMethod = virtualSlots[i];
                MethodDesc implMethod = implType.GetClosestMetadataType().FindVirtualFunctionTargetMethodOnObjectType(declMethod);

                sb.AppendLine();
                if (implMethod.IsAbstract)
                {
                    sb.Append("NULL,");
                }
                else
                {
                    sb.Append("(void*)&");
                    sb.Append(GetCppMethodDeclarationName(implMethod.OwningType, GetCppMethodName(implMethod)));
                    sb.Append(",");
                }
            }
        }
Example #11
0
        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();
        }
Example #12
0
 private void OutputMethod(CppGenerationBuffer sb, MethodDesc m)
 {
     sb.AppendLine();
     sb.Append(GetCppMethodDeclaration(m, false));
 }
Example #13
0
        private void OutputType(CppGenerationBuffer sb, TypeDesc t, bool full)
        {
            _emittedTypes.Add(t);

            if (full)
            {
                if (!t.IsValueType)
                {
                    var baseType = t.BaseType;
                    if (baseType != null)
                    {
                        if (!_emittedTypes.Contains(baseType))
                        {
                            OutputType(sb, baseType, full);
                        }
                    }
                }

                foreach (var field in t.GetFields())
                {
                    var fieldType = GetFieldTypeOrPlaceholder(field);
                    if (fieldType.IsValueType && !fieldType.IsPrimitive && !field.IsStatic)
                    {
                        if (!_emittedTypes.Contains(fieldType))
                        {
                            OutputType(sb, fieldType, full);
                        }
                    }
                }
            }

            string mangledName = GetCppTypeName(t);

            int nesting = 0;
            int current = 0;
            // Create Namespaces. If a mangledName starts with just :: we will simply ignore it.
            sb.AppendLine();
            for (;;)
            {
                int sep = mangledName.IndexOf("::", current);
                if (sep < 0)
                    break;

                if (sep != 0)
                {
                    // Case of a name not starting with ::
                    sb.Append("namespace " + mangledName.Substring(current, sep - current) + " { ");
                    nesting++;
                }
                current = sep + 2;

            }

            if (full)
            {
                sb.Append("class " + mangledName.Substring(current));
                if (!t.IsValueType)
                {
                    if (t.BaseType != null)
                    {
                        sb.Append(" : public " + GetCppTypeName(t.BaseType));
                    }
                }
                sb.Append(" {");
                sb.AppendLine();
                sb.Append("public:");
                sb.Indent();

                // 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("static MethodTable * __getMethodTable();");
                }

                IReadOnlyList<MethodDesc> virtualSlots = _compilation.NodeFactory.VTable(t).Slots;
                
                int baseSlots = 0;
                var baseType = t.BaseType;
                while (baseType != null)
                {
                    IReadOnlyList<MethodDesc> baseVirtualSlots = _compilation.NodeFactory.VTable(baseType).Slots;
                    if (baseVirtualSlots != null)
                        baseSlots += baseVirtualSlots.Count;
                    baseType = baseType.BaseType;
                }

                for (int slot = 0; slot < virtualSlots.Count; slot++)
                {
                    MethodDesc virtualMethod = virtualSlots[slot];
                    sb.AppendLine();
                    sb.Append(GetCodeForVirtualMethod(virtualMethod, baseSlots + slot));
                }

                if (t.IsDelegate)
                {
                    sb.AppendLine();
                    sb.Append(GetCodeForDelegate(t));
                }

                OutputTypeFields(sb, t);

                if (t.HasStaticConstructor)
                {
                    _statics.AppendLine();
                    _statics.Append("bool __cctor_" + GetCppTypeName(t).Replace("::", "__") + ";");
                }

                List<MethodDesc> methodList;
                if (_methodLists.TryGetValue(t, out methodList))
                {
                    foreach (var m in methodList)
                    {
                        OutputMethod(sb, m);
                    }
                }
                sb.Exdent();
                sb.AppendLine();
                sb.Append("};");
            }
            else
            {
                sb.Append("class " + mangledName.Substring(current) + ";");
            }

            while (nesting > 0)
            {
                sb.Append("};");
                nesting--;
            }

            // Make some rooms between two type definitions
            if (full)
                sb.AppendEmptyLine();
        }
Example #14
0
        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();
        }
Example #15
0
        public void AppendCppMethodCallParamList(CppGenerationBuffer sb, MethodDesc method)
        {
            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(", ");
            }
        }
Example #16
0
        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();
        }
Example #17
0
        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>());
        }
Example #18
0
        /// <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());
            }
        }
Example #19
0
        private void OutputTypeFields(CppGenerationBuffer sb, TypeDesc t)
        {
            bool explicitLayout = false;
            ClassLayoutMetadata classLayoutMetadata = default(ClassLayoutMetadata);

            if (t.IsValueType)
            {
                MetadataType metadataType = (MetadataType)t;
                if (metadataType.IsExplicitLayout)
                {
                    explicitLayout = true;
                    classLayoutMetadata = metadataType.GetClassLayout();
                }
            }

            int instanceFieldIndex = 0;

            if (explicitLayout)
            {
                sb.AppendLine();
                sb.Append("union {");
                sb.Indent();
            }

            foreach (var field in t.GetFields())
            {
                if (field.IsStatic)
                {
                    if (field.IsLiteral)
                        continue;

                    TypeDesc fieldType = GetFieldTypeOrPlaceholder(field);
                    CppGenerationBuffer builder;
                    if (!fieldType.IsValueType)
                    {
                        builder = _gcStatics;
                    }
                    else
                    {
                        // TODO: Valuetype statics with GC references
                        builder = _statics;
                    }
                    builder.AppendLine();
                    builder.Append(GetCppSignatureTypeName(fieldType));
                    builder.Append(" ");
                    builder.Append(GetCppStaticFieldName(field) + ";");
                }
                else
                {
                    if (explicitLayout)
                    {
                        sb.AppendLine();
                        sb.Append("struct {");
                        sb.Indent();
                        int offset = classLayoutMetadata.Offsets[instanceFieldIndex].Offset;
                        if (offset > 0)
                        {
                            sb.AppendLine();
                            sb.Append("char __pad" + instanceFieldIndex + "[" + offset + "];");
                        }
                    }
                    sb.AppendLine();
                    sb.Append(GetCppSignatureTypeName(GetFieldTypeOrPlaceholder(field)) + " " + GetCppFieldName(field) + ";");
                    if (explicitLayout)
                    {
                        sb.Exdent();
                        sb.AppendLine();
                        sb.Append("};");
                    }
                    instanceFieldIndex++;
                }
            }

            if (explicitLayout)
            {
                sb.Exdent();
                sb.AppendLine();
                sb.Append("};");
            }
        }
Example #20
0
        private void OutputTypeNode(IEETypeNode typeNode, NodeFactory factory, CppGenerationBuffer forwardDefinitions, CppGenerationBuffer typeDefinitions, CppGenerationBuffer methodTable)
        {
            if (_emittedTypes == null)
            {
                _emittedTypes = new HashSet<TypeDesc>();
            }
            TypeDesc nodeType = typeNode.Type;
            if (nodeType.IsPointer || nodeType.IsByRef || _emittedTypes.Contains(nodeType))
                return;

            _emittedTypes.Add(nodeType);


            // Create Namespaces
            string mangledName = GetCppTypeName(nodeType);

            int nesting = 0;
            int current = 0;

            forwardDefinitions.AppendLine();
            for (;;)
            {
                int sep = mangledName.IndexOf("::", current);

                if (sep < 0)
                    break;

                if (sep != 0)
                {
                    // Case of a name not starting with ::
                    forwardDefinitions.Append("namespace " + mangledName.Substring(current, sep - current) + " { ");
                    typeDefinitions.Append("namespace " + mangledName.Substring(current, sep - current) + " { ");
                    typeDefinitions.Indent();
                    nesting++;
                }
                current = sep + 2;
            }

            forwardDefinitions.Append("class " + mangledName.Substring(current) + ";");

            // type definition
            typeDefinitions.Append("class " + mangledName.Substring(current));
            if (!nodeType.IsValueType)
            {
                // Don't emit inheritance if base type has not been marked for emission
                if (nodeType.BaseType != null && _emittedTypes.Contains(nodeType.BaseType))
                {
                    typeDefinitions.Append(" : public " + GetCppTypeName(nodeType.BaseType));
                }
            }
            typeDefinitions.Append(" {");
            typeDefinitions.AppendLine();
            typeDefinitions.Append("public:");
            typeDefinitions.Indent();

            // TODO: Enable once the dependencies are tracked for arrays
            // if (((DependencyNode)_compilation.NodeFactory.ConstructedTypeSymbol(t)).Marked)
            if (!nodeType.IsPointer && !nodeType.IsByRef)
            {
                typeDefinitions.AppendLine();
                typeDefinitions.Append("static MethodTable * __getMethodTable();");
            }
            if (typeNode is ConstructedEETypeNode)
            {
                OutputTypeFields(typeDefinitions, nodeType);

                IReadOnlyList<MethodDesc> virtualSlots = _compilation.NodeFactory.VTable(nodeType).Slots;

                int baseSlots = 0;
                var baseType = nodeType.BaseType;
                while (baseType != null)
                {
                    IReadOnlyList<MethodDesc> baseVirtualSlots = _compilation.NodeFactory.VTable(baseType).Slots;
                    if (baseVirtualSlots != null)
                        baseSlots += baseVirtualSlots.Count;
                    baseType = baseType.BaseType;
                }

                for (int slot = 0; slot < virtualSlots.Count; slot++)
                {
                    MethodDesc virtualMethod = virtualSlots[slot];
                    typeDefinitions.AppendLine();
                    typeDefinitions.Append(GetCodeForVirtualMethod(virtualMethod, baseSlots + slot));
                }

                if (nodeType.IsDelegate)
                {
                    typeDefinitions.AppendLine();
                    typeDefinitions.Append(GetCodeForDelegate(nodeType));
                }


                if (nodeType.HasStaticConstructor)
                {
                    _statics.AppendLine();
                    _statics.Append("bool __cctor_" + GetCppTypeName(nodeType).Replace("::", "__") + ";");
                }

                List<MethodDesc> methodList;
                if (_methodLists.TryGetValue(nodeType, out methodList))
                {
                    foreach (var m in methodList)
                    {
                        typeDefinitions.AppendLine();
                        AppendCppMethodDeclaration(typeDefinitions, m, false);
                    }
                }
            }
            typeDefinitions.AppendEmptyLine();
            typeDefinitions.Append("};");
            typeDefinitions.AppendEmptyLine();
            typeDefinitions.Exdent();

            while (nesting > 0)
            {
                forwardDefinitions.Append("};");
                typeDefinitions.Append("};");
                typeDefinitions.Exdent();
                nesting--;
            }
            typeDefinitions.AppendEmptyLine();

            // declare method table
            if (!nodeType.IsPointer && !nodeType.IsByRef)
            {
                methodTable.Append(GetCodeForObjectNode(typeNode as ObjectNode, factory));
                methodTable.AppendEmptyLine();
            }
        }
Example #21
0
        internal void AppendSignatureTypeDef(CppGenerationBuffer sb, string name, MethodSignature methodSignature, TypeDesc thisArgument)
        {
            sb.AppendLine();
            sb.Append("typedef ");
            sb.Append(GetCppSignatureTypeName(methodSignature.ReturnType));
            sb.Append("(*");
            sb.Append(name);
            sb.Append(")(");

            int argCount = methodSignature.Length;
            if (thisArgument != null)
                argCount++;
            for (int i = 0; i < argCount; i++)
            {
                if (thisArgument != null)
                {
                    if (i == 0)
                    {
                        sb.Append(GetCppSignatureTypeName(thisArgument));
                    }
                    else
                    {
                        sb.Append(GetCppSignatureTypeName(methodSignature[i - 1]));
                    }
                }
                else
                {
                    sb.Append(GetCppSignatureTypeName(methodSignature[i]));
                }
                if (i != argCount - 1)
                    sb.Append(", ");
            }
            sb.Append(");");
        }
Example #22
0
        public void AppendCppMethodDeclaration(CppGenerationBuffer sb, MethodDesc method, bool implementation, string externalMethodName = null, MethodSignature methodSignature = null)
        {
            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(";");
        }
Example #23
0
        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();
        }
Example #24
0
        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();
        }
Example #25
0
        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();
        }
Example #26
0
        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());
        }
Example #27
0
        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();
        }
Example #28
0
        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();
        }
Example #29
0
        /// <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);
        }
Example #30
0
        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();
        }