Пример #1
0
        public DotNetField(PEFile file, Field backend, DotNetType parrent, int indexintable)
        {
            this.file         = file;
            this.ParrentType  = parrent;
            this.BackendTabel = backend;
            this.IndexInTabel = indexintable;
            flags             = (FieldAttribs)BackendTabel.Flags;
            Name = file.ClrStringsStream.GetByOffset(backend.Name);


            //Read the field info in blob stream
            var b = new BinaryReader(new MemoryStream(file.BlobStream));

            b.BaseStream.Position = backend.Signature;

            var size   = b.ReadByte();
            var prolog = b.ReadByte();

            ValueType = ReadParam(b, parrent.File);
        }
Пример #2
0
        public MethodDeclTag GetCompareFieldsDeclTag(Compiler compiler)
        {
            if (m_fieldsEqualMethodDecl != null)
                return m_fieldsEqualMethodDecl;

            MethodSignatureParam[] sigParams = new MethodSignatureParam[2];

            TypeSpecGenericParamTag m0Type = new TypeSpecGenericParamTag(new TypeSpecGenericParamTypeTag(TypeSpecGenericParamTypeTag.Values.MVar), 0);
            m0Type = (TypeSpecGenericParamTag)compiler.TagRepository.InternTypeSpec(m0Type);

            sigParams[0] = new MethodSignatureParam(m0Type, new MethodSignatureParamTypeOfType(MethodSignatureParamTypeOfType.Values.ByRef));
            sigParams[1] = sigParams[0];

            MethodSignatureTag signature = new MethodSignatureTag(1, GetSystemBoolType(compiler), sigParams);
            signature = compiler.TagRepository.InternMethodSignature(signature);

            MethodDeclTag declTag = new MethodDeclTag("FieldsEqual", signature, GetClarityToolsType(compiler).TypeName);
            declTag = compiler.TagRepository.InternMethodDeclTag(declTag);

            m_fieldsEqualMethodDecl = declTag;

            return declTag;
        }
Пример #3
0
        public uint GetEqualsVTableSlot(Compiler compiler)
        {
            if (m_equalsVTableSlot.HasValue)
                return m_equalsVTableSlot.Value;

            MethodSignatureParam[] sigParams = new MethodSignatureParam[1];
            sigParams[0] = new MethodSignatureParam(GetSystemObjectType(compiler), new MethodSignatureParamTypeOfType(MethodSignatureParamTypeOfType.Values.Value));

            MethodSignatureTag signature = new MethodSignatureTag(0, GetSystemBoolType(compiler), sigParams);
            signature = compiler.TagRepository.InternMethodSignature(signature);

            MethodDeclTag declTag = new MethodDeclTag("Equals", signature, GetSystemObjectType(compiler).TypeName);
            declTag = compiler.TagRepository.InternMethodDeclTag(declTag);

            CliClass cls = compiler.GetClosedClass(GetSystemObjectType(compiler));
            uint result = cls.DeclTagToVTableSlot[declTag];

            m_equalsVTableSlot = result;

            return result;
        }
Пример #4
0
        internal static MethodSignatureParam ReadParam(BinaryReader r, DotNetFile file)
        {
            string sig;
            var    parm = r.ReadByte();
            MethodSignatureParam ret = new MethodSignatureParam();

            switch (parm)
            {
            case 0x00:
            {
                //end of list
                sig      = "End of list";
                ret.type = StackItemType.Array;         //array maybe?
                break;
            }

            case 0x01:
            {
                sig      = "void";
                ret.type = StackItemType.None;
                break;
            }

            case 0x02:
            {
                sig      = "bool";
                ret.type = StackItemType.Boolean;
                break;
            }

            case 0x03:
            {
                sig      = "char";
                ret.type = StackItemType.Char;
                break;
            }

            case 0x04:
            {
                sig      = "sbyte";
                ret.type = StackItemType.SByte;
                break;
            }

            case 0x05:
            {
                sig      = "byte";
                ret.type = StackItemType.Byte;
                break;
            }

            case 0x06:
            {
                sig      = "short";
                ret.type = StackItemType.Int16;
                break;
            }

            case 0x07:
            {
                sig      = "ushort";
                ret.type = StackItemType.UInt16;
                break;
            }

            case 0x08:
            {
                sig      = "int";
                ret.type = StackItemType.Int32;
                break;
            }

            case 0x09:
            {
                sig      = "uint";
                ret.type = StackItemType.UInt32;
                break;
            }

            case 0x0A:
            {
                sig      = "long";
                ret.type = StackItemType.Int64;
                break;
            }

            case 0x0B:
            {
                sig      = "ulong";
                ret.type = StackItemType.UInt64;
                break;
            }

            case 0x0C:
            {
                sig      = "float";
                ret.type = StackItemType.Float32;
                break;
            }

            case 0x0D:
            {
                sig      = "double";
                ret.type = StackItemType.Float64;
                break;
            }

            case 0x0E:
            {
                sig      = "string";
                ret.type = StackItemType.String;
                break;
            }

            case 0xF:
                //Pointer* (followed by type)
            {
                sig      = ReadParam(r, file).TypeInString + "*";
                ret.type = StackItemType.Int32;
                break;
            }

            case 0x10:
                //byref* //followed by type
            {
                sig      = "ref " + ReadParam(r, file).TypeInString;
                ret.type = StackItemType.Int32;
                break;
            }

            case 0x11:
                //valve type (followed by typedef or typeref token)
            {
                var t = IlDecompiler.ParseNumber(r);         //type of the type
                IlDecompiler.DecodeTypeDefOrRef(t, out uint rowType, out uint index);
                string name;
                string Namespace;
                ret.type    = StackItemType.Object;
                ret.IsClass = true;
                if (rowType == 0)
                {
                    //typedef
                    var tt = file.Backend.Tabels.TypeDefTabel[(int)(index - 1)];
                    name      = file.Backend.ClrStringsStream.GetByOffset(tt.Name);
                    Namespace = file.Backend.ClrStringsStream.GetByOffset(tt.Namespace);

                    //resolve it
                    foreach (var item in file.Types)
                    {
                        if (item.NameSpace == Namespace && item.Name == name)
                        {
                            ret.ClassType = item;
                        }
                    }
                }
                else if (rowType == 1)
                {
                    //typeref
                    var tt = file.Backend.Tabels.TypeRefTabel[(int)(index - 1)];
                    name      = file.Backend.ClrStringsStream.GetByOffset(tt.TypeName);
                    Namespace = file.Backend.ClrStringsStream.GetByOffset(tt.TypeNamespace);
                }
                else
                {
                    throw new NotImplementedException();
                }
                if (!string.IsNullOrEmpty(Namespace))
                {
                    sig = $"{Namespace}.{name}";
                }
                else
                {
                    sig = $"{name}";
                }
                break;
            }

            case 0x12:
                //class followed by typedef or typeref token
            {
                var t = IlDecompiler.ParseNumber(r);         //type of the type
                IlDecompiler.DecodeTypeDefOrRef(t, out uint rowType, out uint index);
                string name;
                string Namespace;
                ret.type    = StackItemType.Object;
                ret.IsClass = true;
                if (rowType == 0)
                {
                    //typedef
                    var tt = file.Backend.Tabels.TypeDefTabel[(int)(index - 1)];
                    name      = file.Backend.ClrStringsStream.GetByOffset(tt.Name);
                    Namespace = file.Backend.ClrStringsStream.GetByOffset(tt.Namespace);

                    //resolve it
                    foreach (var item in file.Types)
                    {
                        if (item.NameSpace == Namespace && item.Name == name)
                        {
                            ret.ClassType = item;
                        }
                    }
                }
                else if (rowType == 1)
                {
                    //typeref
                    var tt = file.Backend.Tabels.TypeRefTabel[(int)(index - 1)];
                    name      = file.Backend.ClrStringsStream.GetByOffset(tt.TypeName);
                    Namespace = file.Backend.ClrStringsStream.GetByOffset(tt.TypeNamespace);
                }
                else
                {
                    throw new NotImplementedException();
                }
                if (!string.IsNullOrEmpty(Namespace))
                {
                    sig = $"{Namespace}.{name}";
                }
                else
                {
                    sig = $"{name}";
                }
                break;
            }

            case 0x13:
                //GENERIC_PARM
            {
                var b = IlDecompiler.ParseNumber(r);
                sig      = "T";
                ret.type = StackItemType.Any;
                break;
            }

            case 0x14:
            {
                sig      = "[][]";
                ret.type = StackItemType.Array;
                break;
            }

            case 0x15:
            {
                //ELEMENT_TYPE_GENERICINST
                var t = IlDecompiler.ParseNumber(r);         //type of the generic type
                var c = IlDecompiler.ParseNumber(r);         //generic type (TypeDefOrRefEncoded)
                var d = IlDecompiler.ParseNumber(r);         //Count of generic args
                IlDecompiler.DecodeTypeDefOrRef((uint)c, out uint rowType, out uint index);
                ret.IsGeneric = true;
                ret.type      = StackItemType.Object;
                List <MethodSignatureParam> @params = new List <MethodSignatureParam>();
                for (ulong i = 0; i < d; i++)
                {
                    @params.Add(ReadParam(r, file));
                }


                if (rowType == 0)
                {
                    //typedef
                    var tt        = file.Backend.Tabels.TypeDefTabel[(int)(index - 1)];
                    var name      = file.Backend.ClrStringsStream.GetByOffset(tt.Name);
                    var Namespace = file.Backend.ClrStringsStream.GetByOffset(tt.Namespace);

                    if (!string.IsNullOrEmpty(Namespace))
                    {
                        sig = $"{Namespace}.{name}<";
                    }
                    else
                    {
                        sig = $"{name}<";
                    }

                    ret.GenericClassNamespace = Namespace;
                    ret.GenericClassName      = name;
                }
                else if (rowType == 1)
                {
                    //typeref
                    var tt        = file.Backend.Tabels.TypeRefTabel[(int)(index - 1)];
                    var name      = file.Backend.ClrStringsStream.GetByOffset(tt.TypeName);
                    var Namespace = file.Backend.ClrStringsStream.GetByOffset(tt.TypeNamespace);

                    if (!string.IsNullOrEmpty(Namespace))
                    {
                        sig = $"{Namespace}.{name}<";
                    }
                    else
                    {
                        sig = $"{name}<";
                    }

                    ret.GenericClassNamespace = Namespace;
                    ret.GenericClassName      = name;
                }
                else
                {
                    throw new NotImplementedException();
                }

                foreach (var item in @params)
                {
                    sig += item.TypeInString + ", ";
                }
                sig  = sig.Substring(0, sig.Length - 2);
                sig += ">";
                break;
            }

            case 0x16:
            {
                //TypedRefrerence structure
                sig      = "TypedReference";
                ret.type = StackItemType.Object;
                break;
            }

            case 0x18:
            {
                //IntPtr
                sig      = "IntPtr";
                ret.type = StackItemType.IntPtr;
                break;
            }

            case 0x19:
            {
                //UIntPtr
                sig      = "UIntPtr";
                ret.type = StackItemType.UIntPtr;
                break;
            }

            case 0x1B:
            {
                sig      = "func ptr";
                ret.type = StackItemType.MethodPtr;
                break;
            }

            case 0x1C:
            {
                sig      = "object";
                ret.type = StackItemType.Object;
                break;
            }

            case 0x1D:
            {
                ret.ArrayType = ReadParam(r, file);
                sig           = ret.ArrayType.TypeInString + "[]";
                ret.type      = StackItemType.Array;
                ret.IsArray   = true;
                break;
            }

            case 0x1E:
                //MVar
                var num = IlDecompiler.ParseNumber(r);
                sig = "T" + num;

                break;

            case 0x20:
                var num2 = IlDecompiler.ParseNumber(r);
                IlDecompiler.DecodeTypeDefOrRef((uint)num2, out uint rowType2, out uint index2);
                sig = "TODO: 0x20";
                break;

            default:
                throw new System.NotImplementedException("Unknown byte: 0x" + parm.ToString("X"));
            }

            ret.TypeInString = sig;
            return(ret);
        }
Пример #5
0
        private void ProcessInstruction(HighCfgNode cfgNode, HighInstruction instr, List<HighInstruction> newInstrs)
        {
            bool validationOnly = true;

            {
                IBranchingInstruction brInstr = instr as IBranchingInstruction;
                if (brInstr != null)
                {
                    brInstr.VisitSuccessors(delegate (ref HighCfgEdge edge)
                    {
                        HighCfgNode dest = edge.Dest.Value;
                        foreach (HighCfgNodeHandle pred in dest.Predecessors)
                            if (pred.Value == cfgNode)
                                return;
                        throw new RpaCompileException("Branching instruction jumps to undeclared predecessor");
                    });
                }
            }

            switch (instr.Opcode)
            {
                case HighInstruction.Opcodes.LoadLocal:
                    {
                        LoadLocalInstruction tInstr = (LoadLocalInstruction)instr;
                        HighSsaRegister dest = tInstr.Dest;
                        HighLocal local = tInstr.Local;

                        switch (local.TypeOfType)
                        {
                            case HighLocal.ETypeOfType.ByRef:
                                if (dest.ValueType != HighValueType.ManagedPtr)
                                    throw new RpaCompileException("Illegal LoadLocal");
                                break;
                            case HighLocal.ETypeOfType.TypedByRef:
                                throw new NotImplementedException();
                            case HighLocal.ETypeOfType.Value:
                                if (dest.ValueType != HighValueType.ValueValue && dest.ValueType != HighValueType.ReferenceValue)
                                    throw new RpaCompileException("Illegal LoadLocal");
                                break;
                            default:
                                throw new Exception();
                        }

                        if (dest.Type != local.Type)
                            throw new RpaCompileException("Type mismatch in LoadLocal");
                    }
                    break;
                case HighInstruction.Opcodes.AllocArray:
                    {
                        AllocArrayInstruction tInstr = (AllocArrayInstruction)instr;

                        HighSsaRegister dest = tInstr.Dest;
                        if (dest == null)
                            throw new RpaCompileException("AllocArray has no destination");
                        if (dest.ValueType != HighValueType.ReferenceValue || !(dest.Type is TypeSpecArrayTag))
                            throw new RpaCompileException("AllocArray destination is not an array");
                        TypeSpecArrayTag type = (TypeSpecArrayTag)dest.Type;
                        if (type.Rank != (uint)tInstr.Sizes.Length)
                            throw new RpaCompileException("AllocArray index count doesn't match destination type rank");

                        foreach (HighSsaRegister sz in tInstr.Sizes)
                        {
                            switch (sz.ValueType)
                            {
                                case HighValueType.ConstantValue:
                                case HighValueType.ValueValue:
                                    break;
                                default:
                                    throw new RpaCompileException("AllocArray index is invalid");
                            }

                            if (sz.Type != m_nativeIntType)
                                throw new RpaCompileException("AllocArray index is invalid");
                        }

                        this.Compiler.GetRloVTable(dest.Type, GenerateMethodInstantiationPath(tInstr.CodeLocation));
                    }
                    break;
                case HighInstruction.Opcodes.AllocObj:
                    {
                        AllocObjInstruction tInstr = (AllocObjInstruction)instr;

                        HighSsaRegister dest = tInstr.Dest;
                        if (dest == null)
                            throw new RpaCompileException("AllocObj has no destination");

                        if (dest.ValueType != HighValueType.ReferenceValue)
                            throw new RpaCompileException("AllocObj destination is not a reference type");

                        TypeSpecClassTag destType = dest.Type as TypeSpecClassTag;
                        if (destType == null)
                            throw new RpaCompileException("AllocObj destination type is not a class");

                        HighTypeDef typeDef = this.Compiler.GetTypeDef(destType.TypeName);
                        if (typeDef.Semantics != TypeSemantics.Class)
                            throw new RpaCompileException("AllocObj created non-class");
                        if (typeDef.IsAbstract)
                            throw new RpaCompileException("AllocObj created class is abstract");

                        this.Compiler.GetRloVTable(destType, GenerateMethodInstantiationPath(tInstr.CodeLocation));
                    }
                    break;
                case HighInstruction.Opcodes.Box:
                    {
                        BoxInstruction tInstr = (BoxInstruction)instr;

                        HighSsaRegister dest = tInstr.Dest;
                        HighSsaRegister src = tInstr.Src;
                        if (dest == null)
                            throw new RpaCompileException("Box has no destination");

                        if ((src.ValueType == HighValueType.ConstantValue || src.ValueType == HighValueType.ValueValue) && dest.ValueType == HighValueType.BoxedValue)
                        {
                            // Normally don't do anything, leave box as canonical
                            // In the case of Nullable`1 only, convert the box instruction
                            if (dest.Type != src.Type)
                            {
                                if (!(src.Type is TypeSpecClassTag))
                                    throw new RpaCompileException("Invalid box source type");
                                TypeSpecClassTag srcClass = (TypeSpecClassTag)src.Type;
                                TypeNameTag srcClassName = srcClass.TypeName;
                                if (srcClassName.ContainerType != null || srcClassName.AssemblyName != "mscorlib" || srcClassName.TypeNamespace != "System" || srcClassName.TypeName != "Nullable`1" || srcClass.ArgTypes.Length != 1)
                                    throw new RpaCompileException("Invalid box source type");
                                TypeSpecTag srcSubType = srcClass.ArgTypes[0];

                                if (dest.Type != srcSubType)
                                    throw new RpaCompileException("Nullable box type mixmatch");

                                validationOnly = false;

                                TypeNameTag clarityToolsName = new TypeNameTag("mscorlib", "Clarity", "Tools");
                                clarityToolsName = this.Compiler.TagRepository.InternTypeName(clarityToolsName);

                                TypeSpecClassTag clarityToolsClass = new TypeSpecClassTag(clarityToolsName, new TypeSpecTag[0]);
                                clarityToolsClass = (TypeSpecClassTag)this.Compiler.TagRepository.InternTypeSpec(clarityToolsClass);

                                TypeNameTag nullableName = new TypeNameTag("mscorlib", "System", "Nullable`1", 1, null);
                                nullableName = this.Compiler.TagRepository.InternTypeName(nullableName);

                                TypeSpecGenericParamTypeTag mArgType = new TypeSpecGenericParamTypeTag(TypeSpecGenericParamTypeTag.Values.MVar);
                                TypeSpecGenericParamTag m0Type = new TypeSpecGenericParamTag(mArgType, 0);
                                m0Type = (TypeSpecGenericParamTag)this.Compiler.TagRepository.InternTypeSpec(m0Type);

                                TypeSpecClassTag nullableM0Class = new TypeSpecClassTag(nullableName, new TypeSpecTag[] { m0Type });
                                nullableM0Class = (TypeSpecClassTag)this.Compiler.TagRepository.InternTypeSpec(nullableM0Class);

                                MethodSignatureParam[] bnDeclParams = new MethodSignatureParam[] { new MethodSignatureParam(nullableM0Class, new MethodSignatureParamTypeOfType(MethodSignatureParamTypeOfType.Values.Value)) };
                                MethodSignatureTag bnDeclSignature = new MethodSignatureTag(1, m_objectType, bnDeclParams);
                                bnDeclSignature = this.Compiler.TagRepository.InternMethodSignature(bnDeclSignature);

                                MethodDeclTag boxNullableDecl = new MethodDeclTag("BoxNullable", bnDeclSignature, clarityToolsName);
                                boxNullableDecl = this.Compiler.TagRepository.InternMethodDeclTag(boxNullableDecl);

                                MethodSpecTag bnMethodSpec = new MethodSpecTag(MethodSlotType.Static, new TypeSpecTag[] { srcSubType }, clarityToolsClass, boxNullableDecl);
                                bnMethodSpec = this.Compiler.TagRepository.InternMethodSpec(bnMethodSpec);

                                MethodHandle hdl = this.Compiler.InstantiateMethod(new MethodSpecMethodKey(bnMethodSpec), GenerateMethodInstantiationPath(tInstr.CodeLocation));

                                newInstrs.Add(new Instructions.CallRloStaticMethodInstruction(tInstr.CodeLocation, hdl, dest, new HighSsaRegister[] { src }));
                            }
                            else
                            {
                                TypeSpecBoxTag boxType = new TypeSpecBoxTag((TypeSpecClassTag)dest.Type);
                                boxType = (TypeSpecBoxTag)this.Compiler.TagRepository.InternTypeSpec(boxType);
                                this.Compiler.GetRloVTable(boxType, GenerateMethodInstantiationPath(tInstr.CodeLocation));
                            }
                        }
                        else if (src.ValueType == HighValueType.ReferenceValue && dest.ValueType == HighValueType.ReferenceValue)
                        {
                            if (dest.Type != src.Type)
                                throw new RpaCompileException("Box instruction destination is a different type from source");

                            // Source should never be ConstantString at this stage.
                            // Boxing a reference type converts to a copy
                            validationOnly = false;
                            newInstrs.Add(new Instructions.CopyInstruction(tInstr.CodeLocation, dest, src));
                        }
                    }
                    break;
                case HighInstruction.Opcodes.Arith:
                    {
                        ArithInstruction tInstr = (ArithInstruction)instr;
                        TypeSpecClassTag expectedClass = ExpectedClassForArithType(tInstr.ArithType);

                        if (tInstr.CheckOverflow)
                        {
                            switch (tInstr.ArithType)
                            {
                                case NumberArithType.Int32:
                                case NumberArithType.Int64:
                                case NumberArithType.NativeInt:
                                case NumberArithType.NativeUInt:
                                case NumberArithType.UInt32:
                                case NumberArithType.UInt64:
                                    break;
                                case NumberArithType.Float32:
                                case NumberArithType.Float64:
                                    throw new RpaCompileException("Check overflow flag on flowing point arith operation");
                                default:
                                    throw new Exception();
                            }
                        }

                        CheckArithDest(tInstr.Dest, expectedClass);
                        CheckArithOperand(tInstr.Left, expectedClass);
                        CheckArithOperand(tInstr.Right, expectedClass);
                    }
                    break;
                case HighInstruction.Opcodes.BranchCompareNumbers:
                    {
                        BranchCompareNumbersInstruction tInstr = (BranchCompareNumbersInstruction)instr;

                        TypeSpecClassTag expectedClass = ExpectedClassForArithType(tInstr.ArithType);

                        CheckArithOperand(tInstr.Left, expectedClass);
                        CheckArithOperand(tInstr.Right, expectedClass);
                    }
                    break;
                case HighInstruction.Opcodes.DynamicCast:
                    {
                        DynamicCastInstruction tInstr = (DynamicCastInstruction)instr;

                        if (tInstr.Dest != null)
                        {
                            switch (tInstr.Dest.ValueType)
                            {
                                case HighValueType.BoxedValue:
                                case HighValueType.ReferenceValue:
                                    break;
                                default:
                                    throw new RpaCompileException("Illegal destination type for dynamic cast instruction");
                            }
                        }

                        switch (tInstr.Src.ValueType)
                        {
                            case HighValueType.BoxedValue:
                            case HighValueType.ConstantString:
                            case HighValueType.Null:
                            case HighValueType.ReferenceValue:
                                break;
                            default:
                                throw new RpaCompileException("Illegal source type for dynamic cast instruction.");
                        }
                    }
                    break;
                case HighInstruction.Opcodes.ForceDynamicCast:
                    {
                        ForceDynamicCastInstruction tInstr = (ForceDynamicCastInstruction)instr;

                        if (tInstr.Dest != null)
                        {
                            switch (tInstr.Dest.ValueType)
                            {
                                case HighValueType.BoxedValue:
                                case HighValueType.ReferenceValue:
                                    break;
                                default:
                                    throw new RpaCompileException("Illegal destination type for force dynamic cast instruction");
                            }
                        }

                        switch (tInstr.Src.ValueType)
                        {
                            case HighValueType.BoxedValue:
                            case HighValueType.ConstantString:
                            case HighValueType.Null:
                            case HighValueType.ReferenceValue:
                                break;
                            default:
                                throw new RpaCompileException("Illegal source type for force dynamic cast instruction.");
                        }
                    }
                    break;
                case HighInstruction.Opcodes.GetArrayElementPtr:
                    {
                        GetArrayElementPtrInstruction tInstr = (GetArrayElementPtrInstruction)instr;

                        HighSsaRegister arraySrc = tInstr.ArraySrc;
                        if (arraySrc.ValueType != HighValueType.ReferenceValue)
                            throw new RpaCompileException("GetArrayElementPtr instruction array is not a reference");

                        TypeSpecArrayTag arrayType = arraySrc.Type as TypeSpecArrayTag;
                        if (arrayType == null)
                            throw new RpaCompileException("GetArrayElementPtr instruction arrays source is not an array");

                        if ((uint)tInstr.Indexes.Length != arrayType.Rank)
                            throw new RpaCompileException("GetArrayElementPtr instruction array source rank doesn't match index count");

                        HighSsaRegister dest = tInstr.Dest;
                        if (dest != null)
                        {
                            if (dest.ValueType != HighValueType.ManagedPtr)
                                throw new RpaCompileException("GetArrayElementPtr destination is not a managed pointer");
                            if (dest.Type != arrayType.SubscriptType)
                                throw new RpaCompileException("GetArrayElementPtr destination does not match subscript type");
                        }
                    }
                    break;
                case HighInstruction.Opcodes.CompareRefs:
                    {
                        CompareRefsInstruction tInstr = (CompareRefsInstruction)instr;
                        HighSsaRegister[] sources = new HighSsaRegister[2];
                        sources[0] = tInstr.SrcA;
                        sources[1] = tInstr.SrcB;

                        if (tInstr.Dest != null && tInstr.Dest.ValueType != HighValueType.ValueValue && tInstr.Dest.Type != m_int32Type)
                            throw new RpaCompileException("CompareRefs destination is not an int");

                        bool isSideConverted = false;
                        UpdateRefCompare(tInstr.CodeLocation, sources, newInstrs, out isSideConverted);

                        if (isSideConverted)
                        {
                            validationOnly = false;
                            newInstrs.Add(new CompareRefsInstruction(tInstr.CodeLocation, tInstr.Dest, sources[0], sources[1], tInstr.EqualValue, tInstr.NotEqualValue));
                        }
                    }
                    break;
                case HighInstruction.Opcodes.BranchCompareRefs:
                    {
                        BranchCompareRefsInstruction tInstr = (BranchCompareRefsInstruction)instr;
                        HighSsaRegister[] sources = new HighSsaRegister[2];
                        sources[0] = tInstr.SrcA;
                        sources[1] = tInstr.SrcB;

                        bool isSideConverted = false;
                        UpdateRefCompare(tInstr.CodeLocation, sources, newInstrs, out isSideConverted);

                        if (isSideConverted)
                        {
                            validationOnly = false;
                            newInstrs.Add(new BranchCompareRefsInstruction(tInstr.CodeLocation, sources[0], sources[1], tInstr.EqualEdge.Dest, tInstr.NotEqualEdge.Dest));
                        }
                    }
                    break;
                case HighInstruction.Opcodes.GetStaticFieldAddr:
                    {
                        GetStaticFieldAddrInstruction tInstr = (GetStaticFieldAddrInstruction)instr;

                        TypeSpecClassTag classSpec = tInstr.StaticType as TypeSpecClassTag;
                        if (classSpec == null)
                            throw new RpaCompileException("GetStaticFieldAddr type is not a class");
                        CliClass cls = this.Compiler.GetClosedClass(classSpec);

                        uint fieldIndex;
                        if (!cls.NameToStaticFieldSlot.TryGetValue(tInstr.FieldName, out fieldIndex))
                            throw new RpaCompileException("GetStaticFieldAddr could not match static field name");

                        HighSsaRegister dest = tInstr.Dest;
                        if (dest != null)
                        {
                            if (dest.ValueType != HighValueType.ManagedPtr)
                                throw new RpaCompileException("GetStaticFieldAddr dest is not a managed pointer");
                            if (dest.Type != cls.StaticFields[fieldIndex].Type)
                                throw new RpaCompileException("GetStaticFieldAddr dest type does not match field type");
                        }
                    }
                    break;
                case HighInstruction.Opcodes.BranchRefNull:
                    {
                        BranchRefNullInstruction tInstr = (BranchRefNullInstruction)instr;

                        HighSsaRegister src = tInstr.Src;
                        switch (src.ValueType)
                        {
                            case HighValueType.BoxedValue:
                            case HighValueType.ConstantString:
                            case HighValueType.Null:
                            case HighValueType.ReferenceValue:
                                break;
                            default:
                                throw new RpaCompileException("BranchRefNull source is not a reference");
                        }
                    }
                    break;
                case HighInstruction.Opcodes.GetTypeInfo:
                    {
                        GetTypeInfoInstruction tInstr = (GetTypeInfoInstruction)instr;

                        if (tInstr.Dest.ValueType != HighValueType.ValueValue || tInstr.Dest.Type != m_runtimeTypeHandleType)
                            throw new RpaCompileException("GetTypeInfo destination is not the correct type");
                    }
                    break;
                case HighInstruction.Opcodes.LoadPtr:
                    {
                        LoadPtrInstruction tInstr = (LoadPtrInstruction)instr;

                        if (tInstr.Dest != null)
                        {
                            switch (tInstr.Dest.ValueType)
                            {
                                case HighValueType.ReferenceValue:
                                case HighValueType.ValueValue:
                                    break;
                                default:
                                    throw new RpaCompileException("LoadPtr destination has an invalid value type");
                            }
                        }

                        if (tInstr.Src.ValueType != HighValueType.ManagedPtr)
                            throw new RpaCompileException("LoadPtr source is not a managed pointer");

                        if (tInstr.Src.Type != tInstr.Dest.Type)
                            throw new RpaCompileException("LoadPtr source type is not the same as dest type");
                    }
                    break;
                case HighInstruction.Opcodes.PtrField:
                    {
                        PtrFieldInstruction tInstr = (PtrFieldInstruction)instr;

                        HighSsaRegister dest = tInstr.Dest;
                        HighSsaRegister src = tInstr.Src;

                        if (src.ValueType != HighValueType.ManagedPtr)
                            throw new RpaCompileException("PtrField source not a field");

                        TypeSpecClassTag classSpec = src.Type as TypeSpecClassTag;
                        if (classSpec == null)
                            throw new RpaCompileException("PtrField source is not a class");

                        CliClass cls = this.Compiler.GetClosedClass(classSpec);
                        uint fieldIndex;
                        if (!cls.NameToInstanceFieldSlot.TryGetValue(tInstr.FieldName, out fieldIndex))
                            throw new RpaCompileException("PtrField field does not exist");

                        if (dest != null)
                        {
                            if (dest.ValueType != HighValueType.ManagedPtr)
                                throw new RpaCompileException("PtrField dest is not a field");
                            HighField fld = cls.InstanceFields[fieldIndex];
                            if (fld.Type != dest.Type)
                                throw new RpaCompileException("PtrField dest type does not match field type");
                        }
                    }
                    break;
                case HighInstruction.Opcodes.RefField:
                    {
                        RefFieldInstruction tInstr = (RefFieldInstruction)instr;

                        HighSsaRegister dest = tInstr.Dest;
                        HighSsaRegister src = tInstr.Src;

                        if (src.ValueType != HighValueType.ReferenceValue)
                            throw new RpaCompileException("RefField source not a field");

                        TypeSpecClassTag classSpec = src.Type as TypeSpecClassTag;
                        if (classSpec == null)
                            throw new RpaCompileException("RefField source is not a class");

                        CliClass cls = this.Compiler.GetClosedClass(classSpec);
                        uint fieldIndex;
                        if (!cls.NameToInstanceFieldSlot.TryGetValue(tInstr.FieldName, out fieldIndex))
                            throw new RpaCompileException("RefField field does not exist");

                        if (dest != null)
                        {
                            if (dest.ValueType != HighValueType.ManagedPtr)
                                throw new RpaCompileException("RefField dest is not a field");
                            HighField fld = cls.InstanceFields[fieldIndex];
                            if (fld.Type != dest.Type)
                                throw new RpaCompileException("RefField dest type does not match field type");
                        }
                    }
                    break;
                case HighInstruction.Opcodes.CallInstanceMethod:
                    {
                        CallInstanceMethodInstruction tInstr = (CallInstanceMethodInstruction)instr;
                        HighSsaRegister instance = tInstr.InstanceSrc;
                        HighSsaRegister[] parameters = tInstr.Parameters;
                        HighSsaRegister dest = tInstr.ReturnDest;

                        TypeSpecClassTag classSpec = tInstr.MethodSpec.DeclaringClass;

                        if (instance.Type != tInstr.MethodSpec.DeclaringClass)
                            throw new RpaCompileException("CallInstanceMethod target is not the same class as the method being called");

                        HighTypeDef typeDef = this.Compiler.GetTypeDef(classSpec.TypeName);

                        switch (typeDef.Semantics)
                        {
                            case TypeSemantics.Interface:
                                throw new RpaCompileException("CallInstanceMethod target is an interface");
                            case TypeSemantics.Class:
                            case TypeSemantics.Delegate:
                            case TypeSemantics.Enum:
                            case TypeSemantics.Struct:
                                break;
                            default:
                                throw new ArgumentException();
                        }

                        switch (instance.ValueType)
                        {
                            case HighValueType.ConstantString:
                            case HighValueType.ReferenceValue:
                            case HighValueType.ManagedPtr:
                                break;

                            // BoxedValues should never have methods called on them directly (use unbox first)
                            // Calls on null at this stage are illegal
                            default:
                                throw new RpaCompileException("CallInstanceMethod source type is invalid");
                        }

                        CliClass cliClass = this.Compiler.GetClosedClass(classSpec);
                        MethodSpecTag methodSpec = tInstr.MethodSpec;
                        if (methodSpec.MethodSlotType != MethodSlotType.Instance)
                            throw new RpaCompileException("CallInstanceMethod method is not an instance method");

                        uint methodSlot;
                        if (!cliClass.DeclTagToMethod.TryGetValue(methodSpec.MethodDecl, out methodSlot))
                            throw new RpaCompileException("CallInstanceMethod method wasn't found");
                        HighMethod method = cliClass.Methods[methodSlot];
                        if (method.IsStatic)
                            throw new RpaCompileException("CallInstanceMethod method is static");

                        CheckMethodCall(methodSpec, dest, parameters, method.MethodSignature);

                        MethodHandle methodHandle = this.Compiler.InstantiateMethod(new MethodSpecMethodKey(methodSpec), GenerateMethodInstantiationPath(tInstr.CodeLocation));

                        validationOnly = false;
                        newInstrs.Add(new Instructions.CallRloInstanceMethodInstruction(tInstr.CodeLocation, methodHandle, tInstr.ReturnDest, tInstr.InstanceSrc, tInstr.Parameters));
                    }
                    break;
                case HighInstruction.Opcodes.CallStaticMethod:
                    {
                        CallStaticMethodInstruction tInstr = (CallStaticMethodInstruction)instr;
                        HighSsaRegister[] parameters = tInstr.Parameters;
                        HighSsaRegister dest = tInstr.ReturnDest;

                        TypeSpecClassTag classSpec = tInstr.MethodSpec.DeclaringClass;

                        HighTypeDef typeDef = this.Compiler.GetTypeDef(classSpec.TypeName);

                        switch (typeDef.Semantics)
                        {
                            case TypeSemantics.Interface:
                                throw new RpaCompileException("CallStaticMethod target is an interface");
                            case TypeSemantics.Class:
                            case TypeSemantics.Delegate:
                            case TypeSemantics.Enum:
                            case TypeSemantics.Struct:
                                break;
                            default:
                                throw new ArgumentException();
                        }

                        CliClass cliClass = this.Compiler.GetClosedClass(classSpec);
                        MethodSpecTag methodSpec = tInstr.MethodSpec;
                        if (methodSpec.MethodSlotType != MethodSlotType.Static)
                            throw new RpaCompileException("CallStaticMethod method is not an instance method");

                        uint methodSlot;
                        if (!cliClass.DeclTagToMethod.TryGetValue(methodSpec.MethodDecl, out methodSlot))
                            throw new RpaCompileException("CallStaticMethod method wasn't found");
                        HighMethod method = cliClass.Methods[methodSlot];
                        if (!method.IsStatic)
                            throw new RpaCompileException("CallStaticMethod method is not static");

                        CheckMethodCall(methodSpec, dest, parameters, method.MethodSignature);

                        MethodHandle methodHandle = this.Compiler.InstantiateMethod(new MethodSpecMethodKey(methodSpec), GenerateMethodInstantiationPath(tInstr.CodeLocation));

                        validationOnly = false;
                        newInstrs.Add(new Instructions.CallRloStaticMethodInstruction(tInstr.CodeLocation, methodHandle, tInstr.ReturnDest, tInstr.Parameters));
                    }
                    break;
                case HighInstruction.Opcodes.CallVirtualMethod:
                    {
                        CallVirtualMethodInstruction tInstr = (CallVirtualMethodInstruction)instr;
                        HighSsaRegister instance = tInstr.InstanceSrc;
                        HighSsaRegister[] parameters = tInstr.Parameters;
                        HighSsaRegister dest = tInstr.ReturnDest;
                        MethodSpecTag methodSpec = tInstr.MethodSpec;

                        if (methodSpec.MethodSlotType != MethodSlotType.Virtual)
                            throw new RpaCompileException("CallVirtualMethod target is not virtual");

                        TypeSpecClassTag classSpec = methodSpec.DeclaringClass;

                        if (instance.Type != tInstr.MethodSpec.DeclaringClass)
                            throw new RpaCompileException("CallVirtualMethod target is not the same class as the method being called");

                        HighTypeDef typeDef = this.Compiler.GetTypeDef(classSpec.TypeName);

                        bool isInterface;
                        switch (typeDef.Semantics)
                        {
                            case TypeSemantics.Interface:
                                isInterface = true;
                                break;
                            case TypeSemantics.Class:
                            case TypeSemantics.Delegate:
                            case TypeSemantics.Enum:
                            case TypeSemantics.Struct:
                                isInterface = false;
                                break;
                            default:
                                throw new ArgumentException();
                        }

                        switch (instance.ValueType)
                        {
                            case HighValueType.ConstantString:
                            case HighValueType.ReferenceValue:
                            case HighValueType.ManagedPtr:
                                break;

                            // BoxedValues should never have methods called on them directly (use unbox first)
                            // Calls on null at this stage are illegal
                            default:
                                throw new RpaCompileException("CallVirtualMethod source type is invalid");
                        }

                        if (methodSpec.GenericParameters.Length != 0)
                            throw new RpaCompileException("Can't call an unconstrained generic virtual method");

                        CliVtableSlot vtableSlot;
                        uint vtableSlotIndex;
                        MethodSignatureTag methodSignature;

                        if (isInterface)
                        {
                            CliInterface ifc = this.Compiler.GetClosedInterface(classSpec);
                            vtableSlotIndex = ifc.CliSlotForSlotTag(methodSpec.MethodDecl);
                            methodSignature = ifc.Slots[vtableSlotIndex].Signature;
                        }
                        else
                        {
                            CliClass cliClass = this.Compiler.GetClosedClass(classSpec);
                            if (!cliClass.DeclTagToVTableSlot.TryGetValue(methodSpec.MethodDecl, out vtableSlotIndex))
                                throw new RpaCompileException("CallVirtualMethod method wasn't found");
                            methodSignature = cliClass.VTable[vtableSlotIndex].MethodSignature;
                        }

                        if (methodSpec.MethodSlotType != MethodSlotType.Virtual)
                            throw new RpaCompileException("CallVirtualMethod method is not an instance method");

                        CheckMethodCall(methodSpec, dest, parameters, methodSignature);

                        validationOnly = false;
                        if (isInterface)
                            newInstrs.Add(new Instructions.CallRloVirtualMethodInstruction(tInstr.CodeLocation, vtableSlotIndex, tInstr.ReturnDest, tInstr.InstanceSrc, tInstr.Parameters));
                        else
                            newInstrs.Add(new Instructions.CallRloInterfaceMethodInstruction(tInstr.CodeLocation, vtableSlotIndex, tInstr.ReturnDest, tInstr.InstanceSrc, tInstr.Parameters));
                    }
                    break;

                case HighInstruction.Opcodes.CallConstrainedVirtualMethod:
                    {
                        validationOnly = false;

                        CallConstrainedVirtualMethodInstruction tInstr = (CallConstrainedVirtualMethodInstruction)instr;
                        HighSsaRegister refInstance = tInstr.InstanceSrc;
                        HighSsaRegister[] parameters = tInstr.Parameters;
                        HighSsaRegister dest = tInstr.ReturnDest;
                        MethodSpecTag methodSpec = tInstr.MethodSpec;

                        if (methodSpec.MethodSlotType != MethodSlotType.Virtual)
                            throw new RpaCompileException("CallConstrainedVirtualMethod target is not virtual");

                        TypeSpecTag constraintType = tInstr.ConstraintType;

                        if (refInstance.ValueType != HighValueType.ManagedPtr)
                            throw new RpaCompileException("CallConstrainedVirtualMethod target is not a managed pointer");

                        if (refInstance.Type != constraintType)
                            throw new RpaCompileException("CallConstrainedVirtualMethod target type is different from constraint type");

                        TypeSpecTag instanceType = refInstance.Type;

                        bool isValueType;
                        bool isInterface;

                        switch (instanceType.SubType)
                        {
                            case TypeSpecTag.SubTypeCode.Array:
                                isValueType = false;
                                isInterface = false;
                                break;
                            case TypeSpecTag.SubTypeCode.Class:
                                {
                                    TypeSpecClassTag instanceClassTag = (TypeSpecClassTag)instanceType;
                                    HighTypeDef instanceTypeDef = this.Compiler.GetTypeDef(instanceClassTag.TypeName);

                                    switch (instanceTypeDef.Semantics)
                                    {
                                        case TypeSemantics.Class:
                                        case TypeSemantics.Delegate:
                                            isValueType = false;
                                            isInterface = false;
                                            break;
                                        case TypeSemantics.Interface:
                                            isValueType = false;
                                            isInterface = true;
                                            break;
                                        case TypeSemantics.Enum:
                                        case TypeSemantics.Struct:
                                            isValueType = true;
                                            isInterface = false;
                                            break;
                                        default:
                                            throw new NotSupportedException();
                                    }
                                }
                                break;
                            default:
                                throw new RpaCompileException("Invalid instance type in CallConstrainedVirtualMethod");
                        };

                        if (isValueType)
                        {
                            TypeSpecClassTag instanceClassTag = (TypeSpecClassTag)refInstance.Type;
                            CliClass cls = this.Compiler.GetClosedClass(instanceClassTag);

                            TypeSpecClassTag methodDeclaringClass = methodSpec.DeclaringClass;

                            HighTypeDef methodTypeDef = this.Compiler.GetTypeDef(methodDeclaringClass.TypeName);

                            HighMethod resolvedMethod;
                            uint vtableSlotIndex;
                            if (methodTypeDef.Semantics != TypeSemantics.Interface)
                            {
                                if (!cls.DeclTagToVTableSlot.TryGetValue(methodSpec.MethodDecl, out vtableSlotIndex))
                                    throw new RpaCompileException("CallConstrainedVirtualMethod virtual method was not found");
                            }
                            else
                            {
                                CliInterface ifc = this.Compiler.GetClosedInterface(methodDeclaringClass);
                                uint ifcSlot = ifc.CliSlotForSlotTag(methodSpec.MethodDecl);

                                vtableSlotIndex = this.Compiler.DevirtualizeInterfaceMethod(cls, methodDeclaringClass, ifcSlot);
                            }

                            CliMethodIndex methodIndex = cls.VTable[vtableSlotIndex].MethodIndex;

                            if (methodIndex == null)
                                throw new Exception("Invalid method index (???)");

                            uint depth = methodIndex.Depth;

                            if (depth == 0)
                            {
                                resolvedMethod = cls.Methods[methodIndex.Index];

                                if (resolvedMethod.MethodSignature.NumGenericParameters != 0)
                                    throw new NotImplementedException();

                                if (cls.TypeSpec != instanceType)
                                    throw new RpaCompileException("CallConstrainedVirtualMethod instance type doesn't match method (???)");

                                int numParameters = parameters.Length;
                                HighSsaRegister tempDest = null;
                                HighSsaRegister[] tempParameters = new HighSsaRegister[numParameters];

                                MethodSignatureTag signature = resolvedMethod.MethodSignature;

                                if (signature.ParamTypes.Length != numParameters)
                                    throw new RpaCompileException("CallConstrainedVirtualMethod method call parameter mismatch");

                                for (int i = 0; i < numParameters; i++)
                                {
                                    HighValueType hvt;
                                    MethodSignatureParam sigParam = signature.ParamTypes[i];
                                    switch (sigParam.TypeOfType.Value)
                                    {
                                        case MethodSignatureParamTypeOfType.Values.ByRef:
                                            hvt = HighValueType.ManagedPtr;
                                            break;
                                        case MethodSignatureParamTypeOfType.Values.Value:
                                            hvt = this.Compiler.TypeIsValueType(sigParam.Type) ? HighValueType.ValueValue : HighValueType.ReferenceValue;
                                            break;
                                        default:
                                            throw new NotImplementedException();
                                    }

                                    if (hvt == HighValueType.ReferenceValue)
                                    {
                                        HighSsaRegister tempParam = new HighSsaRegister(hvt, sigParam.Type, null);
                                        EmitPassiveRefConversion(tInstr.CodeLocation, tempParam, parameters[i], newInstrs);

                                        tempParameters[i] = tempParam;
                                    }
                                    else
                                        tempParameters[i] = parameters[i];
                                }

                                HighSsaRegister returnDest = tInstr.ReturnDest;
                                HighSsaRegister tempReturn = returnDest;

                                bool needReturnConversion = false;
                                if (signature.RetType is TypeSpecVoidTag)
                                {
                                    if (returnDest != null)
                                        throw new RpaCompileException("Return type is not void");
                                }
                                else if (returnDest != null)
                                {
                                    needReturnConversion = !this.Compiler.TypeIsValueType(signature.RetType);
                                    if (needReturnConversion)
                                        tempReturn = new HighSsaRegister(HighValueType.ReferenceValue, signature.RetType, null);
                                }

                                MethodSpecTag generatedMethodSpec = new MethodSpecTag(MethodSlotType.Instance, methodSpec.GenericParameters, cls.TypeSpec, resolvedMethod.MethodDeclTag);
                                generatedMethodSpec = this.Compiler.TagRepository.InternMethodSpec(generatedMethodSpec);

                                MethodHandle methodHandle = this.Compiler.InstantiateMethod(new MethodSpecMethodKey(generatedMethodSpec), GenerateMethodInstantiationPath(tInstr.CodeLocation));

                                CheckMethodCall(generatedMethodSpec, tempReturn, tempParameters, resolvedMethod.MethodSignature);

                                newInstrs.Add(new Instructions.CallRloInstanceMethodInstruction(tInstr.CodeLocation, methodHandle, tempReturn, refInstance, tempParameters));

                                if (needReturnConversion)
                                    EmitPassiveRefConversion(tInstr.CodeLocation, returnDest, tempReturn, newInstrs);
                            }
                            else
                            {
                                CliClass resolvedClass = cls;
                                while (depth > 0)
                                {
                                    resolvedClass = this.Compiler.GetClosedClass(resolvedClass.ParentClassSpec);
                                    depth--;
                                }

                                resolvedMethod = resolvedClass.Methods[methodIndex.Index];

                                // Method is on the parent of a value type, so it must be boxed
                                HighSsaRegister boxed = new HighSsaRegister(HighValueType.BoxedValue, instanceType, null);
                                newInstrs.Add(new Clarity.Rpa.Instructions.BoxInstruction(tInstr.CodeLocation, boxed, refInstance));

                                HighSsaRegister newInstanceSrc = new HighSsaRegister(HighValueType.ReferenceValue, resolvedClass.TypeSpec, null);
                                newInstrs.Add(new Instructions.ObjectToObjectInstruction(tInstr.CodeLocation, newInstanceSrc, boxed));

                                MethodSpecTag generatedMethodSpec = new MethodSpecTag(MethodSlotType.Instance, methodSpec.GenericParameters, resolvedClass.TypeSpec, resolvedMethod.MethodDeclTag);
                                generatedMethodSpec = this.Compiler.TagRepository.InternMethodSpec(generatedMethodSpec);

                                MethodHandle methodHandle = this.Compiler.InstantiateMethod(new MethodSpecMethodKey(generatedMethodSpec), GenerateMethodInstantiationPath(tInstr.CodeLocation));

                                CheckMethodCall(generatedMethodSpec, dest, parameters, resolvedMethod.MethodSignature);

                                newInstrs.Add(new Instructions.CallRloInstanceMethodInstruction(tInstr.CodeLocation, methodHandle, dest, newInstanceSrc, parameters));
                            }
                        }
                        else
                        {
                            HighSsaRegister loadedInstance = new HighSsaRegister(HighValueType.ReferenceValue, refInstance.Type, null);
                            newInstrs.Add(new LoadPtrInstruction(tInstr.CodeLocation, loadedInstance, refInstance));

                            if (methodSpec.GenericParameters.Length == 0)
                            {
                                HighSsaRegister instance = new HighSsaRegister(HighValueType.ReferenceValue, constraintType, null);
                                EmitPassiveRefConversion(tInstr.CodeLocation, instance, loadedInstance, newInstrs);

                                if (isInterface)
                                {
                                    CliInterface ifc = this.Compiler.GetClosedInterface((TypeSpecClassTag)constraintType);
                                    uint vtableSlotIndex = ifc.CliSlotForSlotTag(methodSpec.MethodDecl);
                                    MethodSignatureTag methodSignature = ifc.Slots[vtableSlotIndex].Signature;

                                    CheckMethodCall(methodSpec, dest, parameters, methodSignature);

                                    newInstrs.Add(new Instructions.CallRloInterfaceMethodInstruction(tInstr.CodeLocation, vtableSlotIndex, dest, instance, parameters));
                                }
                                else
                                {
                                    if (constraintType is TypeSpecClassTag || constraintType is TypeSpecArrayTag)
                                    {
                                        TypeSpecClassTag methodInstanceClass = methodSpec.DeclaringClass;
                                        if (this.Compiler.TypeIsValueType(methodInstanceClass))
                                            throw new RpaCompileException("CallConstrainedVirtualMethod method spec is from a value type");

                                        HighSsaRegister convertedInstance = new HighSsaRegister(HighValueType.ReferenceValue, methodInstanceClass, null);
                                        EmitPassiveRefConversion(tInstr.CodeLocation, convertedInstance, loadedInstance, newInstrs);

                                        if (this.Compiler.TypeIsInterface(methodInstanceClass))
                                        {
                                            CliInterface ifcClass = this.Compiler.GetClosedInterface(methodInstanceClass);
                                            uint vtableSlotIndex;
                                            vtableSlotIndex = ifcClass.CliSlotForSlotTag(methodSpec.MethodDecl);
                                            MethodSignatureTag methodSignature = ifcClass.Slots[vtableSlotIndex].Signature;

                                            CheckMethodCall(methodSpec, dest, parameters, methodSignature);

                                            newInstrs.Add(new Instructions.CallRloInterfaceMethodInstruction(tInstr.CodeLocation, vtableSlotIndex, dest, convertedInstance, parameters));
                                        }
                                        else
                                        {
                                            CliClass cliClass = this.Compiler.GetClosedClass(methodInstanceClass);
                                            uint vtableSlotIndex;
                                            if (!cliClass.DeclTagToVTableSlot.TryGetValue(methodSpec.MethodDecl, out vtableSlotIndex))
                                                throw new RpaCompileException("CallConstrainedVirtualMethod method wasn't found");
                                            MethodSignatureTag methodSignature = cliClass.VTable[vtableSlotIndex].MethodSignature;

                                            CheckMethodCall(methodSpec, dest, parameters, methodSignature);

                                            newInstrs.Add(new Instructions.CallRloVirtualMethodInstruction(tInstr.CodeLocation, vtableSlotIndex, dest, convertedInstance, parameters));
                                        }
                                    }
                                    else
                                        throw new RpaCompileException("Unexpected constraint type");
                                }
                            }
                            else
                            {
                                // Constrained generic call on a reference value
                                TypeSpecClassTag declaringClass = methodSpec.DeclaringClass;
                                HighTypeDef typeDef = this.Compiler.GetTypeDef(declaringClass.TypeName);

                                TypeSpecClassTag instanceClassTag = instanceType as TypeSpecClassTag;
                                if (instanceClassTag == null)
                                    throw new RpaCompileException("Constrained generic call site a non-class");

                                HighTypeDef instanceTypeDef = this.Compiler.GetTypeDef(instanceClassTag.TypeName);
                                if (instanceTypeDef.Semantics != TypeSemantics.Class)
                                {
                                    MethodInstantiationPath path = GenerateMethodInstantiationPath(tInstr.CodeLocation);
                                    throw new RpaCompileException("Constrained generic call on a non-class: " + path.ToString());
                                }

                                if (!instanceTypeDef.IsSealed)
                                {
                                    MethodInstantiationPath path = GenerateMethodInstantiationPath(tInstr.CodeLocation);
                                    throw new RpaCompileException("Constrained generic call on a class that isn't sealed: " + path.ToString());
                                }

                                CliClass instanceClass = this.Compiler.GetClosedClass(instanceClassTag);
                                uint vtableSlotIndex;

                                switch (typeDef.Semantics)
                                {
                                    case TypeSemantics.Interface:
                                        {
                                            CliInterface ifc = this.Compiler.GetClosedInterface(declaringClass);
                                            uint ifcSlot = ifc.CliSlotForSlotTag(methodSpec.MethodDecl);

                                            vtableSlotIndex = this.Compiler.DevirtualizeInterfaceMethod(instanceClass, declaringClass, ifcSlot);
                                        }
                                        break;
                                    case TypeSemantics.Class:
                                        {
                                            CliClass cls = this.Compiler.GetClosedClass(declaringClass);
                                            if (!cls.DeclTagToVTableSlot.TryGetValue(methodSpec.MethodDecl, out vtableSlotIndex))
                                                throw new RpaCompileException("CallConstrainedVirtualMethod vtable slot had no match");
                                        }
                                        break;
                                    default:
                                        throw new RpaCompileException("Unexpected semantics on generic call on reference type");
                                }

                                CliVtableSlot vtableSlot = instanceClass.VTable[vtableSlotIndex];
                                CliMethodIndex methodIndex = vtableSlot.MethodIndex;

                                uint depth = methodIndex.Depth;
                                CliClass instanceConversionTargetClass = instanceClass;
                                while (depth > 0)
                                {
                                    instanceConversionTargetClass = instanceConversionTargetClass.ParentClass;
                                    depth--;
                                }

                                HighMethod resolvedMethod = instanceConversionTargetClass.Methods[methodIndex.Index];

                                if (resolvedMethod.MethodSignature.NumGenericParameters != methodSpec.GenericParameters.Length)
                                    throw new RpaCompileException("Constrained generic call parameter type mismatch");

                                // Convert instance
                                HighSsaRegister convertedInstance = new HighSsaRegister(HighValueType.ReferenceValue, instanceConversionTargetClass.TypeSpec, null);
                                EmitPassiveRefConversion(tInstr.CodeLocation, convertedInstance, loadedInstance, newInstrs);

                                // Convert parameters
                                MethodSignatureTag methodSignature = resolvedMethod.MethodSignature.Instantiate(this.Compiler.TagRepository, new TypeSpecTag[0], methodSpec.GenericParameters);

                                int numParameters = methodSignature.ParamTypes.Length;
                                if (numParameters != parameters.Length)
                                    throw new RpaCompileException("Constrained generic call parameter count mismatch");

                                List<HighSsaRegister> convertedParameters = new List<HighSsaRegister>();
                                for (int i = 0; i < numParameters; i++)
                                {
                                    MethodSignatureParam param = methodSignature.ParamTypes[i];
                                    switch (param.TypeOfType.Value)
                                    {
                                        case MethodSignatureParamTypeOfType.Values.ByRef:
                                            convertedParameters.Add(parameters[i]);
                                            break;
                                        case MethodSignatureParamTypeOfType.Values.Value:
                                            {
                                                if (this.Compiler.TypeIsValueType(param.Type))
                                                    convertedParameters.Add(parameters[i]);
                                                else
                                                {
                                                    HighSsaRegister convertedParameter = new HighSsaRegister(HighValueType.ReferenceValue, param.Type, null);
                                                    EmitPassiveRefConversion(tInstr.CodeLocation, convertedParameter, parameters[i], newInstrs);
                                                    convertedParameters.Add(convertedParameter);
                                                }
                                            }
                                            break;
                                        default:
                                            throw new NotImplementedException();
                                    }
                                }

                                parameters = convertedParameters.ToArray();

                                HighSsaRegister unconvertedReturnDest = tInstr.ReturnDest;
                                HighSsaRegister convertedReturnDest = null;
                                if (unconvertedReturnDest != null)
                                {
                                    if (this.Compiler.TypeIsValueType(methodSignature.RetType))
                                        convertedReturnDest = unconvertedReturnDest;
                                    else
                                    {
                                        unconvertedReturnDest = new HighSsaRegister(HighValueType.ReferenceValue, methodSignature.RetType, null);
                                        convertedReturnDest = tInstr.ReturnDest;
                                    }
                                }

                                MethodSpecTag generatedMethodSpec = new MethodSpecTag(MethodSlotType.Instance, methodSpec.GenericParameters, instanceConversionTargetClass.TypeSpec, resolvedMethod.MethodDeclTag);
                                generatedMethodSpec = this.Compiler.TagRepository.InternMethodSpec(generatedMethodSpec);

                                MethodHandle methodHandle = this.Compiler.InstantiateMethod(new MethodSpecMethodKey(generatedMethodSpec), GenerateMethodInstantiationPath(tInstr.CodeLocation));

                                CheckMethodCall(generatedMethodSpec, unconvertedReturnDest, parameters, resolvedMethod.MethodSignature);

                                newInstrs.Add(new Instructions.CallRloInstanceMethodInstruction(tInstr.CodeLocation, methodHandle, unconvertedReturnDest, convertedInstance, parameters));

                                if (unconvertedReturnDest != convertedReturnDest)
                                    EmitPassiveRefConversion(tInstr.CodeLocation, convertedReturnDest, unconvertedReturnDest, newInstrs);
                            }
                        }
                    }
                    break;

                case HighInstruction.Opcodes.CompareNumbers:
                    {
                        CompareNumbersInstruction tInstr = (CompareNumbersInstruction)instr;

                        HighSsaRegister dest = tInstr.Dest;
                        if (dest == null)
                            throw new RpaCompileException("CompareNumbers has no destination");

                        if (dest.ValueType != HighValueType.ValueValue || dest.Type != m_boolType)
                            throw new RpaCompileException("CompareNumbers has an invalid destination type");

                        TypeSpecClassTag expectedType = ExpectedClassForArithType(tInstr.NumberType);

                        switch (tInstr.Left.ValueType)
                        {
                            case HighValueType.ConstantValue:
                            case HighValueType.ValueValue:
                                break;
                            default:
                                throw new RpaCompileException("CompareNumbers has an invalid operand");
                        }

                        switch (tInstr.Right.ValueType)
                        {
                            case HighValueType.ConstantValue:
                            case HighValueType.ValueValue:
                                break;
                            default:
                                throw new RpaCompileException("CompareNumbers has an invalid operand");
                        }

                        if (tInstr.Left.Type != expectedType || tInstr.Right.Type != expectedType)
                            throw new RpaCompileException("CompareNumbers operands are the wrong type");
                    }
                    break;
                case HighInstruction.Opcodes.GetArrayLength:
                    {
                        GetArrayLengthInstruction tInstr = (GetArrayLengthInstruction)instr;

                        HighSsaRegister dest = tInstr.Dest;
                        HighSsaRegister src = tInstr.Src;
                        if (dest != null)
                        {
                            if (dest.ValueType != HighValueType.ValueValue || dest.Type != m_nativeUIntType)
                                throw new RpaCompileException("GetArrayLength invalid destination type");
                        }

                        switch (src.ValueType)
                        {
                            case HighValueType.Null:
                                break;
                            case HighValueType.ReferenceValue:
                                {
                                    TypeSpecArrayTag srcType = src.Type as TypeSpecArrayTag;
                                    if (srcType == null)
                                        throw new RpaCompileException("GetArrayLength operand isn't an array");
                                    if (srcType.Rank != 1)
                                        throw new RpaCompileException("GetArrayLength operand isn't 1-rank");
                                }
                                break;
                            default:
                                throw new RpaCompileException("GetArrayLength operand isn't a reference");
                        }
                    }
                    break;
                case HighInstruction.Opcodes.ReturnValue:
                    {
                        ReturnValueInstruction tInstr = (ReturnValueInstruction)instr;

                        HighSsaRegister value = tInstr.Value;

                        TypeSpecTag retType = this.MethodBody.ReturnType;
                        if (retType is TypeSpecVoidTag)
                            throw new RpaCompileException("ReturnValue in a function that has no return type");

                        bool isValueType = this.Compiler.TypeIsValueType(retType);

                        bool expectValueType;
                        switch (tInstr.Value.ValueType)
                        {
                            case HighValueType.Null:
                            case HighValueType.ConstantString:
                            case HighValueType.ReferenceValue:
                                expectValueType = false;
                                break;
                            case HighValueType.ConstantValue:
                            case HighValueType.ValueValue:
                                expectValueType = true;
                                break;
                            default:
                                throw new RpaCompileException("ReturnValue invalid return value type");
                        }

                        if (expectValueType != isValueType)
                            throw new RpaCompileException("Incompatible return value type");

                        if (tInstr.Value.ValueType != HighValueType.Null && tInstr.Value.Type != retType)
                            throw new RpaCompileException("Incompatible return value type");
                    }
                    break;
                case HighInstruction.Opcodes.GetLocalPtr:
                    {
                        GetLocalPtrInstruction tInstr = (GetLocalPtrInstruction)instr;

                        HighLocal local = tInstr.Local;
                        if (local.TypeOfType != HighLocal.ETypeOfType.Value)
                            throw new RpaCompileException("GetLocalPtr local isn't a value");

                        HighSsaRegister dest = tInstr.Dest;
                        if (dest == null)
                            throw new RpaCompileException("GetLocalPtr has no destination");

                        if (dest.ValueType != HighValueType.ManagedPtr)
                            throw new RpaCompileException("GetLocalPtr destination isn't a managed pointer");

                        if (dest.Type != local.Type)
                            throw new RpaCompileException("GetLocalPtr destination isn't the same type as the local");
                    }
                    break;
                case HighInstruction.Opcodes.UnaryArith:
                    {
                        UnaryArithInstruction tInstr = (UnaryArithInstruction)instr;

                        if (tInstr.Dest == null)
                            throw new RpaCompileException("UnaryArith has no destination");

                        TypeSpecClassTag expectedClass = ExpectedClassForArithType(tInstr.ArithType);

                        switch (tInstr.Src.ValueType)
                        {
                            case HighValueType.ConstantValue:
                            case HighValueType.ValueValue:
                                break;
                            default:
                                throw new RpaCompileException("UnaryArith source type is invalid");
                        }

                        if (tInstr.Dest.ValueType != HighValueType.ValueValue)
                            throw new RpaCompileException("UnaryArith destination type is invalid");

                        if (tInstr.Src.Type != expectedClass || tInstr.Dest.Type != expectedClass)
                            throw new RpaCompileException("UnaryArith type doesn't match");
                    }
                    break;
                case HighInstruction.Opcodes.StoreLocal:
                    {
                        StoreLocalInstruction tInstr = (StoreLocalInstruction)instr;

                        HighLocal local = tInstr.Local;
                        HighSsaRegister src = tInstr.Src;
                        switch (local.TypeOfType)
                        {
                            case HighLocal.ETypeOfType.ByRef:
                                if (src.ValueType != HighValueType.ManagedPtr)
                                    throw new RpaCompileException("StoreLocal type mismatch");
                                if (src.Type != local.Type)
                                    throw new RpaCompileException("StoreLocal type mismatch");
                                break;
                            case HighLocal.ETypeOfType.Value:
                                {
                                    bool isValueType = this.Compiler.TypeIsValueType(local.Type);

                                    if (isValueType)
                                    {
                                        switch (src.ValueType)
                                        {
                                            case HighValueType.ConstantValue:
                                            case HighValueType.ValueValue:
                                                if (src.Type != local.Type)
                                                    throw new RpaCompileException("StoreLocal type mismatch");
                                                break;
                                            default:
                                                throw new RpaCompileException("StoreLocal source type is invalid");
                                        }
                                    }
                                    else
                                    {
                                        switch (src.ValueType)
                                        {
                                            case HighValueType.ConstantString:
                                            case HighValueType.ReferenceValue:
                                                if (src.Type != local.Type)
                                                    throw new RpaCompileException("StoreLocal type mismatch");
                                                break;
                                            case HighValueType.Null:
                                                break;
                                            default:
                                                throw new RpaCompileException("StoreLocal source type is invalid");
                                        }
                                    }
                                }
                                break;
                            case HighLocal.ETypeOfType.TypedByRef:
                                throw new NotImplementedException();
                            default:
                                throw new ArgumentException();
                        }
                    }
                    break;
                case HighInstruction.Opcodes.UnboxPtr:
                    {
                        UnboxPtrInstruction tInstr = (UnboxPtrInstruction)instr;

                        if (tInstr.Dest == null)
                            throw new RpaCompileException("UnboxPtr has no destination");

                        if (tInstr.Dest.ValueType != HighValueType.ManagedPtr)
                            throw new RpaCompileException("UnboxPtr destination isn't a managed pointer");

                        if (!this.Compiler.TypeIsValueType(tInstr.Dest.Type))
                            throw new RpaCompileException("UnboxPtr type isn't a value type");

                        switch (tInstr.Src.ValueType)
                        {
                            case HighValueType.BoxedValue:
                            case HighValueType.ConstantString:  // Grumble grumble
                            case HighValueType.Null:
                            case HighValueType.ReferenceValue:
                                break;
                            default:
                                throw new RpaCompileException("UnboxPtr source isn't a reference type");
                        }

                        if (tInstr.Src.Type != m_objectType)
                            throw new RpaCompileException("UnboxPtr source isn't System.Object");
                    }
                    break;
                case HighInstruction.Opcodes.ZeroFillPtr:
                    {
                        ZeroFillPtrInstruction tInstr = (ZeroFillPtrInstruction)instr;
                        if (tInstr.Target.ValueType != HighValueType.ManagedPtr)
                            throw new RpaCompileException("ZeroFillPtr target isn't a managed pointer");
                    }
                    break;
                case HighInstruction.Opcodes.UnboxValue:
                    {
                        UnboxValueInstruction tInstr = (UnboxValueInstruction)instr;

                        if (tInstr.Dest == null)
                            throw new RpaCompileException("UnboxValue has no destination");

                        switch (tInstr.Src.ValueType)
                        {
                            case HighValueType.BoxedValue:
                            case HighValueType.ConstantString:  // Grumble grumble
                            case HighValueType.Null:
                            case HighValueType.ReferenceValue:
                                break;
                            default:
                                throw new RpaCompileException("UnboxValue source isn't a reference type");
                        }

                        if (tInstr.Src.Type != m_objectType)
                            throw new RpaCompileException("UnboxValue source isn't System.Object");

                        validationOnly = true;

                        switch (tInstr.Dest.ValueType)
                        {
                            case HighValueType.ValueValue:
                                {
                                    HighSsaRegister ptr = new HighSsaRegister(HighValueType.ManagedPtr, tInstr.Dest.Type, null);
                                    newInstrs.Add(new UnboxPtrInstruction(tInstr.CodeLocation, ptr, tInstr.Src));
                                    newInstrs.Add(new LoadPtrInstruction(tInstr.CodeLocation, tInstr.Dest, ptr));
                                }
                                break;
                            case HighValueType.ReferenceValue:
                                newInstrs.Add(new ForceDynamicCastInstruction(tInstr.CodeLocation, tInstr.Dest, tInstr.Src, tInstr.Dest.Type));
                                break;
                            default:
                                throw new RpaCompileException("UnboxValue destination is invalid");
                        }
                    }
                    break;
                case HighInstruction.Opcodes.Switch:
                    {
                        SwitchInstruction tInstr = (SwitchInstruction)instr;

                        switch (tInstr.Value.ValueType)
                        {
                            case HighValueType.ConstantValue:
                            case HighValueType.ValueValue:
                                break;
                            default:
                                throw new RpaCompileException("Switch source is invalid");
                        }

                        if (tInstr.Value.Type != m_uint32Type)
                            throw new RpaCompileException("Switch source isn't a UInt32");
                    }
                    break;
                case HighInstruction.Opcodes.Throw:
                    {
                        ThrowInstruction tInstr = (ThrowInstruction)instr;

                        switch (tInstr.Exception.ValueType)
                        {
                            case HighValueType.BoxedValue:
                            case HighValueType.ConstantString:
                            case HighValueType.Null:
                            case HighValueType.ReferenceValue:
                                break;
                            default:
                                throw new RpaCompileException("Throw instruction doesn't throw an object");
                        }
                    }
                    break;
                case HighInstruction.Opcodes.StorePtr:
                    {
                        StorePtrInstruction tInstr = (StorePtrInstruction)instr;

                        if (tInstr.Ptr.ValueType != HighValueType.ManagedPtr)
                            throw new RpaCompileException("StorePtr destination isn't a managed pointer");

                        bool isValueType = this.Compiler.TypeIsValueType(tInstr.Ptr.Type);

                        switch (tInstr.Value.ValueType)
                        {
                            case HighValueType.ConstantString:
                            case HighValueType.ConstantValue:
                            case HighValueType.ReferenceValue:
                            case HighValueType.ValueValue:
                                if (tInstr.Value.Type != tInstr.Ptr.Type)
                                    throw new RpaCompileException("StorePtr type mismatch");
                                break;
                            case HighValueType.Null:
                                if (isValueType)
                                    throw new RpaCompileException("StorePtr type mismatch");
                                break;
                            default:
                                throw new RpaCompileException("StorePtr source is invalid");
                        }
                    }
                    break;
                case HighInstruction.Opcodes.GetFieldInfo:
                    {
                        GetFieldInfoInstruction tInstr = (GetFieldInfoInstruction)instr;

                        TypeSpecClassTag typeClassSpec = tInstr.Type as TypeSpecClassTag;
                        if (typeClassSpec == null)
                            throw new RpaCompileException("GetFieldInfo type isn't a class");

                        if (!this.Compiler.HaveCliOpenClass(typeClassSpec.TypeName))
                            throw new RpaCompileException("GetFieldInfo type name isn't a class");

                        CliClass cls = this.Compiler.GetClosedClass(typeClassSpec);

                        if (tInstr.Dest == null)
                            throw new RpaCompileException("GetFieldInfo has no destination");

                        if (tInstr.Dest.ValueType != HighValueType.ValueValue && tInstr.Type != m_runtimeFieldHandleType)
                            throw new RpaCompileException("GetFieldInfo destination is invalid");

                        IDictionary<string, uint> fieldDict = tInstr.IsStatic ? cls.NameToStaticFieldSlot : cls.NameToInstanceFieldSlot;

                        uint fieldIndex;
                        if (!fieldDict.TryGetValue(tInstr.FieldName, out fieldIndex))
                            throw new RpaCompileException("GetFieldInfo field not found");

                        validationOnly = false;
                        newInstrs.Add(new Instructions.GetRloFieldInfoInstruction(tInstr.CodeLocation, tInstr.Dest, tInstr.Type, fieldIndex, tInstr.IsStatic));
                    }
                    break;
                case HighInstruction.Opcodes.LoadValueField:
                    {
                        LoadValueFieldInstruction tInstr = (LoadValueFieldInstruction)instr;
                        validationOnly = false;

                        if (tInstr.Src.ValueType != HighValueType.ValueValue)
                            throw new RpaCompileException("LoadValueField source is invalid");

                        TypeSpecClassTag typeClassSpec = tInstr.Src.Type as TypeSpecClassTag;
                        if (typeClassSpec == null)
                            throw new RpaCompileException("LoadValueField type isn't a class");

                        if (!this.Compiler.HaveCliOpenClass(typeClassSpec.TypeName))
                            throw new RpaCompileException("LoadValueField type name isn't a class");

                        CliClass cls = this.Compiler.GetClosedClass(typeClassSpec);

                        uint fieldIndex;
                        if (!cls.NameToInstanceFieldSlot.TryGetValue(tInstr.FieldName, out fieldIndex))
                            throw new RpaCompileException("LoadValueField field not found");

                        HighField fld = cls.InstanceFields[fieldIndex];

                        switch (tInstr.Dest.ValueType)
                        {
                            case HighValueType.ValueValue:
                            case HighValueType.ReferenceValue:
                                break;
                            default:
                                throw new RpaCompileException("LoadValueField destination isn't a value");
                        }

                        if (tInstr.Dest.Type != fld.Type)
                            throw new RpaCompileException("LoadValueField destination type mismatch");

                        validationOnly = false;
                        newInstrs.Add(new Instructions.LoadValueRloFieldInstruction(tInstr.CodeLocation, tInstr.Dest, tInstr.Src, fieldIndex));
                    }
                    break;
                case HighInstruction.Opcodes.BindStaticDelegate:
                    {
                        BindStaticDelegateInstruction tInstr = (BindStaticDelegateInstruction)instr;

                        if (tInstr.Dest == null)
                            throw new RpaCompileException("BindStaticDelegate has no destination");

                        if (tInstr.Dest.ValueType != HighValueType.ReferenceValue)
                            throw new RpaCompileException("BindStaticDelegate target isn't a reference");

                        TypeSpecClassTag destClass = tInstr.Dest.Type as TypeSpecClassTag;
                        if (destClass == null)
                            throw new RpaCompileException("BindStaticDelegate destination isn't a class");

                        HighTypeDef typeDef = this.Compiler.GetTypeDef(destClass.TypeName);
                        if (typeDef.Semantics != TypeSemantics.Delegate)
                            throw new RpaCompileException("BindStaticDelegate destination isn't a delegate");

                        if (tInstr.MethodSpec.MethodSlotType != MethodSlotType.Static)
                            throw new RpaCompileException("BindStaticDelegate method spec isn't static");

                        TypeSpecDelegateTag dgTag = new TypeSpecDelegateTag(destClass, tInstr.MethodSpec);
                        dgTag = (TypeSpecDelegateTag)this.Compiler.TagRepository.InternTypeSpec(dgTag);

                        validationOnly = true;
                        HighSsaRegister sdInstance = new HighSsaRegister(HighValueType.ReferenceValue, dgTag, null);

                        newInstrs.Add(new AllocObjInstruction(tInstr.CodeLocation, sdInstance, dgTag));
                        newInstrs.Add(new Instructions.ObjectToObjectInstruction(tInstr.CodeLocation, tInstr.Dest, sdInstance));

                        this.Compiler.GetRloVTable(dgTag, GenerateMethodInstantiationPath(tInstr.CodeLocation));
                    }
                    break;
                case HighInstruction.Opcodes.BindInstanceDelegate:
                    {
                        BindInstanceDelegateInstruction tInstr = (BindInstanceDelegateInstruction)instr;

                        if (tInstr.Dest == null)
                            throw new RpaCompileException("BindInstanceDelegate has no destination");

                        if (tInstr.Dest.ValueType != HighValueType.ReferenceValue)
                            throw new RpaCompileException("BindInstanceDelegate target isn't a reference");

                        TypeSpecClassTag destClass = tInstr.Dest.Type as TypeSpecClassTag;
                        if (destClass == null)
                            throw new RpaCompileException("BindInstanceDelegate destination isn't a class");

                        HighTypeDef typeDef = this.Compiler.GetTypeDef(destClass.TypeName);
                        if (typeDef.Semantics != TypeSemantics.Delegate)
                            throw new RpaCompileException("BindInstanceDelegate destination isn't a delegate");

                        if (tInstr.MethodSpec.MethodSlotType != MethodSlotType.Instance)
                            throw new RpaCompileException("BindInstanceDelegate method spec isn't an instance method");

                        switch (tInstr.Object.ValueType)
                        {
                            case HighValueType.BoxedValue:
                            case HighValueType.ConstantString:
                            case HighValueType.Null:
                            case HighValueType.ReferenceValue:
                                break;
                            default:
                                throw new RpaCompileException("BindInstanceDelegate object is invalid");
                        }

                        if (tInstr.MethodSpec.DeclaringClass != tInstr.Object.Type)
                            throw new RpaCompileException("BindInstanceDelegate method spec type doesn't match source");

                        if (tInstr.MethodSpec.MethodSlotType != MethodSlotType.Instance)
                            throw new RpaCompileException("BindInstanceDelegate method spec isn't an instance method");

                        TypeSpecDelegateTag dgTag = new TypeSpecDelegateTag(destClass, tInstr.MethodSpec);
                        dgTag = (TypeSpecDelegateTag)this.Compiler.TagRepository.InternTypeSpec(dgTag);

                        validationOnly = true;
                        HighSsaRegister dgInstance = new HighSsaRegister(HighValueType.ReferenceValue, dgTag, null);

                        newInstrs.Add(new Instructions.AllocInstanceDelegateInstruction(tInstr.CodeLocation, dgTag, dgInstance, tInstr.Object));
                        newInstrs.Add(new Instructions.ObjectToObjectInstruction(tInstr.CodeLocation, tInstr.Dest, dgInstance));

                        this.Compiler.GetRloVTable(dgTag, GenerateMethodInstantiationPath(tInstr.CodeLocation));
                    }
                    break;
                case HighInstruction.Opcodes.BindVirtualDelegate:
                    {
                        BindVirtualDelegateInstruction tInstr = (BindVirtualDelegateInstruction)instr;

                        if (tInstr.Dest == null)
                            throw new RpaCompileException("BindVirtualDelegate has no destination");

                        if (tInstr.Dest.ValueType != HighValueType.ReferenceValue)
                            throw new RpaCompileException("BindVirtualDelegate target isn't a reference");

                        TypeSpecClassTag destClass = tInstr.Dest.Type as TypeSpecClassTag;
                        if (destClass == null)
                            throw new RpaCompileException("BindVirtualDelegate destination isn't a class");

                        HighTypeDef typeDef = this.Compiler.GetTypeDef(destClass.TypeName);
                        if (typeDef.Semantics != TypeSemantics.Delegate)
                            throw new RpaCompileException("BindVirtualDelegate destination isn't a delegate");

                        if (tInstr.MethodSpec.MethodSlotType != MethodSlotType.Virtual)
                            throw new RpaCompileException("BindVirtualDelegate method spec isn't an instance method");

                        switch (tInstr.Object.ValueType)
                        {
                            case HighValueType.BoxedValue:
                            case HighValueType.ConstantString:
                            case HighValueType.Null:
                            case HighValueType.ReferenceValue:
                                break;
                            default:
                                throw new RpaCompileException("BindInstanceDelegate object is invalid");
                        }

                        if (tInstr.MethodSpec.DeclaringClass != tInstr.Object.Type)
                            throw new RpaCompileException("BindInstanceDelegate method spec type doesn't match source");

                        if (tInstr.MethodSpec.MethodSlotType != MethodSlotType.Virtual)
                            throw new RpaCompileException("BindInstanceDelegate method spec isn't a virtual method");

                        TypeSpecDelegateTag dgTag = new TypeSpecDelegateTag(destClass, tInstr.MethodSpec);
                        dgTag = (TypeSpecDelegateTag)this.Compiler.TagRepository.InternTypeSpec(dgTag);

                        validationOnly = true;
                        HighSsaRegister dgInstance = new HighSsaRegister(HighValueType.ReferenceValue, dgTag, null);

                        newInstrs.Add(new Instructions.AllocInstanceDelegateInstruction(tInstr.CodeLocation, dgTag, dgInstance, tInstr.Object));
                        newInstrs.Add(new Instructions.ObjectToObjectInstruction(tInstr.CodeLocation, tInstr.Dest, dgInstance));

                        this.Compiler.GetRloVTable(dgTag, GenerateMethodInstantiationPath(tInstr.CodeLocation));
                    }
                    break;
                case HighInstruction.Opcodes.Catch:
                    {
                        CatchInstruction tInstr = (CatchInstruction)instr;
                        if (tInstr.Dest == null)
                            throw new RpaCompileException("Catch instruction has no destination");

                        if (tInstr.Dest.ValueType != HighValueType.ReferenceValue)
                            throw new RpaCompileException("Catch instruction destination is invalid");
                    }
                    break;
                case HighInstruction.Opcodes.NumberConvert:
                    {
                        validationOnly = false;

                        NumberConvertInstruction tInstr = (NumberConvertInstruction)instr;

                        if (tInstr.Dest == null)
                            throw new RpaCompileException("NumberConvert instruction destination is invalid");
                        if (tInstr.Dest.ValueType != HighValueType.ValueValue)
                            break;
                        switch (tInstr.Src.ValueType)
                        {
                            case HighValueType.ConstantValue:
                            case HighValueType.ValueValue:
                                break;
                            default:
                                throw new RpaCompileException("NumberConvert source is invalid");
                        }

                        EmitNumberConversion(tInstr.CodeLocation, tInstr.Dest, tInstr.Src, tInstr.CheckOverflow, newInstrs);
                    }
                    break;
                case HighInstruction.Opcodes.PassiveConvert:
                    {
                        PassiveConvertInstruction tInstr = (PassiveConvertInstruction)instr;

                        validationOnly = false;

                        if (tInstr.Dest == null)
                            throw new RpaCompileException("PassiveConvert has no destination");

                        bool srcIsValue;
                        switch (tInstr.Src.ValueType)
                        {
                            case HighValueType.ConstantValue:
                            case HighValueType.ValueValue:
                                srcIsValue = true;
                                break;
                            case HighValueType.BoxedValue:
                            case HighValueType.ConstantString:
                            case HighValueType.Null:
                            case HighValueType.ReferenceValue:
                                srcIsValue = false;
                                break;
                            default:
                                throw new RpaCompileException("PassiveConvert invalid source type");
                        }

                        bool destIsValue;
                        switch (tInstr.Dest.ValueType)
                        {
                            case HighValueType.BoxedValue:
                            case HighValueType.ReferenceValue:
                                destIsValue = false;
                                break;
                            case HighValueType.ValueValue:
                                destIsValue = true;
                                break;
                            default:
                                throw new RpaCompileException("PassiveConvert invalid dest type");
                        }

                        if (destIsValue != srcIsValue)
                            throw new RpaCompileException("PassiveConvert ref/value mismatch");

                        if (srcIsValue)
                            EmitPassiveValueConversion(tInstr.CodeLocation, tInstr.Dest, tInstr.Src, newInstrs);
                        else
                            EmitPassiveRefConversion(tInstr.CodeLocation, tInstr.Dest, tInstr.Src, newInstrs);
                    }
                    break;
                case HighInstruction.Opcodes.CallConstrainedMethod:
                    {
                        validationOnly = false;

                        CallConstrainedMethodInstruction tInstr = (CallConstrainedMethodInstruction)instr;
                        HighSsaRegister refInstance = tInstr.InstanceSrc;
                        HighSsaRegister[] parameters = tInstr.Parameters;
                        HighSsaRegister dest = tInstr.ReturnDest;
                        MethodSpecTag methodSpec = tInstr.MethodSpec;

                        if (methodSpec.MethodSlotType != MethodSlotType.Instance)
                            throw new RpaCompileException("CallConstrainedMethodInstruction target is not an instance method");

                        TypeSpecTag constraintType = tInstr.ConstraintType;

                        if (refInstance.ValueType != HighValueType.ManagedPtr)
                            throw new RpaCompileException("CallConstrainedMethodInstruction target is not a managed pointer");

                        if (refInstance.Type != constraintType)
                            throw new RpaCompileException("CallConstrainedMethodInstruction target type is different from constraint type");

                        TypeSpecTag instanceType = refInstance.Type;

                        bool isValueType;
                        bool isInterface;

                        switch (instanceType.SubType)
                        {
                            case TypeSpecTag.SubTypeCode.Array:
                                isValueType = false;
                                isInterface = false;
                                break;
                            case TypeSpecTag.SubTypeCode.Class:
                                {
                                    TypeSpecClassTag instanceClassTag = (TypeSpecClassTag)instanceType;
                                    HighTypeDef instanceTypeDef = this.Compiler.GetTypeDef(instanceClassTag.TypeName);

                                    switch (instanceTypeDef.Semantics)
                                    {
                                        case TypeSemantics.Class:
                                        case TypeSemantics.Delegate:
                                            isValueType = false;
                                            isInterface = false;
                                            break;
                                        case TypeSemantics.Interface:
                                            isValueType = false;
                                            isInterface = true;
                                            break;
                                        case TypeSemantics.Enum:
                                        case TypeSemantics.Struct:
                                            isValueType = true;
                                            isInterface = false;
                                            break;
                                        default:
                                            throw new NotSupportedException();
                                    }
                                }
                                break;
                            default:
                                throw new RpaCompileException("Invalid instance type in CallConstrainedVirtualMethod");
                        };

                        if (isValueType)
                        {
                            TypeSpecClassTag instanceClassTag = (TypeSpecClassTag)refInstance.Type;
                            CliClass cls = this.Compiler.GetClosedClass(instanceClassTag);

                            TypeSpecClassTag methodDeclaringClass = methodSpec.DeclaringClass;

                            HighTypeDef methodTypeDef = this.Compiler.GetTypeDef(methodDeclaringClass.TypeName);

                            HighMethod resolvedMethod;
                            uint methodIndex = 0;
                            if (methodTypeDef.Semantics != TypeSemantics.Class)
                                throw new RpaCompileException("CallConstrainedMethod declaring type isn't a class");

                            CliClass resolvedClass = cls;
                            while (resolvedClass != null)
                            {
                                if (resolvedClass.DeclTagToMethod.TryGetValue(methodSpec.MethodDecl, out methodIndex))
                                    break;
                                resolvedClass = resolvedClass.ParentClass;
                            }

                            if (resolvedClass == null)
                                throw new RpaCompileException("CallConstrainedMethod virtual method was not found");

                            resolvedMethod = resolvedClass.Methods[methodIndex];

                            HighSsaRegister boxed = new HighSsaRegister(HighValueType.BoxedValue, instanceType, null);
                            newInstrs.Add(new BoxInstruction(tInstr.CodeLocation, boxed, refInstance));

                            HighSsaRegister newInstanceSrc = new HighSsaRegister(HighValueType.ReferenceValue, resolvedClass.TypeSpec, null);
                            newInstrs.Add(new Instructions.ObjectToObjectInstruction(tInstr.CodeLocation, newInstanceSrc, boxed));

                            MethodSpecTag generatedMethodSpec = new MethodSpecTag(MethodSlotType.Instance, methodSpec.GenericParameters, resolvedClass.TypeSpec, resolvedMethod.MethodDeclTag);
                            generatedMethodSpec = this.Compiler.TagRepository.InternMethodSpec(generatedMethodSpec);

                            MethodHandle methodHandle = this.Compiler.InstantiateMethod(new MethodSpecMethodKey(generatedMethodSpec), GenerateMethodInstantiationPath(tInstr.CodeLocation));

                            CheckMethodCall(generatedMethodSpec, dest, parameters, resolvedMethod.MethodSignature);

                            newInstrs.Add(new Instructions.CallRloInstanceMethodInstruction(tInstr.CodeLocation, methodHandle, dest, newInstanceSrc, parameters));
                        }
                        else
                        {
                            HighSsaRegister loadedInstance = new HighSsaRegister(HighValueType.ReferenceValue, refInstance.Type, null);
                            newInstrs.Add(new LoadPtrInstruction(tInstr.CodeLocation, loadedInstance, refInstance));

                            if (methodSpec.GenericParameters.Length != 0)
                                throw new RpaCompileException("Generic method spec on a non-virtual method (???)");

                            HighSsaRegister instance = new HighSsaRegister(HighValueType.ReferenceValue, constraintType, null);
                            EmitPassiveRefConversion(tInstr.CodeLocation, instance, loadedInstance, newInstrs);

                            if (isInterface)
                            {
                                HighSsaRegister objReg = new HighSsaRegister(HighValueType.ReferenceValue, m_objectType, null);
                                newInstrs.Add(new Instructions.InterfaceToObjectInstruction(tInstr.CodeLocation, objReg, loadedInstance));

                                if (methodSpec.DeclaringClass != m_objectType)
                                    throw new RpaCompileException("Constrained method on an interface isn't System.Object");

                                uint methodIndex;
                                CliClass objClass = this.Compiler.GetClosedClass(m_objectType);
                                if (!objClass.DeclTagToMethod.TryGetValue(methodSpec.MethodDecl, out methodIndex))
                                    throw new RpaCompileException("Constrained method on System.Object not found");

                                HighMethod resolvedMethod = objClass.Methods[methodIndex];
                                MethodSignatureTag methodSignature = resolvedMethod.MethodSignature;

                                CheckMethodCall(methodSpec, dest, parameters, methodSignature);

                                MethodHandle methodHandle = this.Compiler.InstantiateMethod(new MethodSpecMethodKey(methodSpec), GenerateMethodInstantiationPath(tInstr.CodeLocation));
                                newInstrs.Add(new Instructions.CallRloInstanceMethodInstruction(tInstr.CodeLocation, methodHandle, dest, instance, parameters));
                            }
                            else
                            {
                                if (constraintType is TypeSpecClassTag || constraintType is TypeSpecArrayTag)
                                {
                                    TypeSpecClassTag methodInstanceClass = methodSpec.DeclaringClass;
                                    if (this.Compiler.TypeIsValueType(methodInstanceClass))
                                        throw new RpaCompileException("CallConstrainedMethod method spec is from a value type");

                                    HighSsaRegister convertedInstance = new HighSsaRegister(HighValueType.ReferenceValue, methodInstanceClass, null);
                                    EmitPassiveRefConversion(tInstr.CodeLocation, convertedInstance, loadedInstance, newInstrs);

                                    if (this.Compiler.TypeIsInterface(methodInstanceClass))
                                        throw new RpaCompileException("CallConstrainedMethod target class was an interface");
                                    else
                                    {
                                        CliClass cliClass = this.Compiler.GetClosedClass(methodInstanceClass);
                                        uint methodIndex;

                                        if (!cliClass.DeclTagToMethod.TryGetValue(methodSpec.MethodDecl, out methodIndex))
                                            throw new RpaCompileException("CallConstrainedMethod method wasn't found");

                                        HighMethod resolvedMethod = cliClass.Methods[methodIndex];
                                        MethodSignatureTag methodSignature = resolvedMethod.MethodSignature;

                                        MethodHandle methodHandle = this.Compiler.InstantiateMethod(new MethodSpecMethodKey(methodSpec), GenerateMethodInstantiationPath(tInstr.CodeLocation));
                                        CheckMethodCall(methodSpec, dest, parameters, methodSignature);

                                        newInstrs.Add(new Instructions.CallRloInstanceMethodInstruction(tInstr.CodeLocation, methodHandle, dest, convertedInstance, parameters));
                                    }
                                }
                                else
                                    throw new RpaCompileException("Unexpected constraint type");
                            }
                        }
                    }
                    break;

                case HighInstruction.Opcodes.Return:
                case HighInstruction.Opcodes.Branch:
                case HighInstruction.Opcodes.EnterProtectedBlock:
                case HighInstruction.Opcodes.LeaveRegion:
                    break;
                    //throw new NotImplementedException();
                default:
                    throw new ArgumentException();
            }

            if (validationOnly)
                newInstrs.Add(instr);
        }