<commit_before>// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Text;
using System.Collections.Generic;
using System.Diagnostics;

using Internal.TypeSystem;
using Internal.IL.Stubs;

using ILCompiler;
using ILCompiler.CppCodeGen;

namespace Internal.IL
{
    public struct ILSequencePoint
    {
        public int Offset;
        public string Document;
        public int LineNumber;
        // TODO: The remaining info
    }

    public struct LocalVariable
    {
        public int Slot;
        public string Name;
        public bool CompilerGenerated;
    }

    partial class ILImporter
    {
        Compilation _compilation;
        CppWriter _writer;

        TypeSystemContext _typeSystemContext;

        MethodDesc _method;
        MethodSignature _methodSignature;

        TypeDesc _thisType;

        MethodIL _methodIL;
        byte[] _ilBytes;
        LocalVariableDefinition[] _locals;

        struct SequencePoint
        {
            public string Document;
            public int LineNumber;
        }
        SequencePoint[] _sequencePoints;
        Dictionary<int, LocalVariable> _localSlotToInfoMap;
        Dictionary<int, string> _parameterIndexToNameMap;

        class ExceptionRegion
        {
            public ILExceptionRegion ILRegion;
            public int ReturnLabels;
        };
        ExceptionRegion[] _exceptionRegions;

        class SpillSlot
        {
            public StackValueKind Kind;
            public TypeDesc Type;
            public String Name;
        };
        List<SpillSlot> _spillSlots;

        // TODO: Unify with verifier?
        [Flags]
        enum Prefix
        {
            ReadOnly = 0x01,
            Unaligned = 0x02,
            Volatile = 0x04,
            Tail = 0x08,
            Constrained = 0x10,
            No = 0x20,
        }
        Prefix _pendingPrefix;
        TypeDesc _constrained;

        StringBuilder _builder = new StringBuilder();

        class BasicBlock
        {
            // Common fields
            public BasicBlock Next;

            public int StartOffset;
            public int EndOffset;

            public StackValue[] EntryStack;

            public bool TryStart;
            public bool FilterStart;
            public bool HandlerStart;

            // Custom fields
            public string Code;
        };

        public ILImporter(Compilation compilation, CppWriter writer, MethodDesc method, MethodIL methodIL)
        {
            _compilation = compilation;
            _writer = writer;

            _method = method;
            _methodSignature = method.Signature;

            _typeSystemContext = method.Context;

            if (!_methodSignature.IsStatic)
                _thisType = method.OwningType;

            _methodIL = methodIL;

            _ilBytes = _methodIL.GetILBytes();
            _locals = _methodIL.GetLocals();

            var ilExceptionRegions = _methodIL.GetExceptionRegions();
            _exceptionRegions = new ExceptionRegion[ilExceptionRegions.Length];
            for (int i = 0; i < ilExceptionRegions.Length; i++)
            {
                _exceptionRegions[i] = new ExceptionRegion() { ILRegion = ilExceptionRegions[i] };
            }
        }

        public void SetSequencePoints(IEnumerable<ILSequencePoint> ilSequencePoints)
        {
            try
            {
                SequencePoint[] sequencePoints = new SequencePoint[_ilBytes.Length];
                foreach (var point in ilSequencePoints)
                {
                    sequencePoints[point.Offset] = new SequencePoint() { Document = point.Document, LineNumber = point.LineNumber };
                }
                _sequencePoints = sequencePoints;
            }
            catch
            {
            }
        }

        public void SetLocalVariables(IEnumerable<LocalVariable> localVariables)
        {
            try
            {
                HashSet<string> names = new HashSet<string>();
                var localSlotToInfoMap = new Dictionary<int, LocalVariable>();
                foreach (var v in localVariables)
                {
                    LocalVariable modifiedLocal = v;
                    modifiedLocal.Name = _compilation.NameMangler.SanitizeName(modifiedLocal.Name);
                    if (!names.Add(v.Name))
                    {
                        modifiedLocal.Name = string.Format("{0}_local{1}", v.Name, v.Slot);
                        names.Add(modifiedLocal.Name);
                    }

                    localSlotToInfoMap[v.Slot] = modifiedLocal;
                }
                _localSlotToInfoMap = localSlotToInfoMap;
            }
            catch
            {
                // oops, couldn't get local variables
            }
        }

        public void SetParameterNames(IEnumerable<string> parameters)
        {
            var parameterIndexToNameMap = new Dictionary<int, string>();
            int index = 0;
            foreach (var p in parameters)
            {
                parameterIndexToNameMap[index] = p;
                ++index;
            }

            _parameterIndexToNameMap = parameterIndexToNameMap;
        }

        struct Value
        {
            public Value(String name)
            {
                Name = name;
                Aux = null;
            }

            public String Name;
            public Object Aux;
        };

        struct StackValue
        {
            public StackValueKind Kind;
            public TypeDesc Type;
            public Value Value;
        }

        StackValueKind GetStackValueKind(TypeDesc type)
        {
            switch (type.Category)
            {
                case TypeFlags.Boolean:
                case TypeFlags.Char:
                case TypeFlags.SByte:
                case TypeFlags.Byte:
                case TypeFlags.Int16:
                case TypeFlags.UInt16:
                case TypeFlags.Int32:
                case TypeFlags.UInt32:
                    return StackValueKind.Int32;
                case TypeFlags.Int64:
                case TypeFlags.UInt64:
                    return StackValueKind.Int64;
                case TypeFlags.Single:
                case TypeFlags.Double:
                    return StackValueKind.Float;
                case TypeFlags.IntPtr:
                case TypeFlags.UIntPtr:
                    return StackValueKind.NativeInt;
                case TypeFlags.ValueType:
                case TypeFlags.Nullable:
                    return StackValueKind.ValueType;
                case TypeFlags.Enum:
                    return GetStackValueKind(type.UnderlyingType);
                case TypeFlags.Class:
                case TypeFlags.Interface:
                case TypeFlags.Array:
                    return StackValueKind.ObjRef;
                case TypeFlags.ByRef:
                    return StackValueKind.ByRef;
                case TypeFlags.Pointer:
                    return StackValueKind.NativeInt;
                default:
                    return StackValueKind.Unknown;
            }
        }

        void Push(StackValue value)
        {
            if (_stackTop >= _stack.Length)
                Array.Resize(ref _stack, 2 * _stackTop + 3);
            _stack[_stackTop++] = value;
        }

        void Push(StackValueKind kind, Value value, TypeDesc type = null)
        {
            Push(new StackValue() { Kind = kind, Type = type, Value = value });
        }

        StackValue Pop()
        {
            return _stack[--_stackTop];
        }

        public static bool Msvc = true;

        string GetStackValueKindCPPTypeName(StackValueKind kind, TypeDesc type = null)
        {
            switch (kind)
            {
                case StackValueKind.Int32: return "int32_t";
                case StackValueKind.Int64: return "int64_t";
                case StackValueKind.NativeInt: return "intptr_t";
                case StackValueKind.ObjRef: return "void*";
                case StackValueKind.Float: return "double";
                case StackValueKind.ByRef:
                case StackValueKind.ValueType: return _writer.GetCppSignatureTypeName(type);
                default: throw new NotSupportedException();
            }
        }

        int _currentTemp = 1;
        string NewTempName()
        {
            return "_" + (_currentTemp++).ToString();
        }

        void PushTemp(StackValueKind kind, TypeDesc type = null)
        {
            string temp = NewTempName();

            Push(kind, new Value(temp), type);

            _builder.Append(GetStackValueKindCPPTypeName(kind, type));
            _builder.Append(" ");
            _builder.Append(temp);
            _builder.Append("=");
        }

        void AppendCastIfNecessary(TypeDesc destType, StackValueKind srcType)
        {
            if (destType.IsValueType)
                return;
            Append("(");
            Append(_writer.GetCppSignatureTypeName(destType));
            Append(")");
        }

        void AppendCastIfNecessary(StackValueKind dstType, TypeDesc srcType)
        {
            if (dstType == StackValueKind.ByRef)
            {
                Append("("); 
                Append(_writer.GetCppSignatureTypeName(srcType));
                Append(")");
            }
            else
            if (srcType.IsPointer)
            {
                Append("(intptr_t)");
            }
        }

        Value NewSpillSlot(StackValueKind kind, TypeDesc type)
        {
            if (_spillSlots == null)
                _spillSlots = new List<SpillSlot>();

            SpillSlot spillSlot = new SpillSlot();
            spillSlot.Kind = kind;
            spillSlot.Type = type;
            spillSlot.Name = "_s" + _spillSlots.Count.ToString();

            _spillSlots.Add(spillSlot);

            return new Value() { Name = spillSlot.Name };
        }

        void Append(string s)
        {
            _builder.Append(s);
        }

        void Finish()
        {
            // _builder.AppendLine(";");
            _builder.Append("; ");
        }

        string GetVarName(int index, bool argument)
        {
            if (_localSlotToInfoMap != null && !argument && _localSlotToInfoMap.ContainsKey(index) && !_localSlotToInfoMap[index].CompilerGenerated)
            {
                return _localSlotToInfoMap[index].Name;
            }

            if (_parameterIndexToNameMap != null && argument && _parameterIndexToNameMap.ContainsKey(index))
            {
                return _writer.SanitizeCppVarName(_parameterIndexToNameMap[index]);
            }

            return (argument ? "_a" : "_l") + index.ToString();
        }

        TypeDesc GetVarType(int index, bool argument)
        {
            if (argument)
            {
                if (_thisType != null)
                    index--;
                if (index == -1)
                {
                    if (_thisType.IsValueType)
                        return _thisType.MakeByRefType();
                    return _thisType;
                }
                else return _methodSignature[index];
            }
            else
            {
               return _locals[index].Type;
            }
        }

        TypeDesc GetWellKnownType(WellKnownType wellKnownType)
        {
            return _typeSystemContext.GetWellKnownType(wellKnownType);
        }

        TypeDesc ResolveTypeToken(int token)
        {
            return (TypeDesc)_methodIL.GetObject(token);
        }

        void MarkInstructionBoundary()
        {
        }

        void StartImportingInstruction()
        {
            if (_sequencePoints == null)
                return;

            var sequencePoint = _sequencePoints[_currentOffset];
            if (sequencePoint.Document == null)
                return;

            _builder.AppendLine();

            Append("#line ");
            Append(sequencePoint.LineNumber.ToString());
            Append(" \"");
            Append(sequencePoint.Document.Replace("\\", "\\\\"));
            Append("\"");

            _builder.AppendLine();
        }

        void EndImportingInstruction()
        {
            if (_sequencePoints == null)
                _builder.AppendLine();
        }

        public string Compile()
        {
            FindBasicBlocks();

            ImportBasicBlocks();

            if (_sequencePoints != null && _sequencePoints[0].Document != null)
            {
                var sequencePoint = _sequencePoints[0];

                Append("#line ");
                Append(sequencePoint.LineNumber.ToString());
                Append(" \"");
                Append(sequencePoint.Document.Replace("\\", "\\\\"));
                Append("\"");

                _builder.AppendLine();
            }

            Append(_writer.GetCppMethodDeclaration(_method, true));

            _builder.Append("{");

            bool initLocals = _methodIL.GetInitLocals();
            for (int i = 0; i < _locals.Length; i++)
            {
                Append(_writer.GetCppSignatureTypeName(_locals[i].Type));
                Append(" ");
                Append(GetVarName(i, false));
                if (initLocals)
                {
                    TypeDesc localType = _locals[i].Type;
                    if (localType.IsValueType && !localType.IsPrimitive && !localType.IsEnum)
                    {
                        Finish();
                        Append("memset(&");
                        Append(GetVarName(i, false));
                        Append(",0,sizeof(");
                        Append(_writer.GetCppSignatureTypeName(localType));
                        Append("))");
                    }
                    else
                    {
                        Append("=0");
                    }
                }
                Finish();
            }

            if (_spillSlots != null)
            {
                for (int i = 0; i < _spillSlots.Count; i++)
                {
                    SpillSlot spillSlot = _spillSlots[i];
                    Append(GetStackValueKindCPPTypeName(spillSlot.Kind, spillSlot.Type));
                    Append(" ");
                    Append(spillSlot.Name);
                    Finish();
                }
            }

            for (int i = 0; i < _exceptionRegions.Length; i++)
            {
                var r = _exceptionRegions[i];
                if (r.ReturnLabels != 0)
                {
                    _builder.Append("int __finallyReturn");
                    _builder.Append(i.ToString());
                    _builder.Append("=0;");
                }
            }

            for (int i = 0; i < _basicBlocks.Length; i++)
            {
                BasicBlock basicBlock = _basicBlocks[i];
                if (basicBlock != null)
                {
                    _builder.Append("_bb");
                    _builder.Append(i.ToString());
                    _builder.AppendLine(": {");
                    _builder.Append(basicBlock.Code);
                    // _builder.AppendLine("}");
                    _builder.Append("} ");
                }
            }

            for (int i = 0; i < _exceptionRegions.Length; i++)
            {
                var r = _exceptionRegions[i];
                if (r.ReturnLabels != 0)
                {
                    _builder.AppendLine("__endFinally" + i.ToString() + ": switch(__finallyReturn" + i.ToString() + ") {");
                    for (int j = 1; j <= r.ReturnLabels; j++)
                        _builder.AppendLine("case " + j.ToString() + ": goto __returnFromFinally" + i.ToString() + "_" + j.ToString() + ";");
                    _builder.AppendLine("default: " + (Msvc ? "__assume(0)" : "__builtin_unreachable()") + "; }");
                }
            }

            _builder.AppendLine("}");

            return _builder.ToString();
        }

        void StartImportingBasicBlock(BasicBlock basicBlock)
        {
        }

        void EndImportingBasicBlock(BasicBlock basicBlock)
        {
            basicBlock.Code = _builder.ToString();
            _builder.Clear();
        }

        void ImportNop()
        {
        }

        void ImportBreak()
        {
            throw new NotImplementedException("Opcode: break");
        }

        void ImportLoadVar(int index, bool argument)
        {
            string name = GetVarName(index, argument);
            string temp = NewTempName();

            TypeDesc type = GetVarType(index, argument);
            StackValueKind kind = GetStackValueKind(type);

            PushTemp(kind, type);
            AppendCastIfNecessary(kind, type);
            Append(name);
            Finish();
        }

        void ImportStoreVar(int index, bool argument)
        {
            var value = Pop();

            string name = GetVarName(index, argument);

            Append(name);
            Append("=");
            TypeDesc type = GetVarType(index, argument);
            AppendCastIfNecessary(type, value.Kind);
            Append(value.Value.Name);
            Finish();
        }

        void ImportAddressOfVar(int index, bool argument)
        {
            string name = GetVarName(index, argument);
            string temp = NewTempName();

            TypeDesc type = GetVarType(index, argument);
            type = type.MakeByRefType();

            PushTemp(StackValueKind.ByRef, type);
            AppendCastIfNecessary(StackValueKind.ByRef, type);
            Append("&");
            Append(name);
            Finish();
        }

        void ImportDup()
        {
            Push(_stack[_stackTop - 1]);
        }

        void ImportPop()
        {
            Pop();
        }

        void ImportJmp(int token)
        {
            throw new NotImplementedException("Opcode: jmp");
        }

        void ImportCasting(ILOpcode opcode, int token)
        {
            TypeDesc type = (TypeDesc)_methodIL.GetObject(token);

            if (type.IsInterface || type.IsArray)
                throw new NotImplementedException();

            var value = Pop();
            PushTemp(StackValueKind.ObjRef, type);

            Append(opcode == ILOpcode.isinst ? "__isinst_class" : "__castclass_class");
            Append("(");
            Append(value.Value.Name);
            Append(", ");
            Append(_writer.GetCppTypeName(type));
            Append("::__getMethodTable())");
            Finish();
        }

        void ImportIntrinsicCall(IntrinsicMethodKind intrinsicClassification)
        {
            switch (intrinsicClassification)
            {
                case IntrinsicMethodKind.RuntimeHelpersInitializeArray:
                    {
                        var fieldSlot = Pop();
                        var arraySlot = Pop();

                        var fieldDesc = (TypeSystem.Ecma.EcmaField)fieldSlot.Value.Aux;
                        int addr = fieldDesc.MetadataReader.GetFieldDefinition(fieldDesc.Handle).GetRelativeVirtualAddress();
                        var memBlock = fieldDesc.Module.PEReader.GetSectionData(addr).GetContent();

                        var fieldType = (TypeSystem.Ecma.EcmaType)fieldDesc.FieldType;
                        int size = fieldType.MetadataReader.GetTypeDefinition(fieldType.Handle).GetLayout().Size;
                        if (size == 0)
                            throw new NotImplementedException();

                        // TODO: Need to do more for arches with different endianness?
                        var preinitDataHolder = NewTempName();
                        Append("static const char ");
                        Append(preinitDataHolder);
                        Append("[] = { ");

                        for (int i = 0; i < size; i++)
                        {
                            if (i != 0)
                                Append(", ");
                            Append(String.Format("0x{0:X}", memBlock[i]));
                        }
                        Append(" }");
                        Finish();

                        Append("memcpy((char*)");
                        Append(arraySlot.Value.Name);
                        Append(" + ARRAY_BASE, ");
                        Append(preinitDataHolder);
                        Append(", ");
                        Append(size.ToString());
                        Append(")");

                        Finish();
                        break;
                    }
                default: throw new NotImplementedException();
            }
        }

        void ImportCall(ILOpcode opcode, int token)
        {
            bool callViaSlot = false;
            bool delegateInvoke = false;
            DelegateInfo delegateInfo = null;
            bool mdArrayCreate = false;

            MethodDesc method = (MethodDesc)_methodIL.GetObject(token);

            var intrinsicClassification = IntrinsicMethods.GetIntrinsicMethodClassification(method);
            if (intrinsicClassification != IntrinsicMethodKind.None)
            {
                ImportIntrinsicCall(intrinsicClassification);
                return;
            }

            if (opcode == ILOpcode.calli)
                throw new NotImplementedException();

            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 retType = null;

            {
                TypeDesc owningType = method.OwningType;
                if (opcode == ILOpcode.newobj)
                    retType = owningType;

                if (opcode == ILOpcode.newobj)
                {
                    if (owningType.IsString)
                    {
                        // String constructors actually look like regular method calls
                        method = IntrinsicMethods.GetStringInitializer(method);
                        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();

                    _compilation.AddVirtualSlot(method);

                    callViaSlot = true;
                }
            }

            if (!callViaSlot && !delegateInvoke && !mdArrayCreate)
                _compilation.AddMethod(method);

            if (opcode == ILOpcode.newobj)
                _compilation.MarkAsConstructed(retType);

            var methodSignature = method.Signature;

            if (retType == null)
                retType = methodSignature.ReturnType;

            string temp = null;
            StackValueKind retKind = StackValueKind.Unknown;

            if (!retType.IsVoid)
            {
                retKind = GetStackValueKind(retType);
                temp = NewTempName();

                Append(GetStackValueKindCPPTypeName(retKind, retType));
                Append(" ");
                Append(temp);
                if (retType.IsValueType && opcode == ILOpcode.newobj)
                {
                    Append(";");
                }
                else
                {
                    Append("=");

                    if (retType.IsPointer)
                    {
                        Append("(intptr_t)");
                    }
                }
            }

            if (opcode == ILOpcode.newobj && !mdArrayCreate)
            {
                if (!retType.IsValueType)
                {
                    _compilation.AddType(retType);

                    Append("__allocate_object(");
                    Append(_writer.GetCppTypeName(retType));
                    Append("::__getMethodTable())");
                    Finish();

                    if (delegateInfo != null && delegateInfo.ShuffleThunk != null)
                    {
                        _stack[_stackTop - 2].Value.Name = temp;

                        StringBuilder sb = new StringBuilder();
                        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 (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)
            {
                _compilation.AddType(method.OwningType);
                Append("RhNewMDArray");
            }
            else
            {
                Append(_writer.GetCppTypeName(method.OwningType));
                Append("::");
                Append(_writer.GetCppMethodName(method));
            }


            Append("(");
            int count = methodSignature.Length;
            bool hasThis = !methodSignature.IsStatic;
            if (hasThis)
                count++;
            if (mdArrayCreate)
            {
                Append(_writer.GetCppTypeName(method.OwningType));
                Append("::__getMethodTable(), ");
                Append(((ArrayType)method.OwningType).Rank.ToString());
                Append(", ");
                count--;
            }
            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);
                }
                count--;
                if (count > 0)
                    Append(", ");
            }
            for (int i = 0; i < count; i++)
            {
                var op = _stack[_stackTop - count + i];
                int argIndex = methodSignature.Length - (count - i);
                TypeDesc argType;
                if (argIndex == -1)
                {
                    argType = method.OwningType;
                    if (argType.IsValueType)
                        argType = argType.MakeByRefType();
                }
                else
                {
                    argType = methodSignature[argIndex];
                }
                AppendCastIfNecessary(argType, op.Kind);
                Append(op.Value.Name);
                if (i != count - 1)
                    Append(", ");
            }
            _stackTop -= count;
            Append(")");

            if (temp != null)
                Push(retKind, new Value(temp), retType);
            Finish();
        }

        void ImportLdFtn(int token, ILOpcode opCode)
        {
            MethodDesc method = (MethodDesc)_methodIL.GetObject(token);

            if (opCode == ILOpcode.ldvirtftn)
            {
                if (method.IsVirtual)
                    throw new NotImplementedException();
            }

            _compilation.AddMethod(method);

            PushTemp(StackValueKind.NativeInt);
            Append("(intptr_t)&");
            Append(_writer.GetCppTypeName(method.OwningType));
            Append("::");
            Append(_writer.GetCppMethodName(method));

            _stack[_stackTop-1].Value.Aux = method;

            Finish();
        }

        void ImportLoadInt(long value, StackValueKind kind)
        {
            string val;
            if (kind == StackValueKind.Int64)
            {
                if (value == Int64.MinValue)
                    val = "(int64_t)(0x8000000000000000" + (Msvc ? "i64" : "LL") + ")";
                else
                    val = value.ToString() + (Msvc ? "i64" : "LL");
            }
            else
            {<commit_msg>Fix CPP CodeGen for Linux to emit non-msvc code<commit_after>// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Text;
using System.Collections.Generic;
using System.Diagnostics;

using Internal.TypeSystem;
using Internal.IL.Stubs;

using ILCompiler;
using ILCompiler.CppCodeGen;

namespace Internal.IL
{
    public struct ILSequencePoint
    {
        public int Offset;
        public string Document;
        public int LineNumber;
        // TODO: The remaining info
    }

    public struct LocalVariable
    {
        public int Slot;
        public string Name;
        public bool CompilerGenerated;
    }

    partial class ILImporter
    {
        Compilation _compilation;
        CppWriter _writer;

        TypeSystemContext _typeSystemContext;

        MethodDesc _method;
        MethodSignature _methodSignature;

        TypeDesc _thisType;

        MethodIL _methodIL;
        byte[] _ilBytes;
        LocalVariableDefinition[] _locals;

        struct SequencePoint
        {
            public string Document;
            public int LineNumber;
        }
        SequencePoint[] _sequencePoints;
        Dictionary<int, LocalVariable> _localSlotToInfoMap;
        Dictionary<int, string> _parameterIndexToNameMap;

        class ExceptionRegion
        {
            public ILExceptionRegion ILRegion;
            public int ReturnLabels;
        };
        ExceptionRegion[] _exceptionRegions;

        class SpillSlot
        {
            public StackValueKind Kind;
            public TypeDesc Type;
            public String Name;
        };
        List<SpillSlot> _spillSlots;

        // TODO: Unify with verifier?
        [Flags]
        enum Prefix
        {
            ReadOnly = 0x01,
            Unaligned = 0x02,
            Volatile = 0x04,
            Tail = 0x08,
            Constrained = 0x10,
            No = 0x20,
        }
        Prefix _pendingPrefix;
        TypeDesc _constrained;

        StringBuilder _builder = new StringBuilder();

        class BasicBlock
        {
            // Common fields
            public BasicBlock Next;

            public int StartOffset;
            public int EndOffset;

            public StackValue[] EntryStack;

            public bool TryStart;
            public bool FilterStart;
            public bool HandlerStart;

            // Custom fields
            public string Code;
        };

        public ILImporter(Compilation compilation, CppWriter writer, MethodDesc method, MethodIL methodIL)
        {
            _compilation = compilation;
            _writer = writer;

            _method = method;
            _methodSignature = method.Signature;

            _typeSystemContext = method.Context;

            _msvc = (_typeSystemContext.Target.OperatingSystem == TargetOS.Windows);

            if (!_methodSignature.IsStatic)
                _thisType = method.OwningType;

            _methodIL = methodIL;

            _ilBytes = _methodIL.GetILBytes();
            _locals = _methodIL.GetLocals();

            var ilExceptionRegions = _methodIL.GetExceptionRegions();
            _exceptionRegions = new ExceptionRegion[ilExceptionRegions.Length];
            for (int i = 0; i < ilExceptionRegions.Length; i++)
            {
                _exceptionRegions[i] = new ExceptionRegion() { ILRegion = ilExceptionRegions[i] };
            }
        }

        public void SetSequencePoints(IEnumerable<ILSequencePoint> ilSequencePoints)
        {
            try
            {
                SequencePoint[] sequencePoints = new SequencePoint[_ilBytes.Length];
                foreach (var point in ilSequencePoints)
                {
                    sequencePoints[point.Offset] = new SequencePoint() { Document = point.Document, LineNumber = point.LineNumber };
                }
                _sequencePoints = sequencePoints;
            }
            catch
            {
            }
        }

        public void SetLocalVariables(IEnumerable<LocalVariable> localVariables)
        {
            try
            {
                HashSet<string> names = new HashSet<string>();
                var localSlotToInfoMap = new Dictionary<int, LocalVariable>();
                foreach (var v in localVariables)
                {
                    LocalVariable modifiedLocal = v;
                    modifiedLocal.Name = _compilation.NameMangler.SanitizeName(modifiedLocal.Name);
                    if (!names.Add(v.Name))
                    {
                        modifiedLocal.Name = string.Format("{0}_local{1}", v.Name, v.Slot);
                        names.Add(modifiedLocal.Name);
                    }

                    localSlotToInfoMap[v.Slot] = modifiedLocal;
                }
                _localSlotToInfoMap = localSlotToInfoMap;
            }
            catch
            {
                // oops, couldn't get local variables
            }
        }

        public void SetParameterNames(IEnumerable<string> parameters)
        {
            var parameterIndexToNameMap = new Dictionary<int, string>();
            int index = 0;
            foreach (var p in parameters)
            {
                parameterIndexToNameMap[index] = p;
                ++index;
            }

            _parameterIndexToNameMap = parameterIndexToNameMap;
        }

        struct Value
        {
            public Value(String name)
            {
                Name = name;
                Aux = null;
            }

            public String Name;
            public Object Aux;
        };

        struct StackValue
        {
            public StackValueKind Kind;
            public TypeDesc Type;
            public Value Value;
        }

        StackValueKind GetStackValueKind(TypeDesc type)
        {
            switch (type.Category)
            {
                case TypeFlags.Boolean:
                case TypeFlags.Char:
                case TypeFlags.SByte:
                case TypeFlags.Byte:
                case TypeFlags.Int16:
                case TypeFlags.UInt16:
                case TypeFlags.Int32:
                case TypeFlags.UInt32:
                    return StackValueKind.Int32;
                case TypeFlags.Int64:
                case TypeFlags.UInt64:
                    return StackValueKind.Int64;
                case TypeFlags.Single:
                case TypeFlags.Double:
                    return StackValueKind.Float;
                case TypeFlags.IntPtr:
                case TypeFlags.UIntPtr:
                    return StackValueKind.NativeInt;
                case TypeFlags.ValueType:
                case TypeFlags.Nullable:
                    return StackValueKind.ValueType;
                case TypeFlags.Enum:
                    return GetStackValueKind(type.UnderlyingType);
                case TypeFlags.Class:
                case TypeFlags.Interface:
                case TypeFlags.Array:
                    return StackValueKind.ObjRef;
                case TypeFlags.ByRef:
                    return StackValueKind.ByRef;
                case TypeFlags.Pointer:
                    return StackValueKind.NativeInt;
                default:
                    return StackValueKind.Unknown;
            }
        }

        void Push(StackValue value)
        {
            if (_stackTop >= _stack.Length)
                Array.Resize(ref _stack, 2 * _stackTop + 3);
            _stack[_stackTop++] = value;
        }

        void Push(StackValueKind kind, Value value, TypeDesc type = null)
        {
            Push(new StackValue() { Kind = kind, Type = type, Value = value });
        }

        StackValue Pop()
        {
            return _stack[--_stackTop];
        }

        private bool _msvc;

        string GetStackValueKindCPPTypeName(StackValueKind kind, TypeDesc type = null)
        {
            switch (kind)
            {
                case StackValueKind.Int32: return "int32_t";
                case StackValueKind.Int64: return "int64_t";
                case StackValueKind.NativeInt: return "intptr_t";
                case StackValueKind.ObjRef: return "void*";
                case StackValueKind.Float: return "double";
                case StackValueKind.ByRef:
                case StackValueKind.ValueType: return _writer.GetCppSignatureTypeName(type);
                default: throw new NotSupportedException();
            }
        }

        int _currentTemp = 1;
        string NewTempName()
        {
            return "_" + (_currentTemp++).ToString();
        }

        void PushTemp(StackValueKind kind, TypeDesc type = null)
        {
            string temp = NewTempName();

            Push(kind, new Value(temp), type);

            _builder.Append(GetStackValueKindCPPTypeName(kind, type));
            _builder.Append(" ");
            _builder.Append(temp);
            _builder.Append("=");
        }

        void AppendCastIfNecessary(TypeDesc destType, StackValueKind srcType)
        {
            if (destType.IsValueType)
                return;
            Append("(");
            Append(_writer.GetCppSignatureTypeName(destType));
            Append(")");
        }

        void AppendCastIfNecessary(StackValueKind dstType, TypeDesc srcType)
        {
            if (dstType == StackValueKind.ByRef)
            {
                Append("("); 
                Append(_writer.GetCppSignatureTypeName(srcType));
                Append(")");
            }
            else
            if (srcType.IsPointer)
            {
                Append("(intptr_t)");
            }
        }

        Value NewSpillSlot(StackValueKind kind, TypeDesc type)
        {
            if (_spillSlots == null)
                _spillSlots = new List<SpillSlot>();

            SpillSlot spillSlot = new SpillSlot();
            spillSlot.Kind = kind;
            spillSlot.Type = type;
            spillSlot.Name = "_s" + _spillSlots.Count.ToString();

            _spillSlots.Add(spillSlot);

            return new Value() { Name = spillSlot.Name };
        }

        void Append(string s)
        {
            _builder.Append(s);
        }

        void Finish()
        {
            // _builder.AppendLine(";");
            _builder.Append("; ");
        }

        string GetVarName(int index, bool argument)
        {
            if (_localSlotToInfoMap != null && !argument && _localSlotToInfoMap.ContainsKey(index) && !_localSlotToInfoMap[index].CompilerGenerated)
            {
                return _localSlotToInfoMap[index].Name;
            }

            if (_parameterIndexToNameMap != null && argument && _parameterIndexToNameMap.ContainsKey(index))
            {
                return _writer.SanitizeCppVarName(_parameterIndexToNameMap[index]);
            }

            return (argument ? "_a" : "_l") + index.ToString();
        }

        TypeDesc GetVarType(int index, bool argument)
        {
            if (argument)
            {
                if (_thisType != null)
                    index--;
                if (index == -1)
                {
                    if (_thisType.IsValueType)
                        return _thisType.MakeByRefType();
                    return _thisType;
                }
                else return _methodSignature[index];
            }
            else
            {
               return _locals[index].Type;
            }
        }

        TypeDesc GetWellKnownType(WellKnownType wellKnownType)
        {
            return _typeSystemContext.GetWellKnownType(wellKnownType);
        }

        TypeDesc ResolveTypeToken(int token)
        {
            return (TypeDesc)_methodIL.GetObject(token);
        }

        void MarkInstructionBoundary()
        {
        }

        void StartImportingInstruction()
        {
            if (_sequencePoints == null)
                return;

            var sequencePoint = _sequencePoints[_currentOffset];
            if (sequencePoint.Document == null)
                return;

            _builder.AppendLine();

            Append("#line ");
            Append(sequencePoint.LineNumber.ToString());
            Append(" \"");
            Append(sequencePoint.Document.Replace("\\", "\\\\"));
            Append("\"");

            _builder.AppendLine();
        }

        void EndImportingInstruction()
        {
            if (_sequencePoints == null)
                _builder.AppendLine();
        }

        public string Compile()
        {
            FindBasicBlocks();

            ImportBasicBlocks();

            if (_sequencePoints != null && _sequencePoints[0].Document != null)
            {
                var sequencePoint = _sequencePoints[0];

                Append("#line ");
                Append(sequencePoint.LineNumber.ToString());
                Append(" \"");
                Append(sequencePoint.Document.Replace("\\", "\\\\"));
                Append("\"");

                _builder.AppendLine();
            }

            Append(_writer.GetCppMethodDeclaration(_method, true));

            _builder.Append("{");

            bool initLocals = _methodIL.GetInitLocals();
            for (int i = 0; i < _locals.Length; i++)
            {
                Append(_writer.GetCppSignatureTypeName(_locals[i].Type));
                Append(" ");
                Append(GetVarName(i, false));
                if (initLocals)
                {
                    TypeDesc localType = _locals[i].Type;
                    if (localType.IsValueType && !localType.IsPrimitive && !localType.IsEnum)
                    {
                        Finish();
                        Append("memset(&");
                        Append(GetVarName(i, false));
                        Append(",0,sizeof(");
                        Append(_writer.GetCppSignatureTypeName(localType));
                        Append("))");
                    }
                    else
                    {
                        Append("=0");
                    }
                }
                Finish();
            }

            if (_spillSlots != null)
            {
                for (int i = 0; i < _spillSlots.Count; i++)
                {
                    SpillSlot spillSlot = _spillSlots[i];
                    Append(GetStackValueKindCPPTypeName(spillSlot.Kind, spillSlot.Type));
                    Append(" ");
                    Append(spillSlot.Name);
                    Finish();
                }
            }

            for (int i = 0; i < _exceptionRegions.Length; i++)
            {
                var r = _exceptionRegions[i];
                if (r.ReturnLabels != 0)
                {
                    _builder.Append("int __finallyReturn");
                    _builder.Append(i.ToString());
                    _builder.Append("=0;");
                }
            }

            for (int i = 0; i < _basicBlocks.Length; i++)
            {
                BasicBlock basicBlock = _basicBlocks[i];
                if (basicBlock != null)
                {
                    _builder.Append("_bb");
                    _builder.Append(i.ToString());
                    _builder.AppendLine(": {");
                    _builder.Append(basicBlock.Code);
                    // _builder.AppendLine("}");
                    _builder.Append("} ");
                }
            }

            for (int i = 0; i < _exceptionRegions.Length; i++)
            {
                var r = _exceptionRegions[i];
                if (r.ReturnLabels != 0)
                {
                    _builder.AppendLine("__endFinally" + i.ToString() + ": switch(__finallyReturn" + i.ToString() + ") {");
                    for (int j = 1; j <= r.ReturnLabels; j++)
                        _builder.AppendLine("case " + j.ToString() + ": goto __returnFromFinally" + i.ToString() + "_" + j.ToString() + ";");
                    _builder.AppendLine("default: " + (_msvc ? "__assume(0)" : "__builtin_unreachable()") + "; }");
                }
            }

            _builder.AppendLine("}");

            return _builder.ToString();
        }

        void StartImportingBasicBlock(BasicBlock basicBlock)
        {
        }

        void EndImportingBasicBlock(BasicBlock basicBlock)
        {
            basicBlock.Code = _builder.ToString();
            _builder.Clear();
        }

        void ImportNop()
        {
        }

        void ImportBreak()
        {
            throw new NotImplementedException("Opcode: break");
        }

        void ImportLoadVar(int index, bool argument)
        {
            string name = GetVarName(index, argument);
            string temp = NewTempName();

            TypeDesc type = GetVarType(index, argument);
            StackValueKind kind = GetStackValueKind(type);

            PushTemp(kind, type);
            AppendCastIfNecessary(kind, type);
            Append(name);
            Finish();
        }

        void ImportStoreVar(int index, bool argument)
        {
            var value = Pop();

            string name = GetVarName(index, argument);

            Append(name);
            Append("=");
            TypeDesc type = GetVarType(index, argument);
            AppendCastIfNecessary(type, value.Kind);
            Append(value.Value.Name);
            Finish();
        }

        void ImportAddressOfVar(int index, bool argument)
        {
            string name = GetVarName(index, argument);
            string temp = NewTempName();

            TypeDesc type = GetVarType(index, argument);
            type = type.MakeByRefType();

            PushTemp(StackValueKind.ByRef, type);
            AppendCastIfNecessary(StackValueKind.ByRef, type);
            Append("&");
            Append(name);
            Finish();
        }

        void ImportDup()
        {
            Push(_stack[_stackTop - 1]);
        }

        void ImportPop()
        {
            Pop();
        }

        void ImportJmp(int token)
        {
            throw new NotImplementedException("Opcode: jmp");
        }

        void ImportCasting(ILOpcode opcode, int token)
        {
            TypeDesc type = (TypeDesc)_methodIL.GetObject(token);

            if (type.IsInterface || type.IsArray)
                throw new NotImplementedException();

            var value = Pop();
            PushTemp(StackValueKind.ObjRef, type);

            Append(opcode == ILOpcode.isinst ? "__isinst_class" : "__castclass_class");
            Append("(");
            Append(value.Value.Name);
            Append(", ");
            Append(_writer.GetCppTypeName(type));
            Append("::__getMethodTable())");
            Finish();
        }

        void ImportIntrinsicCall(IntrinsicMethodKind intrinsicClassification)
        {
            switch (intrinsicClassification)
            {
                case IntrinsicMethodKind.RuntimeHelpersInitializeArray:
                    {
                        var fieldSlot = Pop();
                        var arraySlot = Pop();

                        var fieldDesc = (TypeSystem.Ecma.EcmaField)fieldSlot.Value.Aux;
                        int addr = fieldDesc.MetadataReader.GetFieldDefinition(fieldDesc.Handle).GetRelativeVirtualAddress();
                        var memBlock = fieldDesc.Module.PEReader.GetSectionData(addr).GetContent();

                        var fieldType = (TypeSystem.Ecma.EcmaType)fieldDesc.FieldType;
                        int size = fieldType.MetadataReader.GetTypeDefinition(fieldType.Handle).GetLayout().Size;
                        if (size == 0)
                            throw new NotImplementedException();

                        // TODO: Need to do more for arches with different endianness?
                        var preinitDataHolder = NewTempName();
                        Append("static const char ");
                        Append(preinitDataHolder);
                        Append("[] = { ");

                        for (int i = 0; i < size; i++)
                        {
                            if (i != 0)
                                Append(", ");
                            Append(String.Format("0x{0:X}", memBlock[i]));
                        }
                        Append(" }");
                        Finish();

                        Append("memcpy((char*)");
                        Append(arraySlot.Value.Name);
                        Append(" + ARRAY_BASE, ");
                        Append(preinitDataHolder);
                        Append(", ");
                        Append(size.ToString());
                        Append(")");

                        Finish();
                        break;
                    }
                default: throw new NotImplementedException();
            }
        }

        void ImportCall(ILOpcode opcode, int token)
        {
            bool callViaSlot = false;
            bool delegateInvoke = false;
            DelegateInfo delegateInfo = null;
            bool mdArrayCreate = false;

            MethodDesc method = (MethodDesc)_methodIL.GetObject(token);

            var intrinsicClassification = IntrinsicMethods.GetIntrinsicMethodClassification(method);
            if (intrinsicClassification != IntrinsicMethodKind.None)
            {
                ImportIntrinsicCall(intrinsicClassification);
                return;
            }

            if (opcode == ILOpcode.calli)
                throw new NotImplementedException();

            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 retType = null;

            {
                TypeDesc owningType = method.OwningType;
                if (opcode == ILOpcode.newobj)
                    retType = owningType;

                if (opcode == ILOpcode.newobj)
                {
                    if (owningType.IsString)
                    {
                        // String constructors actually look like regular method calls
                        method = IntrinsicMethods.GetStringInitializer(method);
                        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();

                    _compilation.AddVirtualSlot(method);

                    callViaSlot = true;
                }
            }

            if (!callViaSlot && !delegateInvoke && !mdArrayCreate)
                _compilation.AddMethod(method);

            if (opcode == ILOpcode.newobj)
                _compilation.MarkAsConstructed(retType);

            var methodSignature = method.Signature;

            if (retType == null)
                retType = methodSignature.ReturnType;

            string temp = null;
            StackValueKind retKind = StackValueKind.Unknown;

            if (!retType.IsVoid)
            {
                retKind = GetStackValueKind(retType);
                temp = NewTempName();

                Append(GetStackValueKindCPPTypeName(retKind, retType));
                Append(" ");
                Append(temp);
                if (retType.IsValueType && opcode == ILOpcode.newobj)
                {
                    Append(";");
                }
                else
                {
                    Append("=");

                    if (retType.IsPointer)
                    {
                        Append("(intptr_t)");
                    }
                }
            }

            if (opcode == ILOpcode.newobj && !mdArrayCreate)
            {
                if (!retType.IsValueType)
                {
                    _compilation.AddType(retType);

                    Append("__allocate_object(");
                    Append(_writer.GetCppTypeName(retType));
                    Append("::__getMethodTable())");
                    Finish();

                    if (delegateInfo != null && delegateInfo.ShuffleThunk != null)
                    {
                        _stack[_stackTop - 2].Value.Name = temp;

                        StringBuilder sb = new StringBuilder();
                        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 (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)
            {
                _compilation.AddType(method.OwningType);
                Append("RhNewMDArray");
            }
            else
            {
                Append(_writer.GetCppTypeName(method.OwningType));
                Append("::");
                Append(_writer.GetCppMethodName(method));
            }


            Append("(");
            int count = methodSignature.Length;
            bool hasThis = !methodSignature.IsStatic;
            if (hasThis)
                count++;
            if (mdArrayCreate)
            {
                Append(_writer.GetCppTypeName(method.OwningType));
                Append("::__getMethodTable(), ");
                Append(((ArrayType)method.OwningType).Rank.ToString());
                Append(", ");
                count--;
            }
            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);
                }
                count--;
                if (count > 0)
                    Append(", ");
            }
            for (int i = 0; i < count; i++)
            {
                var op = _stack[_stackTop - count + i];
                int argIndex = methodSignature.Length - (count - i);
                TypeDesc argType;
                if (argIndex == -1)
                {
                    argType = method.OwningType;
                    if (argType.IsValueType)
                        argType = argType.MakeByRefType();
                }
                else
                {
                    argType = methodSignature[argIndex];
                }
                AppendCastIfNecessary(argType, op.Kind);
                Append(op.Value.Name);
                if (i != count - 1)
                    Append(", ");
            }
            _stackTop -= count;
            Append(")");

            if (temp != null)
                Push(retKind, new Value(temp), retType);
            Finish();
        }

        void ImportLdFtn(int token, ILOpcode opCode)
        {
            MethodDesc method = (MethodDesc)_methodIL.GetObject(token);

            if (opCode == ILOpcode.ldvirtftn)
            {
                if (method.IsVirtual)
                    throw new NotImplementedException();
            }

            _compilation.AddMethod(method);

            PushTemp(StackValueKind.NativeInt);
            Append("(intptr_t)&");
            Append(_writer.GetCppTypeName(method.OwningType));
            Append("::");
            Append(_writer.GetCppMethodName(method));

            _stack[_stackTop-1].Value.Aux = method;

            Finish();
        }

        void ImportLoadInt(long value, StackValueKind kind)
        {
            string val;
            if (kind == StackValueKind.Int64)
            {
                if (value == Int64.MinValue)
                    val = "(int64_t)(0x8000000000000000" + (_msvc ? "i64" : "LL") + ")";
                else
                    val = value.ToString() + (_msvc ? "i64" : "LL");
            }
            else
            {
{'fraction_non_alphanumeric': 0.09172903163237267, 'fraction_numerical': 0.003652997559280392, 'mean_word_length': 1.2370552502169512, 'pattern_counts': {'":': 20, '<': 43, '<?xml version=': 0, '>': 35, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6886247', 'n_tokens_mistral': 15597, 'n_tokens_neox': 14440, 'n_words': 2917}