Ejemplo n.º 1
0
        private CliClass(CliClass baseClass, Compiler compiler, TypeSpecTag[] argTypes)
        {
            if (!baseClass.m_isCreated)
                throw new Exception("Can't instantiate an open class that hasn't been processed");

            m_typeName = baseClass.m_typeName;
            m_parentClassSpec = (TypeSpecClassTag)baseClass.m_parentClassSpec.Instantiate(compiler.TagRepository, argTypes);
            m_parentClass = compiler.GetClosedClass(m_parentClassSpec);
            m_isSealed = baseClass.m_isSealed;
            m_isAbstract = baseClass.m_isAbstract;
            m_isStruct = baseClass.m_isStruct;
            m_typeSpec = (TypeSpecClassTag)compiler.TagRepository.InternTypeSpec(new TypeSpecClassTag(m_typeName, argTypes));

            m_isCreated = baseClass.m_isCreated;

            m_numGenericParameters = baseClass.m_numGenericParameters;

            List<HighField> staticFields = new List<HighField>();
            foreach (HighField fld in baseClass.m_staticFields)
                staticFields.Add(fld.Instantiate(compiler.TagRepository, argTypes));

            m_staticFields = staticFields.ToArray();

            List<HighMethod> methods = new List<HighMethod>();
            foreach (HighMethod method in baseClass.m_methods)
                methods.Add(method.Instantiate(compiler.TagRepository, argTypes));
            m_methods = methods.ToArray();

            List<HighField> instanceFields = new List<HighField>();
            foreach (HighField fld in baseClass.m_instanceFields)
                instanceFields.Add(fld.Instantiate(compiler.TagRepository, argTypes));
            m_instanceFields = instanceFields.ToArray();

            List<CliVtableSlot> vtableSlots = new List<CliVtableSlot>();
            foreach (CliVtableSlot slot in baseClass.m_vtable)
                vtableSlots.Add(slot.Instantiate(compiler, argTypes));
            m_vtable = vtableSlots.ToArray();

            List<CliInterfaceImpl> interfaceImpls = new List<CliInterfaceImpl>();
            foreach (CliInterfaceImpl ifcImpl in baseClass.m_interfaceImpls)
                interfaceImpls.Add(ifcImpl.Instantiate(compiler, argTypes));
            m_interfaceImpls = interfaceImpls.ToArray();

            List<TypeSpecClassTag> explicitInterfaces = new List<TypeSpecClassTag>();
            foreach (TypeSpecClassTag ifc in baseClass.m_explicitInterfaceSpecs)
                explicitInterfaces.Add((TypeSpecClassTag)ifc.Instantiate(compiler.TagRepository, argTypes));
            m_explicitInterfaceSpecs = explicitInterfaces.ToArray();

            m_declTagToMethod = baseClass.m_declTagToMethod;
            m_declTagToVTableSlot = baseClass.m_declTagToVTableSlot;
            m_ifcToIfcSlot = baseClass.m_ifcToIfcSlot;
            m_nameToInstanceFieldSlot = baseClass.m_nameToInstanceFieldSlot;
            m_nameToStaticFieldSlot = baseClass.m_nameToStaticFieldSlot;
        }
Ejemplo n.º 2
0
 private TypeSpecTag GetOrReturnTypeSpec(ref TypeSpecTag typeSpecTag, string typeName)
 {
     if (typeSpecTag == null)
     {
         TypeNameTag nameTag = new TypeNameTag("mscorlib", "System", typeName);
         nameTag = m_compiler.TagRepository.InternTypeName(nameTag);
         TypeSpecTag typeSpec = new TypeSpecClassTag(nameTag, new TypeSpecTag[0]);
         typeSpecTag = m_compiler.TagRepository.InternTypeSpec(typeSpec);
     }
     return typeSpecTag;
 }
Ejemplo n.º 3
0
        public AssignabilityResolver(Compiler compiler)
        {
            m_compiler = compiler;

            m_objectType = ResolveSimpleType("System", "Object");
            m_arrayType = ResolveSimpleType("System", "Array");
            m_refSZArrayName = compiler.TagRepository.InternTypeName(new TypeNameTag("mscorlib", "Clarity", "RefSZArray"));
            m_valueSZArrayName = compiler.TagRepository.InternTypeName(new TypeNameTag("mscorlib", "Clarity", "ValueSZArray`1", 1, null));
            m_nullableSZArrayName = compiler.TagRepository.InternTypeName(new TypeNameTag("mscorlib", "Clarity", "NullableSZArray`1", 1, null));
            m_nullableName = compiler.TagRepository.InternTypeName(new TypeNameTag("mscorlib", "System", "Nullable`1", 1, null));

            m_ilistName = compiler.TagRepository.InternTypeName(new TypeNameTag("mscorlib", "System.Collections.Generic", "IList`1", 1, null));
            m_icollectionName = compiler.TagRepository.InternTypeName(new TypeNameTag("mscorlib", "System.Collections.Generic", "ICollection`1", 1, null));
            m_ienumerableName = compiler.TagRepository.InternTypeName(new TypeNameTag("mscorlib", "System.Collections.Generic", "IEnumerable`1", 1, null));
        }
Ejemplo n.º 4
0
        // Export exists in CppBuilder.ExportClassDefinitions
        public static HighMethod Read(TagRepository rpa, CatalogReader catalog, BinaryReader reader, TypeNameTag declaringClass)
        {
            bool isStatic = reader.ReadBoolean();
            MethodSignatureTag methodSignature = catalog.GetMethodSignature(reader.ReadUInt32());
            string name = catalog.GetString(reader.ReadUInt32());

            MethodDeclTag methodDeclTag = new MethodDeclTag(name, methodSignature, declaringClass);
            methodDeclTag = rpa.InternMethodDeclTag(methodDeclTag);

            bool isInternal = reader.ReadBoolean();
            HighMethodBody methodBody;

            if (isInternal)
                methodBody = null;
            else
                methodBody = HighMethodBody.Read(rpa, catalog, methodDeclTag, reader);

            return new HighMethod(isStatic, methodSignature, methodBody, methodDeclTag, isInternal);
        }
Ejemplo n.º 5
0
 public TypeSpecClassTag(TypeNameTag typeNameTag, TypeSpecTag[] argTypes)
 {
     m_typeNameTag = typeNameTag;
     m_argTypes = argTypes;
 }
Ejemplo n.º 6
0
        private List<MethodHandle> GenerateVTableForArray(Compiler compiler, TypeSpecArrayTag typeSpec)
        {
            TypeSpecClassTag baseClass;

            if (typeSpec.IsSZArray)
            {
                TypeSpecTag subscriptType = typeSpec.SubscriptType;
                if (compiler.TypeIsValueType(typeSpec.SubscriptType))
                {
                    TypeSpecClassTag subscriptClassTag = (TypeSpecClassTag)subscriptType;
                    TypeNameTag subscriptClassName = subscriptClassTag.TypeName;

                    if (subscriptClassName.FastIs("mscorlib", "System", "Nullable`1", 1, null))
                    {
                        TypeNameTag baseName = new TypeNameTag("mscorlib", "Clarity", "NullableSZArray`1", 1, null);
                        baseName = compiler.TagRepository.InternTypeName(baseName);

                        baseClass = new TypeSpecClassTag(baseName, subscriptClassTag.ArgTypes);
                        baseClass = (TypeSpecClassTag)compiler.TagRepository.InternTypeSpec(baseClass);
                    }
                    else
                    {
                        TypeNameTag baseName = new TypeNameTag("mscorlib", "Clarity", "ValueSZArray`1", 1, null);
                        baseName = compiler.TagRepository.InternTypeName(baseName);

                        baseClass = new TypeSpecClassTag(baseName, new TypeSpecTag[] { subscriptClassTag });
                        baseClass = (TypeSpecClassTag)compiler.TagRepository.InternTypeSpec(baseClass);
                    }
                }
                else
                {
                    TypeNameTag baseName = new TypeNameTag("mscorlib", "Clarity", "RefSZArray");
                    baseName = compiler.TagRepository.InternTypeName(baseName);

                    baseClass = new TypeSpecClassTag(baseName, new TypeSpecTag[0]);
                    baseClass = (TypeSpecClassTag)compiler.TagRepository.InternTypeSpec(baseClass);
                }
            }
            else
                throw new NotImplementedException("Multidimensional arrays not implemented");

            return GenerateVTableForClass(compiler, baseClass);
        }
Ejemplo n.º 7
0
        private List<MethodHandle> GenerateVTableForBox(Compiler compiler, TypeSpecBoxTag typeSpec, VTableGenerationCache vtCache)
        {
            TypeSpecClassTag containedType = typeSpec.ContainedType;
            List<MethodSpecTag> baseSpecs = GenerateMethodSpecsForClass(compiler, containedType);

            IList<MethodSpecTag> vtMethodSpecs = vtCache.ValueTypeMethodSpecs;

            if (vtMethodSpecs == null)
            {
                TypeNameTag valueTypeName = new TypeNameTag("mscorlib", "System", "ValueType");
                valueTypeName = compiler.TagRepository.InternTypeName(valueTypeName);

                TypeSpecClassTag valueTypeSpec = new TypeSpecClassTag(valueTypeName, new TypeSpecTag[0]);
                valueTypeSpec = (TypeSpecClassTag)compiler.TagRepository.InternTypeSpec(valueTypeSpec);

                vtMethodSpecs = GenerateMethodSpecsForClass(compiler, valueTypeSpec);
                vtCache.ValueTypeMethodSpecs = vtMethodSpecs;
            }

            List<MethodHandle> methodHandles = new List<MethodHandle>();

            for (int slotIndex = 0; slotIndex < baseSpecs.Count; slotIndex++)
            {
                MethodSpecTag methodSpec = baseSpecs[slotIndex];
                if (methodSpec == null)
                {
                    methodHandles.Add(null);
                    continue;
                }

                if (slotIndex < vtMethodSpecs.Count && vtMethodSpecs[slotIndex] == methodSpec)
                {
                    MethodSpecTag slotSpec = vtMethodSpecs[slotIndex];
                    if (slotSpec == methodSpec)
                    {
                        MethodDeclTag slotDecl = vtMethodSpecs[slotIndex].MethodDecl;

                        // Generate implementations for value-sensitive slots
                        if (slotDecl.Name == "Equals")
                        {
                            methodHandles.Add(compiler.InstantiateMethod(new GeneratedMethods.GMBoxedValueTypeEquals(typeSpec, vtCache), m_instantiationPath));
                            continue;
                        }
                        else if (slotDecl.Name == "GetHashCode")
                        {
                            methodHandles.Add(compiler.InstantiateMethod(new GeneratedMethods.GMBoxedValueTypeGetHashCode(typeSpec, vtCache), m_instantiationPath));
                            continue;
                        }
                    }
                }

                // If not sensitive, then use the method spec and generate a box thunk
                methodHandles.Add(compiler.InstantiateMethod(new GeneratedMethods.GMBoxThunk(methodSpec), m_instantiationPath));
            }

            return methodHandles;
        }
Ejemplo n.º 8
0
        private static TypeSpecClassTag GetCachedClass(Compiler compiler, ref TypeSpecClassTag clsTagRef, string typeNamespace, string typeName)
        {
            TypeSpecClassTag clsTag = clsTagRef;
            if (clsTag != null)
                return clsTag;

            TypeNameTag name = new TypeNameTag("mscorlib", typeNamespace, typeName);
            name = compiler.TagRepository.InternTypeName(name);

            clsTag = new TypeSpecClassTag(name, new TypeSpecTag[0]);
            clsTag = (TypeSpecClassTag)compiler.TagRepository.InternTypeSpec(clsTag);

            clsTagRef = clsTag;
            return clsTag;
        }
Ejemplo n.º 9
0
        public uint IndexTypeNameTag(TypeNameTag typeNameTag)
        {
            uint index;
            if (m_typeNameTagsDict.TryGetValue(typeNameTag, out index))
                return index;

            typeNameTag.Write(this, m_typeNameCatalogWriter);

            index = (uint)m_typeNameTagsDict.Count;
            m_typeNameTagsDict.Add(typeNameTag, index);

            return index;
        }
Ejemplo n.º 10
0
 public bool HaveCliOpenInterface(TypeNameTag typeName)
 {
     if (m_typeDefsDict[typeName].Semantics != TypeSemantics.Interface)
         throw new ArgumentException();
     return m_openInterfaces.Lookup(typeName).IsCreated;
 }
Ejemplo n.º 11
0
 public void Initialize(TypeNameTag nameTag)
 {
     m_typeName = nameTag;
 }
Ejemplo n.º 12
0
        public bool Create(Compiler compiler)
        {
            HighTypeDef typeDef = compiler.GetTypeDef(m_typeName);

            TypeSpecClassTag parentClassSpec = null;
            HighClassVtableSlot[] newSlots;
            HighClassVtableSlot[] replacedSlots;
            HighInterfaceImplementation[] typeInterfaceImpls;

            if (typeDef.Semantics == TypeSemantics.Struct || typeDef.Semantics == TypeSemantics.Class)
            {
                if (typeDef.Semantics == TypeSemantics.Struct)
                {
                    m_isStruct = true;
                    TypeNameTag valueTypeName = new TypeNameTag("mscorlib", "System", "ValueType", 0, null);
                    valueTypeName = compiler.TagRepository.InternTypeName(valueTypeName);
                    TypeSpecClassTag vtClassTag = new TypeSpecClassTag(valueTypeName, new TypeSpecTag[0]);
                    vtClassTag = (TypeSpecClassTag)compiler.TagRepository.InternTypeSpec(vtClassTag);

                    parentClassSpec = vtClassTag;
                }
                else if (typeDef.Semantics == TypeSemantics.Class)
                {
                    m_isStruct = false;
                    parentClassSpec = typeDef.ParentClass;

                    RestrictedExtensionType thisRet = GetRestrictedExtensionType(m_typeName);

                    if (parentClassSpec == null)
                    {
                        if (thisRet != RestrictedExtensionType.Object)
                            throw new Exception("Parentless class is not [mscorlib]System.Object");
                    }
                    else
                    {
                        if (thisRet == RestrictedExtensionType.Object)
                            throw new Exception("[mscorlib]System.Object has a parent");

                        RestrictedExtensionType parentRet = GetRestrictedExtensionType(parentClassSpec.TypeName);

                        bool isExtensionOK = false;
                        switch (parentRet)
                        {
                            case RestrictedExtensionType.ValueType:
                                if (thisRet == RestrictedExtensionType.Enum)
                                    isExtensionOK = true;
                                break;
                            case RestrictedExtensionType.Delegate:
                                if (thisRet == RestrictedExtensionType.MulticastDelegate)
                                    isExtensionOK = true;
                                break;
                            case RestrictedExtensionType.Enum:
                            case RestrictedExtensionType.MulticastDelegate:
                            case RestrictedExtensionType.NullableSZArray:
                            case RestrictedExtensionType.RefSZArray:
                            case RestrictedExtensionType.ValueSZArray:
                                break;
                            case RestrictedExtensionType.Object:
                            case RestrictedExtensionType.None:
                                isExtensionOK = true;
                                break;
                            case RestrictedExtensionType.Array:
                                if (thisRet == RestrictedExtensionType.NullableSZArray || thisRet == RestrictedExtensionType.ValueSZArray || thisRet == RestrictedExtensionType.RefSZArray)
                                    isExtensionOK = true;
                                break;
                            default:
                                throw new ArgumentException();
                        }

                        if (!isExtensionOK)
                            throw new Exception("Invalid extension of a restricted class");
                    }
                }

                m_instanceFields = typeDef.InstanceFields;
                m_methods = typeDef.Methods;
                m_staticFields = typeDef.StaticFields;
                m_isSealed = typeDef.IsSealed;
                m_isAbstract = typeDef.IsAbstract;

                replacedSlots = typeDef.ReplacedSlots;
                newSlots = typeDef.NewSlots;
                typeInterfaceImpls = typeDef.InterfaceImpls;
            }
            else if (typeDef.Semantics == TypeSemantics.Delegate)
            {
                m_isStruct = false;

                TypeNameTag dgTypeName = new TypeNameTag("mscorlib", "System", typeDef.IsMulticastDelegate ? "MulticastDelegate" : "Delegate", 0, null);
                dgTypeName = compiler.TagRepository.InternTypeName(dgTypeName);
                TypeSpecClassTag dgClassTag = new TypeSpecClassTag(dgTypeName, new TypeSpecTag[0]);
                dgClassTag = (TypeSpecClassTag)compiler.TagRepository.InternTypeSpec(dgClassTag);

                parentClassSpec = dgClassTag;

                m_instanceFields = new HighField[0];
                m_methods = new HighMethod[0];
                m_staticFields = new HighField[0];
                m_isSealed = false;
                m_isAbstract = true;

                replacedSlots = new HighClassVtableSlot[0];

                MethodDeclTag invokeTag = new MethodDeclTag("Invoke", typeDef.DelegateSignature, m_typeName);
                invokeTag = compiler.TagRepository.InternMethodDeclTag(invokeTag);

                HighClassVtableSlot invokeSlot = new HighClassVtableSlot(invokeTag, typeDef.DelegateSignature, null, true, false);

                newSlots = new HighClassVtableSlot[1] { invokeSlot };

                typeInterfaceImpls = new HighInterfaceImplementation[0];
            }
            else if (typeDef.Semantics == TypeSemantics.Enum)
            {
                m_isStruct = false;

                TypeNameTag dgTypeName = new TypeNameTag("mscorlib", "System", "Enum", 0, null);
                dgTypeName = compiler.TagRepository.InternTypeName(dgTypeName);
                TypeSpecClassTag dgClassTag = new TypeSpecClassTag(dgTypeName, new TypeSpecTag[0]);
                dgClassTag = (TypeSpecClassTag)compiler.TagRepository.InternTypeSpec(dgClassTag);

                parentClassSpec = dgClassTag;

                string underlyingTypeName;
                switch (typeDef.UnderlyingType)
                {
                    case HighTypeDef.EnumUnderlyingType.Int8:
                        underlyingTypeName = "SByte";
                        break;
                    case HighTypeDef.EnumUnderlyingType.Int16:
                        underlyingTypeName = "Int16";
                        break;
                    case HighTypeDef.EnumUnderlyingType.Int32:
                        underlyingTypeName = "Int32";
                        break;
                    case HighTypeDef.EnumUnderlyingType.Int64:
                        underlyingTypeName = "Int64";
                        break;
                    case HighTypeDef.EnumUnderlyingType.UInt8:
                        underlyingTypeName = "Byte";
                        break;
                    case HighTypeDef.EnumUnderlyingType.UInt16:
                        underlyingTypeName = "Int16";
                        break;
                    case HighTypeDef.EnumUnderlyingType.UInt32:
                        underlyingTypeName = "UInt32";
                        break;
                    case HighTypeDef.EnumUnderlyingType.UInt64:
                        underlyingTypeName = "UInt64";
                        break;
                    default:
                        throw new Exception();
                }

                TypeNameTag underlyingTypeNameTag = new TypeNameTag("mscorlib", "System", underlyingTypeName);
                underlyingTypeNameTag = compiler.TagRepository.InternTypeName(underlyingTypeNameTag);

                TypeSpecClassTag underlyingTypeSpec = new TypeSpecClassTag(underlyingTypeNameTag, new TypeSpecTag[0]);
                underlyingTypeSpec = (TypeSpecClassTag)compiler.TagRepository.InternTypeSpec(underlyingTypeSpec);

                HighField fld = new HighField("value__", underlyingTypeSpec);

                m_instanceFields = new HighField[1] { fld };
                m_methods = new HighMethod[0];
                m_staticFields = new HighField[0];
                m_isSealed = true;
                m_isAbstract = false;

                replacedSlots = new HighClassVtableSlot[0];
                newSlots = new HighClassVtableSlot[0];
                typeInterfaceImpls = new HighInterfaceImplementation[0];
            }
            else
                throw new ArgumentException();

            if (parentClassSpec != null)
            {
                if (compiler.GetTypeDef(parentClassSpec.TypeName).Semantics != TypeSemantics.Class)
                    throw new RpaCompileException("Can't extend class with non-class semantics");

                if (!compiler.HaveCliOpenClass(parentClassSpec.TypeName))
                    return false;

                CliClass parentClass = compiler.GetClosedClass(parentClassSpec);

                if (parentClass.m_isSealed)
                    throw new RpaCompileException("Can't extend sealed CLI class");

                m_parentClass = parentClass;
            }

            m_numGenericParameters = typeDef.NumGenericParameters;

            // Update vtable
            {
                Dictionary<MethodDeclTag, uint> declTagToMethod = new Dictionary<MethodDeclTag, uint>();
                uint methodIndex = 0;
                foreach (HighMethod method in m_methods)
                {
                    if (declTagToMethod.ContainsKey(method.MethodDeclTag))
                        throw new Exception("Duplicate method declaration");

                    declTagToMethod.Add(method.MethodDeclTag, methodIndex++);
                }
                m_declTagToMethod = declTagToMethod;
            }

            m_declTagToVTableSlot = new Dictionary<MethodDeclTag, uint>();
            m_ifcToIfcSlot = new Dictionary<TypeSpecClassTag, uint>();
            List<CliVtableSlot> slots = new List<CliVtableSlot>();

            if (m_parentClass != null)
            {
                foreach (KeyValuePair<MethodDeclTag, uint> dttvs in m_parentClass.m_declTagToVTableSlot)
                    m_declTagToVTableSlot.Add(dttvs.Key, dttvs.Value);

                foreach (CliVtableSlot parentSlot in m_parentClass.m_vtable)
                {
                    CliMethodIndex methodIndex = parentSlot.MethodIndex;

                    if (methodIndex == null)
                        slots.Add(parentSlot);
                    else
                    {
                        CliMethodIndex newIndex = new CliMethodIndex(methodIndex.Depth + 1, methodIndex.Index);
                        slots.Add(new CliVtableSlot(newIndex, parentSlot.MethodSignature, parentSlot.IsSealed));
                    }
                }
            }

            foreach (HighClassVtableSlot slot in replacedSlots)
            {
                uint index;
                if (!m_declTagToVTableSlot.TryGetValue(slot.SlotTag, out index))
                    throw new Exception("Unmatched vtable slot replacement");
                CliVtableSlot existingSlot = slots[(int)index];
                if (existingSlot.IsSealed)
                    throw new Exception("Can't replace sealed vtable slot");

                if (existingSlot.MethodSignature != slot.Signature)
                    throw new Exception("VTable slot override signature doesn't match");

                CliMethodIndex methodIndex = null;
                if (!slot.IsAbstract)
                {
                    HighMethod method;
                    methodIndex = this.FindMethod(slot.ImplementingMethodTag, out method);
                    if (method.MethodSignature != slot.Signature)
                        throw new Exception("Signature of method used by vtable slot doesn't match vtable slot's signature");
                }

                slots[(int)index] = new CliVtableSlot(methodIndex, slot.Signature, slot.IsFinal);
            }

            foreach (HighClassVtableSlot slot in newSlots)
            {
                CliMethodIndex methodIndex = null;
                if (!slot.IsAbstract)
                {
                    HighMethod method;
                    methodIndex = this.FindMethod(slot.ImplementingMethodTag, out method);
                    if (method.MethodSignature != slot.Signature)
                        throw new Exception("Signature of method used by vtable slot doesn't match vtable slot's signature");
                }

                m_declTagToVTableSlot.Add(slot.SlotTag, (uint)slots.Count);
                slots.Add(new CliVtableSlot(methodIndex, slot.Signature, slot.IsFinal));
            }

            m_vtable = slots.ToArray();

            if (!m_isAbstract)
                foreach (CliVtableSlot slot in m_vtable)
                    if (slot.MethodIndex == null)
                        throw new RpaCompileException("Non-abstract class has unoverrided abstract methods");

            m_nameToInstanceFieldSlot = new Dictionary<string, uint>();
            for (uint i = 0; i < m_instanceFields.Length; i++)
            {
                string fldName = m_instanceFields[i].Name;
                if (m_nameToInstanceFieldSlot.ContainsKey(fldName))
                    throw new RpaCompileException("Duplicate field name");
                m_nameToInstanceFieldSlot.Add(fldName, i);
            }

            m_nameToStaticFieldSlot = new Dictionary<string, uint>();
            for (uint i = 0; i < m_staticFields.Length; i++)
            {
                string fldName = m_staticFields[i].Name;
                if (m_nameToStaticFieldSlot.ContainsKey(fldName))
                    throw new RpaCompileException("Duplicate field name");
                m_nameToStaticFieldSlot.Add(fldName, i);
            }

            HashSet<TypeSpecClassTag> explicitImpls = new HashSet<TypeSpecClassTag>();
            List<CliInterfaceImpl> interfaceImpls = new List<CliInterfaceImpl>();
            foreach (HighInterfaceImplementation ifcImpl in typeInterfaceImpls)
            {
                if (!explicitImpls.Add(ifcImpl.Interface))
                    throw new Exception("Duplicate interface implementation");

                interfaceImpls.Add(ResolveInterfaceImpl(compiler, ifcImpl));
            }

            m_interfaceImpls = interfaceImpls.ToArray();
            m_parentClassSpec = parentClassSpec;

            m_explicitInterfaceSpecs = typeDef.ParentInterfaces;
            if (m_explicitInterfaceSpecs == null)
                m_explicitInterfaceSpecs = new TypeSpecClassTag[0];

            List<TypeSpecTag> thisGenericParameters = new List<TypeSpecTag>();
            for (uint i = 0; i < m_numGenericParameters; i++)
            {
                TypeSpecGenericParamTypeTag gptt = new TypeSpecGenericParamTypeTag(TypeSpecGenericParamTypeTag.Values.Var);
                TypeSpecGenericParamTag gpTag = new TypeSpecGenericParamTag(gptt, i);
                gpTag = (TypeSpecGenericParamTag)compiler.TagRepository.InternTypeSpec(gpTag);

                thisGenericParameters.Add(gpTag);
            }

            TypeSpecClassTag thisClass = new TypeSpecClassTag(m_typeName, thisGenericParameters.ToArray());
            thisClass = (TypeSpecClassTag)compiler.TagRepository.InternTypeSpec(thisClass);

            m_typeSpec = thisClass;

            m_typeDeclarationOrder = new Dictionary<TypeSpecClassTag, uint>();
            ResolveTDOForClass(this);

            m_isCreated = true;

            return true;
        }
Ejemplo n.º 13
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);
        }
Ejemplo n.º 14
0
        public void Read(TagRepository rpa, CatalogReader catalog, BinaryReader reader)
        {
            m_semantics = (TypeSemantics)reader.ReadByte();
            switch (m_semantics)
            {
                case TypeSemantics.Class:
                case TypeSemantics.Interface:
                case TypeSemantics.Struct:
                case TypeSemantics.Enum:
                case TypeSemantics.Delegate:
                    break;
                default:
                    throw new RpaLoadException("Invalid type semantics");
            }

            m_typeName = catalog.GetTypeName(reader.ReadUInt32());

            if (m_typeName.AssemblyName != catalog.AssemblyName)
                throw new Exception("Type definition outside of assembly");

            m_numGenericParameters = m_typeName.NumGenericParameters;

            m_underlyingType = EnumUnderlyingType.NotEnum;
            if (m_semantics == TypeSemantics.Delegate)
            {
                this.ReadDelegate(rpa, catalog, reader);
            }
            else if (m_semantics == TypeSemantics.Enum)
            {
                this.ReadEnum(rpa, catalog, reader);
            }
            else
            {
                this.ReadClassDefinitions(rpa, catalog, reader);

                if (m_semantics == Clarity.Rpa.TypeSemantics.Class || m_semantics == Clarity.Rpa.TypeSemantics.Struct)
                    this.ReadClassStatics(rpa, catalog, reader);
            }
        }
Ejemplo n.º 15
0
 public void InstantiateOpenClass(TypeNameTag typeName)
 {
     if (m_typeDefsDict[typeName].Semantics == TypeSemantics.Interface)
         throw new ArgumentException();
     m_openClasses.Lookup(typeName);
 }
Ejemplo n.º 16
0
        private static RestrictedExtensionType GetRestrictedExtensionType(TypeNameTag typeName)
        {
            if (typeName.ContainerType == null && typeName.AssemblyName == "mscorlib" && typeName.TypeNamespace == "System" && typeName.NumGenericParameters == 0)
            {
                if (typeName.TypeName == "Enum")
                    return RestrictedExtensionType.Enum;
                if (typeName.TypeName == "Delegate")
                    return RestrictedExtensionType.Delegate;
                if (typeName.TypeName == "MulticastDelegate")
                    return RestrictedExtensionType.MulticastDelegate;
                if (typeName.TypeName == "ValueType")
                    return RestrictedExtensionType.ValueType;
                if (typeName.TypeName == "Object")
                    return RestrictedExtensionType.Object;
                if (typeName.TypeName == "Array")
                    return RestrictedExtensionType.Array;
            }
            if (typeName.ContainerType == null && typeName.AssemblyName == "mscorlib" && typeName.TypeNamespace == "Clarity")
            {
                if (typeName.TypeName == "RefSZArray" && typeName.NumGenericParameters == 0)
                    return RestrictedExtensionType.RefSZArray;
                if (typeName.TypeName == "NullableSZArray`1" && typeName.NumGenericParameters == 1)
                    return RestrictedExtensionType.NullableSZArray;
                if (typeName.TypeName == "ValueSZArray`1" && typeName.NumGenericParameters == 1)
                    return RestrictedExtensionType.ValueSZArray;
            }

            return RestrictedExtensionType.None;
        }
Ejemplo n.º 17
0
        private TypeSpecClassTag ResolveSimpleType(string typeNamespace, string typeName)
        {
            TypeNameTag typeNameTag = new TypeNameTag("mscorlib", typeNamespace, typeName, 0, null);
            typeNameTag = m_compiler.TagRepository.InternTypeName(typeNameTag);

            TypeSpecClassTag classTag = new TypeSpecClassTag(typeNameTag, new TypeSpecTag[0]);
            return (TypeSpecClassTag)m_compiler.TagRepository.InternTypeSpec(classTag);
        }
Ejemplo n.º 18
0
 public HighTypeDef GetTypeDef(TypeNameTag typeName)
 {
     HighTypeDef result;
     if (!m_typeDefsDict.TryGetValue(typeName, out result))
         throw new Exception("Unresolved type name");
     return result;
 }