コード例 #1
0
ファイル: RloRegionConverter.cs プロジェクト: elasota/clarity
        public void ConvertNode(HighCfgNode srcNode, HighCfgNodeHandle cfgNodeHandle)
        {
            List<HighInstruction> instructions = new List<HighInstruction>();

            List<HighPhi> newPhis = new List<HighPhi>();
            foreach (HighPhi phi in srcNode.Phis)
            {
                List<HighPhiLink> newLinks = new List<HighPhiLink>();
                foreach (HighPhiLink link in phi.Links)
                {
                    HighCfgNodeHandle predecessor = GetNode(link.Predecessor.Value);
                    HighSsaRegister reg = m_methodConverter.GetReg(link.Reg);

                    newLinks.Add(new HighPhiLink(predecessor, reg));
                }

                HighSsaRegister dest = m_methodConverter.GetReg(phi.Dest);
                newPhis.Add(new HighPhi(dest, newLinks.ToArray()));
            }

            List<HighCfgNodeHandle> newPredecessors = new List<HighCfgNodeHandle>();
            foreach (HighCfgNodeHandle pred in srcNode.Predecessors)
                newPredecessors.Add(GetNode(pred.Value));

            List<HighInstruction> newInstructions = new List<HighInstruction>();
            foreach (HighInstruction instr in srcNode.Instructions)
                ConvertInstruction(instr, newInstructions);

            if (newInstructions.Count == 0)
                throw new Exception("CFG node was empty");

            HighCfgNode newNode = new HighCfgNode(newPredecessors.ToArray(), newPhis.ToArray(), newInstructions.ToArray());

            cfgNodeHandle.Value = newNode;
        }
コード例 #2
0
 protected override void ProcessNode(HighCfgNode cfgNode)
 {
     foreach (HighPhi phi in cfgNode.Phis)
         ProcessSsa(phi.Dest);
     foreach (HighInstruction instr in cfgNode.Instructions)
         instr.VisitSsaDests(m_ssaVisitor);
 }
コード例 #3
0
ファイル: RloPerNodePass.cs プロジェクト: elasota/clarity
 public void QueueNode(HighCfgNode cfgNode)
 {
     if (!m_alreadyQueuedNodesSet.Add(cfgNode))
         return;
     m_queuedNodes.Enqueue(cfgNode);
     m_finalQueue.Enqueue(cfgNode);
 }
コード例 #4
0
ファイル: RloReplaceSsaPass.cs プロジェクト: elasota/clarity
 protected override void ProcessNode(HighCfgNode cfgNode)
 {
     foreach (HighPhi phi in cfgNode.Phis)
     {
         phi.VisitSsaDests(m_visitor);
         phi.VisitSsaUses(m_visitor);
     }
     foreach (HighInstruction instr in cfgNode.Instructions)
     {
         instr.VisitSsaDests(m_visitor);
         instr.VisitSsaUses(m_visitor);
     }
 }
コード例 #5
0
ファイル: RloFindUseDefsPass.cs プロジェクト: elasota/clarity
 protected override void ProcessNode(HighCfgNode cfgNode)
 {
     foreach (HighPhi phi in cfgNode.Phis)
     {
         m_currentEmitter = phi;
         phi.VisitSsaDests(m_defVisitorDelegate);
         foreach (HighPhiLink link in phi.Links)
         {
             m_currentUser = link;
             link.VisitSsaUses(m_useVisitorDelegate);
         }
     }
     foreach (HighInstruction instr in cfgNode.Instructions)
     {
         m_currentEmitter = instr;
         m_currentUser = instr;
         instr.VisitSsaDests(m_defVisitorDelegate);
         instr.VisitSsaUses(m_useVisitorDelegate);
     }
 }
コード例 #6
0
            private HighCfgNode GenerateFinallyInit(HighCfgNode handler)
            {
                List<HighInstruction> instrs = new List<HighInstruction>();

                HighSsaRegister exceptionReg = new HighSsaRegister(HighValueType.ReferenceValue, m_initPass.ObjectType, null);
                HighSsaRegister routeReg = new HighSsaRegister(HighValueType.ReferenceValue, m_initPass.IntType, null);
                instrs.Add(new Instructions.CatchOrRouteInstruction(null, routeReg, exceptionReg));
                instrs.Add(new Rpa.Instructions.BranchInstruction(null, new HighCfgNodeHandle(handler)));

                return new HighCfgNode(new HighCfgNodeHandle[0], new HighPhi[0], instrs.ToArray());
            }
コード例 #7
0
ファイル: RloPerNodePass.cs プロジェクト: elasota/clarity
 protected abstract void ProcessNode(HighCfgNode cfgNode);
コード例 #8
0
ファイル: RloRegionConverter.cs プロジェクト: elasota/clarity
        public HighCfgNodeHandle GetNode(HighCfgNode srcNode)
        {
            HighCfgNodeHandle nodeHandle;
            if (m_sourceToConverted.TryGetValue(srcNode, out nodeHandle))
                return nodeHandle;

            nodeHandle = new HighCfgNodeHandle();
            m_sourceToConverted.Add(srcNode, nodeHandle);

            m_unconvertedNodes.Enqueue(new KeyValuePair<HighCfgNode, HighCfgNodeHandle>(srcNode, nodeHandle));

            return nodeHandle;
        }
コード例 #9
0
 public RloRoutedBranchInstruction(CodeLocationTag codeLocation, int routeID, HighCfgNode destination)
     : base(codeLocation)
 {
     m_routeID = routeID;
     m_destination = new HighCfgEdge(this, new HighCfgNodeHandle(destination));
 }
コード例 #10
0
 public RouteTermination(int routeID, HighCfgNode successor)
 {
     m_routeID = routeID;
     m_successor = successor;
 }
コード例 #11
0
 private HighCfgNode GenerateRepeatRoute(int routeID, HighCfgNode trappingFinally)
 {
     List<HighInstruction> instrs = new List<HighInstruction>();
     instrs.Add(new Instructions.RloRoutedBranchInstruction(null, routeID, trappingFinally));
     return new HighCfgNode(new HighCfgNodeHandle[0], new HighPhi[0], instrs.ToArray());
 }
コード例 #12
0
            private HighCfgNode GenerateTryCatchHandler(HighTryCatchRegion tProtRegion)
            {
                if (tProtRegion.CatchHandlers.Length == 0)
                    throw new RpaCompileException("HighTryCatchRegion has no catch handlers");

                List<HighInstruction> startInstrs = new List<HighInstruction>();
                HighSsaRegister exceptionObj = new HighSsaRegister(HighValueType.ReferenceValue, m_initPass.ObjectType, null);
                startInstrs.Add(new Rpa.Instructions.CatchInstruction(null, exceptionObj, m_initPass.ObjectType));

                List<HighInstruction> rethrowInstrs = new List<HighInstruction>();
                Rpa.Instructions.ThrowInstruction throwInstr = new Rpa.Instructions.ThrowInstruction(null, exceptionObj);
                if (m_exceptionNode != null)
                    throwInstr.ExceptionEdge = new HighCfgEdge(throwInstr, new HighCfgNodeHandle(m_exceptionNode));
                rethrowInstrs.Add(throwInstr);

                HighCfgNode fallThroughNode = new HighCfgNode(new HighCfgNodeHandle[0], new HighPhi[0], rethrowInstrs.ToArray());

                // Build stack handlers from the bottom up
                HighCatchHandler[] catchHandlers = tProtRegion.CatchHandlers;
                for (int i = 0; i < catchHandlers.Length; i++)
                {
                    HighCatchHandler handler = catchHandlers[catchHandlers.Length - 1 - i];
                    TypeSpecTag catchType = handler.CatchType;
                    if (m_initPass.m_compiler.TypeIsValueType(catchType))
                        throw new RpaCompileException("Exception catch type is value type");

                    HighCfgNode catchNode = handler.Region.EntryNode.Value;
                    Rpa.Instructions.CatchInstruction catchInstr = catchNode.Instructions[0] as Rpa.Instructions.CatchInstruction;
                    if (catchInstr == null)
                        throw new RpaCompileException("Catch handler target isn't a catch instruction");

                    if (catchInstr.Dest.ValueType != HighValueType.ReferenceValue || catchInstr.Dest.Type != catchType)
                        throw new RpaCompileException("Catch handler destination is invalid");

                    HighSsaRegister castCatch = new HighSsaRegister(HighValueType.ReferenceValue, catchType, null);

                    catchNode.Instructions[0] = new Instructions.CopyInstruction(catchInstr.CodeLocation, catchInstr.Dest, castCatch);

                    List<HighInstruction> handlerInstrs = new List<HighInstruction>();
                    handlerInstrs.Add(new Rpa.Instructions.DynamicCastInstruction(null, castCatch, exceptionObj, catchType));
                    handlerInstrs.Add(new Rpa.Instructions.BranchRefNullInstruction(null, castCatch, new HighCfgNodeHandle(fallThroughNode), new HighCfgNodeHandle(catchNode)));

                    fallThroughNode = new HighCfgNode(new HighCfgNodeHandle[0], new HighPhi[0], handlerInstrs.ToArray());
                }

                startInstrs.Add(new Rpa.Instructions.BranchInstruction(null, new HighCfgNodeHandle(fallThroughNode)));
                return new HighCfgNode(new HighCfgNodeHandle[0], new HighPhi[0], startInstrs.ToArray());
            }
コード例 #13
0
ファイル: GMDelegateInvoke.cs プロジェクト: elasota/clarity
        public override RloMethod GenerateMethod(Compiler compiler, MethodInstantiationPath instantiationPath)
        {
            TypeSpecDelegateTag delegateType = m_dt;
            TypeSpecClassTag delegateClassType = delegateType.DelegateType;
            MethodSpecTag methodSpec = delegateType.MethodSpec;

            TypeSpecClassTag targetType = methodSpec.DeclaringClass;

            CliClass delegateCls = compiler.GetClosedClass(delegateClassType);

            TypeNameTag delegateTypeName = delegateCls.TypeName;
            HighTypeDef delegateTypeDef = compiler.GetTypeDef(delegateTypeName);
            if (delegateTypeDef.Semantics != TypeSemantics.Delegate)
                throw new RpaCompileException("Delegate-bound class is not a delegate");

            HighTypeDef targetTypeDef = compiler.GetTypeDef(targetType.TypeName);

            CliClass targetCls = null;
            CliInterface targetIfc = null;

            bool isInterface;
            switch (targetTypeDef.Semantics)
            {
                case TypeSemantics.Class:
                case TypeSemantics.Delegate:
                case TypeSemantics.Enum:
                case TypeSemantics.Struct:
                    isInterface = false;
                    targetCls = compiler.GetClosedClass(targetType);
                    break;
                case TypeSemantics.Interface:
                    isInterface = true;
                    targetIfc = compiler.GetClosedInterface(targetType);
                    break;
                default:
                    throw new ArgumentException();
            }

            MethodSignatureTag declSignature = delegateTypeDef.DelegateSignature;

            MethodDeclTag invokeDeclTag = new MethodDeclTag("Invoke", declSignature, delegateTypeName);
            invokeDeclTag = compiler.TagRepository.InternMethodDeclTag(invokeDeclTag);

            uint vtableSlotIndex = delegateCls.DeclTagToVTableSlot[invokeDeclTag];
            CliVtableSlot vtableSlot = delegateCls.VTable[vtableSlotIndex];

            MethodSignatureTag delegateMethodSignature = vtableSlot.MethodSignature;
            MethodSignatureTag targetMethodSignature;

            switch (methodSpec.MethodSlotType)
            {
                case MethodSlotType.Instance:
                case MethodSlotType.Static:
                    {
                        if (isInterface)
                            throw new RpaCompileException("Wrong method spec type for interface");

                        HighMethod method = targetCls.Methods[targetCls.DeclTagToMethod[methodSpec.MethodDecl]];
                        targetMethodSignature = method.MethodSignature.Instantiate(compiler.TagRepository, methodSpec.DeclaringClass.ArgTypes, methodSpec.GenericParameters);
                    }
                    break;
                case MethodSlotType.Virtual:
                    {
                        if (isInterface)
                        {
                            HighClassVtableSlot vtSlot = targetIfc.Slots[targetIfc.CliSlotForSlotTag(methodSpec.MethodDecl)];
                            targetMethodSignature = vtSlot.Signature.Instantiate(compiler.TagRepository, methodSpec.DeclaringClass.ArgTypes, methodSpec.GenericParameters);
                        }
                        else
                        {
                            CliVtableSlot calledVtableSlot = targetCls.VTable[targetCls.DeclTagToVTableSlot[methodSpec.MethodDecl]];

                            if (calledVtableSlot.MethodSignature.NumGenericParameters > 0)
                                throw new RpaCompileException("Can't generate delegate thunk to virtual generic");

                            targetMethodSignature = calledVtableSlot.MethodSignature.Instantiate(compiler.TagRepository, methodSpec.DeclaringClass.ArgTypes, methodSpec.GenericParameters);
                        }
                    }
                    break;
                default:
                    throw new Exception();
            }

            List<HighInstruction> instrs = new List<HighInstruction>();

            HighLocal thisLocal = new HighLocal(m_dt, HighLocal.ETypeOfType.Value);
            HighLocal[] locals = new HighLocal[0];

            List<HighLocal> args = new List<HighLocal>();

            int numParams = delegateMethodSignature.ParamTypes.Length;
            if (numParams != targetMethodSignature.ParamTypes.Length)
                throw new RpaCompileException("Delegate parameter count mismatch");

            List<HighSsaRegister> convertedParameters = new List<HighSsaRegister>();
            for (int i = 0; i < numParams; i++)
            {
                MethodSignatureParam delegateSigParam = delegateMethodSignature.ParamTypes[i];
                MethodSignatureParam targetSigParam = targetMethodSignature.ParamTypes[i];

                TypeSpecTag delegateSigType = delegateSigParam.Type;
                TypeSpecTag targetSigType = targetSigParam.Type;

                if (delegateSigParam.TypeOfType.Value != targetSigParam.TypeOfType.Value)
                    throw new RpaCompileException("Delegate parameter type-of-type mismatch");

                switch (delegateSigParam.TypeOfType.Value)
                {
                    case MethodSignatureParamTypeOfType.Values.ByRef:
                        {
                            if (delegateSigType != targetSigType)
                                throw new RpaCompileException("Delegate parameter type mismatch");

                            HighSsaRegister ssa = new HighSsaRegister(HighValueType.ManagedPtr, delegateSigType, null);
                            HighLocal arg = new HighLocal(delegateSigParam.Type, HighLocal.ETypeOfType.ByRef);

                            args.Add(arg);
                            instrs.Add(new Rpa.Instructions.LoadLocalInstruction(null, ssa, arg));
                            convertedParameters.Add(ssa);
                        }
                        break;
                    case MethodSignatureParamTypeOfType.Values.Value:
                        {
                            if (delegateSigType == targetSigType)
                            {
                                HighSsaRegister ssa = new HighSsaRegister(HighValueType.ValueValue, delegateSigParam.Type, null);
                                HighLocal arg = new HighLocal(delegateSigParam.Type, HighLocal.ETypeOfType.Value);
                                args.Add(arg);
                                instrs.Add(new Rpa.Instructions.LoadLocalInstruction(null, ssa, arg));
                                convertedParameters.Add(ssa);
                            }
                            else
                            {
                                if (compiler.TypeIsValueType(delegateSigType) || compiler.TypeIsValueType(targetSigType))
                                    throw new RpaCompileException("Delegate parameter type mismatch");

                                HighSsaRegister delegateParamSsa = new HighSsaRegister(HighValueType.ReferenceValue, delegateSigType, null);
                                HighLocal arg = new HighLocal(delegateSigParam.Type, HighLocal.ETypeOfType.Value);
                                args.Add(arg);
                                instrs.Add(new Rpa.Instructions.LoadLocalInstruction(null, delegateParamSsa, arg));

                                HighSsaRegister targetParamSsa = GenerateConvertReference(compiler, delegateParamSsa, targetSigType, instrs);

                                convertedParameters.Add(targetParamSsa);
                            }
                        }
                        break;
                    case MethodSignatureParamTypeOfType.Values.TypedByRef:
                        throw new NotImplementedException();
                    default:
                        throw new Exception();
                }
            }

            HighSsaRegister methodReturnValue;
            if (targetMethodSignature.RetType is TypeSpecVoidTag)
                methodReturnValue = null;
            else
            {
                bool isValueType = compiler.TypeIsValueType(targetMethodSignature.RetType);
                methodReturnValue = new HighSsaRegister(isValueType ? HighValueType.ValueValue : HighValueType.ReferenceValue, targetMethodSignature.RetType, null);
            }

            HighInstruction callInstr;

            switch (methodSpec.MethodSlotType)
            {
                case MethodSlotType.Instance:
                    {
                        HighSsaRegister instanceReg;
                        HighSsaRegister thisReg = new HighSsaRegister(HighValueType.ReferenceValue, m_dt, null);
                        instrs.Add(new Rpa.Instructions.LoadLocalInstruction(null, thisReg, thisLocal));

                        if (compiler.TypeIsValueType(methodSpec.DeclaringClass))
                        {
                            HighSsaRegister boxedReg = new HighSsaRegister(HighValueType.BoxedValue, methodSpec.DeclaringClass, null);
                            instrs.Add(new Instructions.LoadDelegateTargetInstruction(null, boxedReg, thisReg));
                            instanceReg = new HighSsaRegister(HighValueType.ManagedPtr, methodSpec.DeclaringClass, null);
                            instrs.Add(new Rpa.Instructions.UnboxPtrInstruction(null, instanceReg, boxedReg));
                        }
                        else
                        {
                            instanceReg = new HighSsaRegister(HighValueType.BoxedValue, methodSpec.DeclaringClass, null);
                            instrs.Add(new Instructions.LoadDelegateTargetInstruction(null, instanceReg, thisReg));
                        }

                        MethodHandle methodHandle = compiler.InstantiateMethod(new MethodSpecMethodKey(methodSpec), instantiationPath);
                        callInstr = new Instructions.CallRloInstanceMethodInstruction(null, methodHandle, methodReturnValue, instanceReg, convertedParameters.ToArray());
                    }
                    break;
                case MethodSlotType.Virtual:
                    {
                        HighSsaRegister instanceReg;
                        HighSsaRegister thisReg = new HighSsaRegister(HighValueType.ReferenceValue, m_dt, null);
                        instrs.Add(new Rpa.Instructions.LoadLocalInstruction(null, thisReg, thisLocal));

                        if (compiler.TypeIsValueType(methodSpec.DeclaringClass))
                        {
                            HighSsaRegister boxedReg = new HighSsaRegister(HighValueType.BoxedValue, methodSpec.DeclaringClass, null);
                            instrs.Add(new Instructions.LoadDelegateTargetInstruction(null, boxedReg, thisReg));
                            instanceReg = new HighSsaRegister(HighValueType.ManagedPtr, methodSpec.DeclaringClass, null);
                            instrs.Add(new Rpa.Instructions.UnboxPtrInstruction(null, instanceReg, boxedReg));
                        }
                        else
                        {
                            instanceReg = new HighSsaRegister(HighValueType.BoxedValue, methodSpec.DeclaringClass, null);
                            instrs.Add(new Instructions.LoadDelegateTargetInstruction(null, instanceReg, thisReg));
                        }

                        if (isInterface)
                        {
                            uint cliSlot = targetIfc.CliSlotForSlotTag(methodSpec.MethodDecl);
                            callInstr = new Instructions.CallRloInterfaceMethodInstruction(null, cliSlot, methodReturnValue, instanceReg, convertedParameters.ToArray());
                        }
                        else
                        {
                            uint targetVtableSlot = targetCls.DeclTagToVTableSlot[methodSpec.MethodDecl];
                            callInstr = new Instructions.CallRloVirtualMethodInstruction(null, targetVtableSlot, methodReturnValue, instanceReg, convertedParameters.ToArray());
                        }
                    }
                    break;
                case MethodSlotType.Static:
                    {
                        MethodHandle methodHandle = compiler.InstantiateMethod(new MethodSpecMethodKey(methodSpec), instantiationPath);
                        callInstr = new Instructions.CallRloStaticMethodInstruction(null, methodHandle, methodReturnValue, convertedParameters.ToArray());
                    }
                    break;
                default:
                    throw new Exception();
            }

            List<HighInstruction> returnInstrs = new List<HighInstruction>();

            if (methodReturnValue == null)
            {
                if (!(delegateMethodSignature.RetType is TypeSpecVoidTag))
                    throw new RpaCompileException("Delegate return type mismatch");

                returnInstrs.Add(new Rpa.Instructions.ReturnInstruction(null));
            }
            else
            {
                if (delegateMethodSignature.RetType is TypeSpecVoidTag)
                    throw new RpaCompileException("Delegate return type mismatch");

                TypeSpecTag delegateRetType = delegateMethodSignature.RetType;
                TypeSpecTag targetRetType = targetMethodSignature.RetType;

                if (delegateMethodSignature.RetType == targetMethodSignature.RetType)
                    returnInstrs.Add(new Rpa.Instructions.ReturnValueInstruction(null, methodReturnValue));
                else
                {
                    if (compiler.TypeIsValueType(targetRetType) || compiler.TypeIsValueType(delegateRetType))
                        throw new RpaCompileException("Delegate return type mismatch");

                    HighSsaRegister retReg = GenerateConvertReference(compiler, methodReturnValue, delegateRetType, returnInstrs);
                    returnInstrs.Add(new Rpa.Instructions.ReturnValueInstruction(null, retReg));
                }
            }

            HighCfgNode returnNode = new HighCfgNode(returnInstrs.ToArray());

            callInstr.ContinuationEdge = new HighCfgEdge(callInstr, new HighCfgNodeHandle(returnNode));
            instrs.Add(callInstr);

            HighCfgNode entryNode = new HighCfgNode(instrs.ToArray());
            HighRegion region = new HighRegion(new HighCfgNodeHandle(entryNode));
            RloMethodBody methodBody = new RloMethodBody(thisLocal, args.ToArray(), locals, delegateMethodSignature.RetType, region, delegateMethodSignature, instantiationPath);

            return new RloMethod(methodBody);
        }
コード例 #14
0
ファイル: CppRegionEmitter.cs プロジェクト: elasota/clarity
        private void EmitCfgNode(CfgNode cfgNode)
        {
            // Build predecessor list
            List<CppTranslatedOutboundEdge> predecessorEdges = new List<CppTranslatedOutboundEdge>();
            foreach (CfgNode pred in cfgNode.Predecessors)
            {
                // Find the successor edge
                CppTranslatedOutboundEdge edge = null;
                foreach (CfgOutboundEdge outEdge in pred.Successors)
                {
                    if (outEdge.SuccessorNode == cfgNode)
                    {
                        edge = InternOutboundEdge(pred, outEdge);
                        break;
                    }
                }

                if (edge == null)
                    throw new Exception("Mismatched CFG edge");

                predecessorEdges.Add(edge);
            }

            List<Clarity.Rpa.HighInstruction> outInstructions = new List<Clarity.Rpa.HighInstruction>();
            List<Clarity.Rpa.HighPhi> outPhis = new List<Clarity.Rpa.HighPhi>();

            Clarity.Rpa.HighCfgNodeHandle highNode = m_nodesToEmittedNodes[cfgNode];
            CppCfgNodeOutline outline = m_nodeOutlines[cfgNode];
            List<SsaRegister> leakedRegs = new List<SsaRegister>();

            int numContinuedRegs = 0;

            int debugInstrNum = -1;
            MidInstruction[] midInstrs = cfgNode.MidInstructions;

            bool fallthroughMerged = false;

            foreach (MidInstruction midInstr in midInstrs)
            {
                debugInstrNum++;
                switch (midInstr.Opcode)
                {
                    case MidInstruction.OpcodeEnum.AllocObject:
                        {
                            Clarity.Rpa.HighSsaRegister dest = InternSsaRegister(midInstr.RegArg);
                            Clarity.Rpa.TypeSpecTag type = RpaTagFactory.CreateTypeTag(midInstr.TypeSpecArg);
                            outInstructions.Add(new Clarity.Rpa.Instructions.AllocObjInstruction(midInstr.CodeLocation, dest, type));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.CallMethod:
                    case MidInstruction.OpcodeEnum.CallConstructor:
                    case MidInstruction.OpcodeEnum.ConstrainedCallMethod:
                        {
                            CppMethodSpec methodSpec = midInstr.MethodSpecArg;
                            CppMethod cppMethod = methodSpec.CppMethod;
                            CppClass thisClass = m_builder.GetCachedClass(cppMethod.DeclaredInClassSpec);

                            SsaRegister returnReg = midInstr.RegArg;
                            SsaRegister thisReg = midInstr.RegArg2;
                            List<Clarity.Rpa.HighSsaRegister> parameters = new List<Clarity.Rpa.HighSsaRegister>();

                            if (!cppMethod.MethodDef.Static && midInstr.Opcode != MidInstruction.OpcodeEnum.ConstrainedCallMethod)
                                thisReg = EmitPassiveConversion_PermitRefs(midInstr.CodeLocation, thisReg, cppMethod.DeclaredInClassSpec, outline, outInstructions);

                            // CLARITYTODO: Verify that this works with generic method parameters
                            for (int pIdx = 0; pIdx < midInstr.RegArgs.Length; pIdx++)
                            {
                                SsaRegister inReg = EmitPassiveConversion_PermitRefs(midInstr.CodeLocation, midInstr.RegArgs[pIdx], cppMethod.MethodSignature.ParamTypes[pIdx].Type, outline, outInstructions);
                                parameters.Add(InternSsaRegister(inReg));
                            }

                            Clarity.Rpa.HighSsaRegister outDestReg = null;

                            if (returnReg != null)
                                outDestReg = InternSsaRegister(returnReg);

                            Clarity.Rpa.TypeSpecTag constraintTag = null;

                            if (midInstr.Opcode == MidInstruction.OpcodeEnum.ConstrainedCallMethod)
                                constraintTag = RpaTagFactory.CreateTypeTag(midInstr.TypeSpecArg);

                            Clarity.Rpa.HighSsaRegister instanceReg = null;
                            if (!cppMethod.MethodDef.Static)
                                instanceReg = InternSsaRegister(thisReg);

                            CLR.CLRMethodSignatureInstance methodSig = cppMethod.MethodSignature;

                            int numParams = parameters.Count;
                            if (numParams != methodSig.ParamTypes.Length)
                                throw new Exception("Internal error: CallMethod param count mismatch");

                            if (midInstr.Opcode == MidInstruction.OpcodeEnum.CallMethod || midInstr.Opcode == MidInstruction.OpcodeEnum.CallConstructor)
                            {
                                if (cppMethod.MethodDef.Static)
                                {
                                    outInstructions.Add(new Clarity.Rpa.Instructions.CallStaticMethodInstruction(
                                        midInstr.CodeLocation,
                                        outDestReg,
                                        RpaTagFactory.CreateMethodSpec(Clarity.Rpa.MethodSlotType.Static, methodSpec),
                                        parameters.ToArray()
                                        ));
                                }
                                else
                                {
                                    outInstructions.Add(new Clarity.Rpa.Instructions.CallInstanceMethodInstruction(
                                        midInstr.CodeLocation,
                                        outDestReg,
                                        RpaTagFactory.CreateMethodSpec(Clarity.Rpa.MethodSlotType.Instance, methodSpec),
                                        instanceReg,
                                        parameters.ToArray()
                                        ));
                                }
                            }
                            else if (midInstr.Opcode == MidInstruction.OpcodeEnum.ConstrainedCallMethod)
                            {
                                outInstructions.Add(new Clarity.Rpa.Instructions.CallConstrainedMethodInstruction(
                                    midInstr.CodeLocation,
                                    outDestReg,
                                    constraintTag,
                                    RpaTagFactory.CreateMethodSpec(Clarity.Rpa.MethodSlotType.Instance, methodSpec),
                                    instanceReg,
                                    parameters.ToArray()
                                    ));
                            }
                        }
                        break;
                    case MidInstruction.OpcodeEnum.CallVirtualMethod:
                    case MidInstruction.OpcodeEnum.ConstrainedCallVirtualMethod:
                        {
                            CppMethodSpec methodSpec = midInstr.MethodSpecArg;
                            CppMethod cppMethod = methodSpec.CppMethod;
                            CppClass thisClass = m_builder.GetCachedClass(cppMethod.DeclaredInClassSpec);

                            Clarity.Rpa.HighSsaRegister returnReg = InternSsaRegister(midInstr.RegArg);
                            Clarity.Rpa.HighSsaRegister thisReg = null;
                            List<Clarity.Rpa.HighSsaRegister> paramRegs = new List<Clarity.Rpa.HighSsaRegister>();

                            if (midInstr.Opcode != MidInstruction.OpcodeEnum.ConstrainedCallVirtualMethod)
                                thisReg = InternSsaRegister(EmitPassiveConversion_PermitRefs(midInstr.CodeLocation, midInstr.RegArg2, cppMethod.DeclaredInClassSpec, outline, outInstructions));
                            else
                                thisReg = InternSsaRegister(midInstr.RegArg2);

                            for (int pIdx = 0; pIdx < midInstr.RegArgs.Length; pIdx++)
                                paramRegs.Add(InternSsaRegister(EmitPassiveConversion_PermitRefs(midInstr.CodeLocation, midInstr.RegArgs[pIdx], cppMethod.MethodSignature.ParamTypes[pIdx].Type, outline, outInstructions)));

                            CppVtableSlot vtableSlot = cppMethod.CreatesSlot;
                            if (vtableSlot == null)
                                vtableSlot = cppMethod.ReplacesStandardSlot;
                            if (vtableSlot == null)
                                throw new Exception("Internal error: Couldn't resolve vtable slot for method");

                            Clarity.Rpa.TypeSpecTag constraintType = null;
                            if (midInstr.Opcode == MidInstruction.OpcodeEnum.ConstrainedCallVirtualMethod)
                                constraintType = RpaTagFactory.CreateTypeTag(midInstr.TypeSpecArg);

                            if (cppMethod.MethodDef.Static)
                                throw new Exception();

                            CLR.CLRMethodSignatureInstance methodSig = cppMethod.MethodSignature;

                            int numParams = paramRegs.Count;
                            if (numParams != methodSig.ParamTypes.Length)
                                throw new Exception("Internal error: CallMethod param count mismatch");

                            if (midInstr.Opcode == MidInstruction.OpcodeEnum.CallVirtualMethod)
                            {
                                outInstructions.Add(new Clarity.Rpa.Instructions.CallVirtualMethodInstruction(
                                    midInstr.CodeLocation,
                                    returnReg,
                                    RpaTagFactory.CreateMethodSpec(Clarity.Rpa.MethodSlotType.Virtual, methodSpec),
                                    thisReg,
                                    paramRegs.ToArray()
                                ));
                            }
                            else if (midInstr.Opcode == MidInstruction.OpcodeEnum.ConstrainedCallVirtualMethod)
                                outInstructions.Add(new Clarity.Rpa.Instructions.CallConstrainedVirtualMethodInstruction(
                                    midInstr.CodeLocation,
                                    returnReg,
                                    constraintType,
                                    RpaTagFactory.CreateMethodSpec(Clarity.Rpa.MethodSlotType.Virtual, methodSpec),
                                    thisReg,
                                    paramRegs.ToArray()
                                    ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.KillReg:
                        break;
                    case MidInstruction.OpcodeEnum.LivenReg:
                        {
                            SsaRegister reg = midInstr.RegArg;
                            reg.GenerateUniqueID(m_regAllocator);
                            reg.MakeUsable();
                        }
                        break;
                    case MidInstruction.OpcodeEnum.Return:
                        outInstructions.Add(new Clarity.Rpa.Instructions.ReturnInstruction(midInstr.CodeLocation));
                        break;
                    case MidInstruction.OpcodeEnum.ReturnValue:
                        {
                            SsaRegister returnRegister = EmitPassiveConversion(midInstr.CodeLocation, midInstr.RegArg, midInstr.TypeSpecArg, outline, outInstructions);

                            outInstructions.Add(new Clarity.Rpa.Instructions.ReturnValueInstruction(
                                midInstr.CodeLocation,
                                InternSsaRegister(returnRegister)));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.LoadReg_ManagedPtr:
                        {
                            Clarity.Rpa.HighLocal lcl = m_localLookup[midInstr.VRegArg];
                            Clarity.Rpa.HighSsaRegister dest = InternSsaRegister(midInstr.RegArg);
                            outInstructions.Add(new Clarity.Rpa.Instructions.LoadLocalInstruction(
                                midInstr.CodeLocation,
                                dest,
                                lcl
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.LoadReg_Value:
                        {
                            CLR.CLRTypeSpec srcSpec = midInstr.VRegArg.VType.TypeSpec;
                            CLR.CLRTypeSpec destSpec = midInstr.RegArg.VType.TypeSpec;
                            if (srcSpec.Equals(destSpec))
                            {
                                outInstructions.Add(new Clarity.Rpa.Instructions.LoadLocalInstruction(
                                    midInstr.CodeLocation,
                                    InternSsaRegister(midInstr.RegArg),
                                    m_localLookup[midInstr.VRegArg]
                                    ));
                            }
                            else
                            {
                                SsaRegister tempReg = new SsaRegister(midInstr.VRegArg.VType);
                                tempReg.MakeUsable();
                                tempReg.GenerateUniqueID(m_regAllocator);

                                outline.AddRegister(tempReg);

                                outInstructions.Add(new Clarity.Rpa.Instructions.LoadLocalInstruction(
                                    midInstr.CodeLocation,
                                    InternSsaRegister(tempReg),
                                    m_localLookup[midInstr.VRegArg]
                                    ));

                                outInstructions.Add(new Clarity.Rpa.Instructions.PassiveConvertInstruction(
                                    midInstr.CodeLocation,
                                    InternSsaRegister(midInstr.RegArg),
                                    InternSsaRegister(tempReg)
                                    ));
                            }
                        }
                        break;
                    case MidInstruction.OpcodeEnum.StoreReg_ManagedPtr:
                        outInstructions.Add(new Clarity.Rpa.Instructions.StoreLocalInstruction(
                            midInstr.CodeLocation,
                            m_localLookup[midInstr.VRegArg],
                            InternSsaRegister(midInstr.RegArg)
                            ));
                        break;
                    case MidInstruction.OpcodeEnum.StoreReg_Value:
                        {
                            SsaRegister srcReg = EmitPassiveConversion(midInstr.CodeLocation, midInstr.RegArg, midInstr.VRegArg.VType.TypeSpec, outline, outInstructions);

                            outInstructions.Add(new Clarity.Rpa.Instructions.StoreLocalInstruction(
                                midInstr.CodeLocation,
                                m_localLookup[midInstr.VRegArg],
                                InternSsaRegister(srcReg)
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.beq_ref:
                    case MidInstruction.OpcodeEnum.bne_ref:
                        {
                            fallthroughMerged = true;
                            CppTranslatedOutboundEdge edgeA = InternOutboundEdge(cfgNode, midInstr.CfgEdgeArg);
                            CppTranslatedOutboundEdge edgeB = InternOutboundEdge(cfgNode, cfgNode.FallThroughEdge);

                            CppTranslatedOutboundEdge trueEdge, falseEdge;
                            if (midInstr.Opcode == MidInstruction.OpcodeEnum.beq_ref)
                            {
                                trueEdge = edgeA;
                                falseEdge = edgeB;
                            }
                            else if (midInstr.Opcode == MidInstruction.OpcodeEnum.bne_ref)
                            {
                                trueEdge = edgeB;
                                falseEdge = edgeA;
                            }
                            else
                                throw new Exception();

                            Clarity.Rpa.HighSsaRegister regA = InternSsaRegister(midInstr.RegArg);
                            Clarity.Rpa.HighSsaRegister regB = InternSsaRegister(midInstr.RegArg2);

                            outInstructions.Add(new Clarity.Rpa.Instructions.BranchCompareRefsInstruction(midInstr.CodeLocation, regA, regB, trueEdge.NextNode, falseEdge.NextNode));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.cne_ref:
                    case MidInstruction.OpcodeEnum.ceq_ref:
                        {
                            int trueValue, falseValue;
                            Clarity.Rpa.HighSsaRegister destReg = InternSsaRegister(midInstr.RegArg);

                            if (midInstr.Opcode == MidInstruction.OpcodeEnum.ceq_ref)
                            {
                                trueValue = 1;
                                falseValue = 0;
                            }
                            else if (midInstr.Opcode == MidInstruction.OpcodeEnum.cne_ref)
                            {
                                trueValue = 0;
                                falseValue = 1;
                            }
                            else
                                throw new Exception();

                            Clarity.Rpa.HighSsaRegister regA = InternSsaRegister(midInstr.RegArg2);
                            Clarity.Rpa.HighSsaRegister regB = InternSsaRegister(midInstr.RegArg3);

                            outInstructions.Add(new Clarity.Rpa.Instructions.CompareRefsInstruction(midInstr.CodeLocation, destReg, regA, regB, trueValue, falseValue));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.beq_val:
                    case MidInstruction.OpcodeEnum.bne_val:
                    case MidInstruction.OpcodeEnum.bge:
                    case MidInstruction.OpcodeEnum.bgt:
                    case MidInstruction.OpcodeEnum.ble:
                    case MidInstruction.OpcodeEnum.blt:
                    case MidInstruction.OpcodeEnum.clt:
                    case MidInstruction.OpcodeEnum.cgt:
                    case MidInstruction.OpcodeEnum.ceq_numeric:
                        {
                            bool isBranch;
                            SsaRegister leftReg, rightReg;

                            switch (midInstr.Opcode)
                            {
                                case MidInstruction.OpcodeEnum.beq_val:
                                case MidInstruction.OpcodeEnum.bne_val:
                                case MidInstruction.OpcodeEnum.bge:
                                case MidInstruction.OpcodeEnum.bgt:
                                case MidInstruction.OpcodeEnum.ble:
                                case MidInstruction.OpcodeEnum.blt:
                                    isBranch = true;
                                    leftReg = midInstr.RegArg;
                                    rightReg = midInstr.RegArg2;
                                    break;
                                case MidInstruction.OpcodeEnum.clt:
                                case MidInstruction.OpcodeEnum.cgt:
                                case MidInstruction.OpcodeEnum.ceq_numeric:
                                    isBranch = false;
                                    leftReg = midInstr.RegArg2;
                                    rightReg = midInstr.RegArg3;
                                    break;
                                default:
                                    throw new Exception();
                            }

                            bool isUnsigned = midInstr.FlagArg;
                            bool isReversed = false;

                            NumericStackType nst = NumericStackTypeForNumericBinaryOp(leftReg, rightReg);

                            if (isUnsigned && (nst == NumericStackType.Float32 || nst == NumericStackType.Float64))
                            {
                                isUnsigned = false;
                                isReversed = true;
                            }

                            CLR.CLRTypeSpec comparisonSpec = this.TypeSpecForNumericBinaryOp(leftReg, rightReg, isUnsigned);

                            Clarity.Rpa.HighSsaRegister leftHighReg = InternSsaRegister(EmitPassiveConversion(midInstr.CodeLocation, leftReg, comparisonSpec, outline, outInstructions));
                            Clarity.Rpa.HighSsaRegister rightHighReg = InternSsaRegister(EmitPassiveConversion(midInstr.CodeLocation, rightReg, comparisonSpec, outline, outInstructions));

                            Clarity.Rpa.Instructions.NumberCompareOperation op;

                            switch (midInstr.Opcode)
                            {
                                case MidInstruction.OpcodeEnum.blt:
                                case MidInstruction.OpcodeEnum.clt:
                                    op = isReversed ?
                                        Clarity.Rpa.Instructions.NumberCompareOperation.GreaterOrEqual :
                                        Clarity.Rpa.Instructions.NumberCompareOperation.LessThan;
                                    break;
                                case MidInstruction.OpcodeEnum.bgt:
                                case MidInstruction.OpcodeEnum.cgt:
                                    op = isReversed ?
                                        Clarity.Rpa.Instructions.NumberCompareOperation.LessOrEqual :
                                        Clarity.Rpa.Instructions.NumberCompareOperation.GreaterThan;
                                    break;
                                case MidInstruction.OpcodeEnum.ble:
                                    op = isReversed ?
                                        Clarity.Rpa.Instructions.NumberCompareOperation.GreaterThan :
                                        Clarity.Rpa.Instructions.NumberCompareOperation.LessOrEqual;
                                    break;
                                case MidInstruction.OpcodeEnum.bge:
                                    op = isReversed ?
                                        Clarity.Rpa.Instructions.NumberCompareOperation.LessThan :
                                        Clarity.Rpa.Instructions.NumberCompareOperation.GreaterOrEqual;
                                    break;
                                case MidInstruction.OpcodeEnum.beq_val:
                                case MidInstruction.OpcodeEnum.ceq_numeric:
                                    op = isReversed ?
                                        Clarity.Rpa.Instructions.NumberCompareOperation.NotEqual :
                                        Clarity.Rpa.Instructions.NumberCompareOperation.Equal;
                                    break;
                                case MidInstruction.OpcodeEnum.bne_val:
                                    op = isReversed ?
                                        Clarity.Rpa.Instructions.NumberCompareOperation.Equal :
                                        Clarity.Rpa.Instructions.NumberCompareOperation.NotEqual;
                                    break;
                                default:
                                    throw new ArgumentException();
                            }

                            Clarity.Rpa.Instructions.NumberArithType numType;

                            switch (nst)
                            {
                                case NumericStackType.Float32:
                                    numType = Clarity.Rpa.Instructions.NumberArithType.Float32;
                                    break;
                                case NumericStackType.Float64:
                                    numType = Clarity.Rpa.Instructions.NumberArithType.Float64;
                                    break;
                                case NumericStackType.Int32:
                                    numType = isUnsigned ?
                                        Clarity.Rpa.Instructions.NumberArithType.UInt32 :
                                        Clarity.Rpa.Instructions.NumberArithType.Int32;
                                    break;
                                case NumericStackType.Int64:
                                    numType = isUnsigned ?
                                        Clarity.Rpa.Instructions.NumberArithType.UInt64 :
                                        Clarity.Rpa.Instructions.NumberArithType.Int64;
                                    break;
                                case NumericStackType.NativeInt:
                                    numType = isUnsigned ?
                                        Clarity.Rpa.Instructions.NumberArithType.NativeUInt :
                                        Clarity.Rpa.Instructions.NumberArithType.NativeInt;
                                    break;
                                default:
                                    throw new ArgumentException();
                            }

                            if (isBranch)
                            {
                                fallthroughMerged = true;
                                CppTranslatedOutboundEdge trueEdge = InternOutboundEdge(cfgNode, midInstr.CfgEdgeArg);
                                CppTranslatedOutboundEdge falseEdge = InternOutboundEdge(cfgNode, cfgNode.FallThroughEdge);

                                if (isReversed)
                                {
                                    CppTranslatedOutboundEdge temp = trueEdge;
                                    trueEdge = falseEdge;
                                    falseEdge = temp;
                                }

                                outInstructions.Add(new Clarity.Rpa.Instructions.BranchCompareNumbersInstruction(
                                    midInstr.CodeLocation,
                                    op,
                                    numType,
                                    leftHighReg,
                                    rightHighReg,
                                    trueEdge.NextNode,
                                    falseEdge.NextNode
                                    ));
                            }
                            else
                            {
                                int trueValue = 0;
                                int falseValue = 1;

                                if (isReversed)
                                {
                                    trueValue = 0;
                                    falseValue = 1;
                                }

                                Clarity.Rpa.HighSsaRegister destReg = InternSsaRegister(midInstr.RegArg);

                                outInstructions.Add(new Clarity.Rpa.Instructions.CompareNumbersInstruction(
                                midInstr.CodeLocation,
                                    destReg,
                                    op,
                                    numType,
                                    leftHighReg,
                                    rightHighReg,
                                    trueValue,
                                    falseValue
                                    ));
                            }
                        }
                        break;
                    case MidInstruction.OpcodeEnum.LoadArgA_Value:
                        {
                            Clarity.Rpa.HighSsaRegister dest = InternSsaRegister(midInstr.RegArg);
                            Clarity.Rpa.HighLocal src = m_localLookup[midInstr.VRegArg];

                            outInstructions.Add(new Clarity.Rpa.Instructions.GetLocalPtrInstruction(
                                midInstr.CodeLocation,
                                dest,
                                src
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.brzero:
                    case MidInstruction.OpcodeEnum.brnotzero:
                        {
                            SsaRegister inReg = midInstr.RegArg;
                            CLR.CLRTypeSpec targetType;
                            object zeroValue;

                            CLR.CLRTypeSpecClass cls = (CLR.CLRTypeSpecClass)inReg.VType.TypeSpec;
                            string typeName = cls.TypeDef.TypeName;
                            Clarity.Rpa.Instructions.NumberArithType arithType;

                            if (typeName == "Char" || typeName == "Boolean" ||
                                typeName == "Byte" || typeName == "UInt16" ||
                                typeName == "UInt32")
                            {
                                targetType = TypeSpecForNumericStackType(NumericStackType.Int32, true);
                                zeroValue = (uint)0;
                                arithType = Clarity.Rpa.Instructions.NumberArithType.UInt32;
                            }
                            else if (typeName == "SByte" || typeName == "Int16" || typeName == "Int32")
                            {
                                targetType = TypeSpecForNumericStackType(NumericStackType.Int32, false);
                                zeroValue = (int)0;
                                arithType = Clarity.Rpa.Instructions.NumberArithType.Int32;
                            }
                            else if (typeName == "UInt64")
                            {
                                targetType = TypeSpecForNumericStackType(NumericStackType.Int64, true);
                                zeroValue = (ulong)0;
                                arithType = Clarity.Rpa.Instructions.NumberArithType.UInt64;
                            }
                            else if (typeName == "Int64")
                            {
                                targetType = TypeSpecForNumericStackType(NumericStackType.Int64, false);
                                zeroValue = (long)0;
                                arithType = Clarity.Rpa.Instructions.NumberArithType.Int64;
                            }
                            else if (typeName == "IntPtr")
                            {
                                targetType = TypeSpecForNumericStackType(NumericStackType.NativeInt, false);
                                zeroValue = (long)0;
                                arithType = Clarity.Rpa.Instructions.NumberArithType.NativeInt;
                            }
                            else if (typeName == "UIntPtr")
                            {
                                targetType = TypeSpecForNumericStackType(NumericStackType.NativeInt, true);
                                zeroValue = (ulong)0;
                                arithType = Clarity.Rpa.Instructions.NumberArithType.NativeUInt;
                            }
                            else if (typeName == "Single")
                            {
                                targetType = TypeSpecForNumericStackType(NumericStackType.Float32, false);
                                zeroValue = (float)0;
                                arithType = Clarity.Rpa.Instructions.NumberArithType.Float32;
                            }
                            else if (typeName == "Double")
                            {
                                targetType = TypeSpecForNumericStackType(NumericStackType.Float64, false);
                                zeroValue = (double)0;
                                arithType = Clarity.Rpa.Instructions.NumberArithType.Float64;
                            }
                            else
                                throw new Exception();

                            fallthroughMerged = true;
                            CppTranslatedOutboundEdge trueEdge = InternOutboundEdge(cfgNode, midInstr.CfgEdgeArg);
                            CppTranslatedOutboundEdge falseEdge = InternOutboundEdge(cfgNode, cfgNode.FallThroughEdge);

                            Clarity.Rpa.Instructions.NumberCompareOperation compareOp;
                            if (midInstr.Opcode == MidInstruction.OpcodeEnum.brzero)
                                compareOp = Clarity.Rpa.Instructions.NumberCompareOperation.Equal;
                            else if (midInstr.Opcode == MidInstruction.OpcodeEnum.brnotzero)
                                compareOp = Clarity.Rpa.Instructions.NumberCompareOperation.NotEqual;
                            else
                                throw new Exception();

                            SsaRegister converted = EmitPassiveConversion(midInstr.CodeLocation, inReg, targetType, outline, outInstructions);
                            Clarity.Rpa.TypeSpecTag typeTag = RpaTagFactory.CreateTypeTag(targetType);

                            outInstructions.Add(new Clarity.Rpa.Instructions.BranchCompareNumbersInstruction(
                                midInstr.CodeLocation,
                                compareOp,
                                arithType,
                                InternSsaRegister(converted),
                                new Clarity.Rpa.HighSsaRegister(Clarity.Rpa.HighValueType.ConstantValue, typeTag, zeroValue),
                                trueEdge.NextNode,
                                falseEdge.NextNode
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.brnull:
                    case MidInstruction.OpcodeEnum.brnotnull:
                        {
                            fallthroughMerged = true;
                            CppTranslatedOutboundEdge isNullEdge = InternOutboundEdge(cfgNode, midInstr.CfgEdgeArg);
                            CppTranslatedOutboundEdge isNotNullEdge = InternOutboundEdge(cfgNode, cfgNode.FallThroughEdge);

                            if (midInstr.Opcode == MidInstruction.OpcodeEnum.brnotnull)
                            {
                                CppTranslatedOutboundEdge temp = isNullEdge;
                                isNullEdge = isNotNullEdge;
                                isNotNullEdge = temp;
                            }

                            outInstructions.Add(new Clarity.Rpa.Instructions.BranchRefNullInstruction(
                                midInstr.CodeLocation,
                                InternSsaRegister(midInstr.RegArg),
                                isNullEdge.NextNode,
                                isNotNullEdge.NextNode
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.LeakReg:
                        {
                            leakedRegs.Add(midInstr.RegArg);
                        }
                        break;
                    case MidInstruction.OpcodeEnum.EntryReg:
                        {
                            SsaRegister reg = midInstr.RegArg;

                            reg.GenerateUniqueID(m_regAllocator);
                            reg.MakeUsable();

                            Clarity.Rpa.HighSsaRegister destReg = InternSsaRegister(reg);

                            // Blocks can have constants on entry if all predecessors have the same value
                            if (!destReg.IsConstant)
                            {
                                List<Clarity.Rpa.HighPhiLink> phiLinks = new List<Clarity.Rpa.HighPhiLink>();

                                foreach (CppTranslatedOutboundEdge predEdge in predecessorEdges)
                                    phiLinks.Add(new Clarity.Rpa.HighPhiLink(predEdge.PrevNode, predEdge.Regs[numContinuedRegs]));

                                outPhis.Add(new Clarity.Rpa.HighPhi(
                                    InternSsaRegister(reg),
                                    phiLinks.ToArray()
                                    ));
                            }

                            numContinuedRegs++;
                        }
                        break;
                    case MidInstruction.OpcodeEnum.Throw:
                        {
                            CLR.CLRTypeSpec objSpec = m_builder.Assemblies.InternVagueType(new CLR.CLRSigTypeSimple(CLR.CLRSigType.ElementType.OBJECT));

                            SsaRegister converted = EmitPassiveConversion(midInstr.CodeLocation, midInstr.RegArg, objSpec, outline, outInstructions);

                            outInstructions.Add(new Clarity.Rpa.Instructions.ThrowInstruction(
                                    midInstr.CodeLocation,
                                    InternSsaRegister(converted)
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.NewSZArray:
                        {
                            NumericStackType indexNst = StackTypeForTypeSpec(midInstr.RegArg2.VType.TypeSpec);

                            CLR.CLRTypeSpec indexSpec = m_builder.Assemblies.InternVagueType(new CLR.CLRSigTypeSimple(CLR.CLRSigType.ElementType.I));

                            SsaRegister indexReg = EmitPassiveConversion(midInstr.CodeLocation, midInstr.RegArg2, indexSpec, outline, outInstructions);

                            outInstructions.Add(new Clarity.Rpa.Instructions.AllocArrayInstruction(
                                midInstr.CodeLocation,
                                    InternSsaRegister(midInstr.RegArg),
                                    new Clarity.Rpa.HighSsaRegister[] { InternSsaRegister(indexReg) },
                                    RpaTagFactory.CreateTypeTag(midInstr.RegArg2.VType.TypeSpec)
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.LoadField_ManagedPtr:
                        {
                            Clarity.Rpa.HighSsaRegister destReg = InternSsaRegister(midInstr.RegArg2);
                            Clarity.Rpa.HighSsaRegister objReg = InternSsaRegister(midInstr.RegArg);
                            Clarity.Rpa.HighSsaRegister addrReg = new Clarity.Rpa.HighSsaRegister(Clarity.Rpa.HighValueType.ManagedPtr, destReg.Type, null);

                            outInstructions.Add(new Clarity.Rpa.Instructions.PtrFieldInstruction(
                                midInstr.CodeLocation,
                                addrReg,
                                objReg,
                                midInstr.StrArg
                                ));
                            outInstructions.Add(new Clarity.Rpa.Instructions.LoadPtrInstruction(
                                midInstr.CodeLocation,
                                destReg,
                                addrReg
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.LoadFieldA_ManagedPtr:
                        {
                            Clarity.Rpa.HighSsaRegister destReg = InternSsaRegister(midInstr.RegArg2);
                            Clarity.Rpa.HighSsaRegister objReg = InternSsaRegister(midInstr.RegArg);

                            outInstructions.Add(new Clarity.Rpa.Instructions.PtrFieldInstruction(
                                midInstr.CodeLocation,
                                destReg,
                                objReg,
                                midInstr.StrArg
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.LoadField_Object:
                        {
                            Clarity.Rpa.HighSsaRegister destReg = InternSsaRegister(midInstr.RegArg2);
                            Clarity.Rpa.HighSsaRegister objReg = InternSsaRegister(EmitPassiveConversion(midInstr.CodeLocation, midInstr.RegArg, midInstr.TypeSpecArg, outline, outInstructions));
                            Clarity.Rpa.HighSsaRegister addrReg = new Clarity.Rpa.HighSsaRegister(Clarity.Rpa.HighValueType.ManagedPtr, destReg.Type, null);

                            outInstructions.Add(new Clarity.Rpa.Instructions.RefFieldInstruction(
                                midInstr.CodeLocation,
                                addrReg,
                                objReg,
                                midInstr.StrArg,
                                RpaTagFactory.CreateTypeTag(midInstr.TypeSpecArg)
                                ));
                            outInstructions.Add(new Clarity.Rpa.Instructions.LoadPtrInstruction(
                                midInstr.CodeLocation,
                                destReg,
                                addrReg
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.LoadFieldA_Object:
                        {
                            Clarity.Rpa.HighSsaRegister destReg = InternSsaRegister(midInstr.RegArg2);
                            Clarity.Rpa.HighSsaRegister objReg = InternSsaRegister(EmitPassiveConversion(midInstr.CodeLocation, midInstr.RegArg, midInstr.TypeSpecArg, outline, outInstructions));

                            outInstructions.Add(new Clarity.Rpa.Instructions.RefFieldInstruction(
                                midInstr.CodeLocation,
                                destReg,
                                objReg,
                                midInstr.StrArg,
                                RpaTagFactory.CreateTypeTag(midInstr.TypeSpecArg)
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.LoadField_Value:
                        {
                            Clarity.Rpa.HighSsaRegister destReg = InternSsaRegister(midInstr.RegArg2);
                            Clarity.Rpa.HighSsaRegister objReg = InternSsaRegister(midInstr.RegArg);

                            outInstructions.Add(new Clarity.Rpa.Instructions.LoadValueFieldInstruction(
                                midInstr.CodeLocation,
                                destReg,
                                objReg,
                                midInstr.StrArg
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.LoadRegA:
                        {
                            Clarity.Rpa.HighLocal local = m_localLookup[midInstr.VRegArg];
                            Clarity.Rpa.HighSsaRegister dest = InternSsaRegister(midInstr.RegArg);

                            outInstructions.Add(new Clarity.Rpa.Instructions.GetLocalPtrInstruction(
                                midInstr.CodeLocation,
                                InternSsaRegister(midInstr.RegArg),
                                m_localLookup[midInstr.VRegArg]
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.LoadArrayElem:
                        {
                            CLR.CLRTypeSpec indexSpec = m_builder.Assemblies.InternVagueType(new CLR.CLRSigTypeSimple(CLR.CLRSigType.ElementType.I));
                            Clarity.Rpa.HighSsaRegister arrayReg = InternSsaRegister(midInstr.RegArg);
                            Clarity.Rpa.HighSsaRegister indexReg = InternSsaRegister(EmitPassiveConversion(midInstr.CodeLocation, midInstr.RegArg2, indexSpec, outline, outInstructions));
                            Clarity.Rpa.HighSsaRegister destReg = InternSsaRegister(midInstr.RegArg3);
                            Clarity.Rpa.HighSsaRegister addrReg = new Clarity.Rpa.HighSsaRegister(Clarity.Rpa.HighValueType.ManagedPtr, destReg.Type, null);

                            outInstructions.Add(new Clarity.Rpa.Instructions.GetArrayElementPtrInstruction(
                                midInstr.CodeLocation,
                                addrReg,
                                arrayReg,
                                new Clarity.Rpa.HighSsaRegister[] { indexReg }
                                ));
                            outInstructions.Add(new Clarity.Rpa.Instructions.LoadPtrInstruction(
                                midInstr.CodeLocation,
                                destReg,
                                addrReg
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.LoadArrayElemAddr:
                        {
                            CLR.CLRTypeSpec indexSpec = m_builder.Assemblies.InternVagueType(new CLR.CLRSigTypeSimple(CLR.CLRSigType.ElementType.I));
                            Clarity.Rpa.HighSsaRegister arrayReg = InternSsaRegister(midInstr.RegArg);
                            Clarity.Rpa.HighSsaRegister indexReg = InternSsaRegister(EmitPassiveConversion(midInstr.CodeLocation, midInstr.RegArg2, indexSpec, outline, outInstructions));
                            Clarity.Rpa.HighSsaRegister destReg = InternSsaRegister(midInstr.RegArg3);

                            outInstructions.Add(new Clarity.Rpa.Instructions.GetArrayElementPtrInstruction(
                                midInstr.CodeLocation,
                                destReg,
                                arrayReg,
                                new Clarity.Rpa.HighSsaRegister[] { indexReg }
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.StoreField_ManagedPtr:
                        {
                            Clarity.Rpa.HighSsaRegister objReg = InternSsaRegister(midInstr.RegArg);
                            Clarity.Rpa.HighSsaRegister valueReg = InternSsaRegister(EmitPassiveConversion(midInstr.CodeLocation, midInstr.RegArg2, midInstr.TypeSpecArg2, outline, outInstructions));
                            Clarity.Rpa.HighSsaRegister addrReg = new Clarity.Rpa.HighSsaRegister(Clarity.Rpa.HighValueType.ManagedPtr, valueReg.Type, null);

                            outInstructions.Add(new Clarity.Rpa.Instructions.PtrFieldInstruction(
                                midInstr.CodeLocation,
                                addrReg,
                                objReg,
                                midInstr.StrArg));
                            outInstructions.Add(new Clarity.Rpa.Instructions.StorePtrInstruction(
                                midInstr.CodeLocation,
                                addrReg,
                                valueReg
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.StoreField_Object:
                        {
                            Clarity.Rpa.HighSsaRegister objReg = InternSsaRegister(EmitPassiveConversion(midInstr.CodeLocation, midInstr.RegArg, midInstr.TypeSpecArg, outline, outInstructions));
                            Clarity.Rpa.HighSsaRegister valueReg = InternSsaRegister(EmitPassiveConversion(midInstr.CodeLocation, midInstr.RegArg2, midInstr.TypeSpecArg2, outline, outInstructions));
                            Clarity.Rpa.HighSsaRegister addrReg = new Clarity.Rpa.HighSsaRegister(Clarity.Rpa.HighValueType.ManagedPtr, valueReg.Type, null);

                            outInstructions.Add(new Clarity.Rpa.Instructions.RefFieldInstruction(
                                midInstr.CodeLocation,
                                addrReg,
                                objReg,
                                midInstr.StrArg,
                                RpaTagFactory.CreateTypeTag(midInstr.TypeSpecArg)
                                ));
                            outInstructions.Add(new Clarity.Rpa.Instructions.StorePtrInstruction(
                                midInstr.CodeLocation,
                                addrReg,
                                valueReg
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.add:
                    case MidInstruction.OpcodeEnum.sub:
                    case MidInstruction.OpcodeEnum.mul:
                    case MidInstruction.OpcodeEnum.div:
                    case MidInstruction.OpcodeEnum.rem:
                    case MidInstruction.OpcodeEnum.and:
                    case MidInstruction.OpcodeEnum.or:
                    case MidInstruction.OpcodeEnum.xor:
                    case MidInstruction.OpcodeEnum.shl:
                    case MidInstruction.OpcodeEnum.shr: // [.un]
                        {
                            bool isUnsigned = (midInstr.ArithArg & MidInstruction.ArithEnum.Flags_Un) != 0;
                            bool isOvf = (midInstr.ArithArg & MidInstruction.ArithEnum.Flags_Ovf) != 0;
                            NumericStackType nst = NumericStackTypeForNumericBinaryOp(midInstr.RegArg, midInstr.RegArg2);

                            Clarity.Rpa.Instructions.NumberArithType arithType;

                            switch(nst)
                            {
                                case NumericStackType.Float32:
                                    arithType = Clarity.Rpa.Instructions.NumberArithType.Float32;
                                    break;
                                case NumericStackType.Float64:
                                    arithType = Clarity.Rpa.Instructions.NumberArithType.Float64;
                                    break;
                                case NumericStackType.Int32:
                                    arithType = isUnsigned ? Clarity.Rpa.Instructions.NumberArithType.UInt32 : Clarity.Rpa.Instructions.NumberArithType.Int32;
                                    break;
                                case NumericStackType.Int64:
                                    arithType = isUnsigned ? Clarity.Rpa.Instructions.NumberArithType.UInt64 : Clarity.Rpa.Instructions.NumberArithType.Int64;
                                    break;
                                case NumericStackType.NativeInt:
                                    arithType = isUnsigned ? Clarity.Rpa.Instructions.NumberArithType.NativeUInt : Clarity.Rpa.Instructions.NumberArithType.NativeInt;
                                    break;
                                default:
                                    throw new ArgumentException();
                            }

                            CLR.CLRTypeSpec opSpec = TypeSpecForNumericStackType(nst, isUnsigned);

                            Clarity.Rpa.Instructions.NumberArithOp arithOp;
                            bool canThrow = isOvf;
                            switch (midInstr.Opcode)
                            {
                                case MidInstruction.OpcodeEnum.add:
                                    arithOp = Clarity.Rpa.Instructions.NumberArithOp.Add;
                                    break;
                                case MidInstruction.OpcodeEnum.sub:
                                    arithOp = Clarity.Rpa.Instructions.NumberArithOp.Subtract;
                                    break;
                                case MidInstruction.OpcodeEnum.mul:
                                    arithOp = Clarity.Rpa.Instructions.NumberArithOp.Multiply;
                                    break;
                                case MidInstruction.OpcodeEnum.div:
                                    arithOp = Clarity.Rpa.Instructions.NumberArithOp.Divide;
                                    break;
                                case MidInstruction.OpcodeEnum.rem:
                                    arithOp = Clarity.Rpa.Instructions.NumberArithOp.Modulo;
                                    break;
                                case MidInstruction.OpcodeEnum.and:
                                    arithOp = Clarity.Rpa.Instructions.NumberArithOp.BitAnd;
                                    break;
                                case MidInstruction.OpcodeEnum.or:
                                    arithOp = Clarity.Rpa.Instructions.NumberArithOp.BitOr;
                                    break;
                                case MidInstruction.OpcodeEnum.xor:
                                    arithOp = Clarity.Rpa.Instructions.NumberArithOp.BitXor;
                                    break;
                                case MidInstruction.OpcodeEnum.shl:
                                    arithOp = Clarity.Rpa.Instructions.NumberArithOp.ShiftLeft;
                                    break;
                                case MidInstruction.OpcodeEnum.shr:
                                    arithOp = Clarity.Rpa.Instructions.NumberArithOp.ShiftRight;
                                    break;
                                default:
                                    throw new ArgumentException();
                            }

                            SsaRegister left = EmitPassiveConversion(midInstr.CodeLocation, midInstr.RegArg, opSpec, outline, outInstructions);
                            SsaRegister right = EmitPassiveConversion(midInstr.CodeLocation, midInstr.RegArg, opSpec, outline, outInstructions);

                            outInstructions.Add(new Clarity.Rpa.Instructions.ArithInstruction(
                                midInstr.CodeLocation,
                                InternSsaRegister(midInstr.RegArg3),
                                arithOp,
                                arithType,
                                InternSsaRegister(left),
                                InternSsaRegister(right),
                                isOvf
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.neg:
                    case MidInstruction.OpcodeEnum.not:
                        {
                            Clarity.Rpa.HighSsaRegister srcReg = InternSsaRegister(EmitPassiveConversion(midInstr.CodeLocation, midInstr.RegArg, midInstr.RegArg2.VType.TypeSpec, outline, outInstructions));
                            Clarity.Rpa.HighSsaRegister destReg = InternSsaRegister(midInstr.RegArg2);

                            Clarity.Rpa.Instructions.NumberArithType arithType;
                            switch (midInstr.ArithArg)
                            {
                                case MidInstruction.ArithEnum.ArithType_Int32:
                                    arithType = Clarity.Rpa.Instructions.NumberArithType.Int32;
                                    break;
                                case MidInstruction.ArithEnum.ArithType_Int64:
                                    arithType = Clarity.Rpa.Instructions.NumberArithType.Int64;
                                    break;
                                case MidInstruction.ArithEnum.ArithType_NativeInt:
                                    arithType = Clarity.Rpa.Instructions.NumberArithType.NativeInt;
                                    break;
                                case MidInstruction.ArithEnum.ArithType_Float32:
                                    arithType = Clarity.Rpa.Instructions.NumberArithType.Float32;
                                    break;
                                case MidInstruction.ArithEnum.ArithType_Float64:
                                    arithType = Clarity.Rpa.Instructions.NumberArithType.Float64;
                                    break;
                                default:
                                    throw new Exception();
                            }

                            Clarity.Rpa.Instructions.NumberUnaryArithOp arithOp;
                            switch(midInstr.Opcode)
                            {
                                case MidInstruction.OpcodeEnum.neg:
                                    arithOp = Clarity.Rpa.Instructions.NumberUnaryArithOp.Negate;
                                    break;
                                case MidInstruction.OpcodeEnum.not:
                                    arithOp = Clarity.Rpa.Instructions.NumberUnaryArithOp.BitNot;
                                    break;
                                default:
                                    throw new Exception();
                            }

                            outInstructions.Add(new Clarity.Rpa.Instructions.UnaryArithInstruction(
                                midInstr.CodeLocation,
                                destReg,
                                arithOp,
                                arithType,
                                srcReg
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.TryConvertObj:
                        {
                            outInstructions.Add(new Clarity.Rpa.Instructions.DynamicCastInstruction(
                                midInstr.CodeLocation,
                                InternSsaRegister(midInstr.RegArg2),
                                InternSsaRegister(midInstr.RegArg),
                                RpaTagFactory.CreateTypeTag(midInstr.RegArg2.VType.TypeSpec)
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.Leave:
                        {
                            outInstructions.Add(new Clarity.Rpa.Instructions.LeaveRegionInstruction(
                                midInstr.CodeLocation,
                                midInstr.UIntArg
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.DuplicateReg:
                        AliasSsaRegister(InternSsaRegister(midInstr.RegArg), midInstr.RegArg2);
                        break;
                    case MidInstruction.OpcodeEnum.StoreStaticField:
                        {
                            Clarity.Rpa.TypeSpecTag staticType = RpaTagFactory.CreateTypeTag(midInstr.TypeSpecArg);
                            string fieldName = midInstr.StrArg;

                            Clarity.Rpa.HighSsaRegister srcReg = InternSsaRegister(EmitPassiveConversion(midInstr.CodeLocation, midInstr.RegArg, midInstr.TypeSpecArg2, outline, outInstructions));

                            Clarity.Rpa.HighSsaRegister addrReg = new Clarity.Rpa.HighSsaRegister(Clarity.Rpa.HighValueType.ManagedPtr, srcReg.Type, null);

                            outInstructions.Add(new Clarity.Rpa.Instructions.GetStaticFieldAddrInstruction(
                                midInstr.CodeLocation,
                                addrReg,
                                staticType,
                                fieldName
                                ));
                            outInstructions.Add(new Clarity.Rpa.Instructions.StorePtrInstruction(
                                midInstr.CodeLocation,
                                addrReg,
                                srcReg
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.LoadIndirect:
                        {
                            SsaRegister srcReg = EmitPassiveConversion(midInstr.CodeLocation, midInstr.RegArg, midInstr.RegArg2.VType.TypeSpec, outline, outInstructions);
                            SsaRegister destReg = midInstr.RegArg2;

                            outInstructions.Add(new Clarity.Rpa.Instructions.LoadPtrInstruction(
                                midInstr.CodeLocation,
                                InternSsaRegister(destReg),
                                InternSsaRegister(srcReg)
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.LoadStaticField:
                        {
                            Clarity.Rpa.TypeSpecTag staticType = RpaTagFactory.CreateTypeTag(midInstr.TypeSpecArg);
                            string fieldName = midInstr.StrArg;

                            Clarity.Rpa.HighSsaRegister destReg = InternSsaRegister(midInstr.RegArg);
                            Clarity.Rpa.HighSsaRegister addrReg = new Clarity.Rpa.HighSsaRegister(Clarity.Rpa.HighValueType.ManagedPtr, destReg.Type, null);

                            outInstructions.Add(new Clarity.Rpa.Instructions.GetStaticFieldAddrInstruction(
                                midInstr.CodeLocation,
                                addrReg,
                                staticType,
                                fieldName
                                ));
                            outInstructions.Add(new Clarity.Rpa.Instructions.LoadPtrInstruction(
                                midInstr.CodeLocation,
                                destReg,
                                addrReg
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.LoadStaticFieldAddr:
                        {
                            Clarity.Rpa.TypeSpecTag staticType = RpaTagFactory.CreateTypeTag(midInstr.TypeSpecArg);
                            string fieldName = midInstr.StrArg;

                            Clarity.Rpa.HighSsaRegister addrReg = InternSsaRegister(midInstr.RegArg);

                            outInstructions.Add(new Clarity.Rpa.Instructions.GetStaticFieldAddrInstruction(
                                midInstr.CodeLocation,
                                addrReg,
                                staticType,
                                fieldName
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.Box:
                        {
                            outInstructions.Add(new Clarity.Rpa.Instructions.BoxInstruction(
                                midInstr.CodeLocation,
                                InternSsaRegister(midInstr.RegArg2),
                                InternSsaRegister(midInstr.RegArg)
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.ConvertNumber:
                        {
                            bool isOvf = ((midInstr.ArithArg & MidInstruction.ArithEnum.Flags_Ovf) != 0);
                            bool isUn = ((midInstr.ArithArg & MidInstruction.ArithEnum.Flags_Un) != 0);

                            SsaRegister srcReg = midInstr.RegArg;
                            SsaRegister destReg = midInstr.RegArg2;

                            NumericStackType sourceNST = StackTypeForTypeSpec(midInstr.RegArg.VType.TypeSpec);
                            CLR.CLRTypeSpec srcSignAdjustedType = TypeSpecForNumericStackType(sourceNST, isUn);

                            srcReg = EmitPassiveConversion(midInstr.CodeLocation, srcReg, srcSignAdjustedType, outline, outInstructions);

                            outInstructions.Add(new Clarity.Rpa.Instructions.NumberConvertInstruction(
                                midInstr.CodeLocation,
                                InternSsaRegister(destReg),
                                InternSsaRegister(srcReg),
                                isOvf
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.LoadArrayLength:
                        {
                            outInstructions.Add(new Clarity.Rpa.Instructions.GetArrayLengthInstruction(
                                midInstr.CodeLocation,
                                InternSsaRegister(midInstr.RegArg2),
                                InternSsaRegister(midInstr.RegArg)
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.LoadTypeInfoHandle:
                        {
                            outInstructions.Add(new Clarity.Rpa.Instructions.GetTypeInfoInstruction(
                                midInstr.CodeLocation,
                                InternSsaRegister(midInstr.RegArg),
                                RpaTagFactory.CreateTypeTag(midInstr.TypeSpecArg)
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.ConvertObj:
                        {
                            outInstructions.Add(new Clarity.Rpa.Instructions.ForceDynamicCastInstruction(
                                midInstr.CodeLocation,
                                InternSsaRegister(midInstr.RegArg2),
                                InternSsaRegister(midInstr.RegArg),
                                RpaTagFactory.CreateTypeTag(midInstr.RegArg2.VType.TypeSpec)
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.StoreArrayElem:
                        {
                            CLR.CLRTypeSpec szArraySpec = midInstr.RegArg.VType.TypeSpec;
                            CLR.CLRTypeSpec subscriptType = ((CLR.CLRTypeSpecSZArray)szArraySpec).SubType;

                            SsaRegister arrayReg = midInstr.RegArg;
                            SsaRegister indexReg = midInstr.RegArg2;
                            SsaRegister valueReg = EmitPassiveConversion(midInstr.CodeLocation, midInstr.RegArg3, subscriptType, outline, outInstructions);

                            Clarity.Rpa.HighSsaRegister arrayRegHigh = InternSsaRegister(arrayReg);
                            Clarity.Rpa.HighSsaRegister indexRegHigh = InternSsaRegister(indexReg);
                            Clarity.Rpa.HighSsaRegister valueRegHigh = InternSsaRegister(valueReg);
                            Clarity.Rpa.HighSsaRegister addrReg = new Clarity.Rpa.HighSsaRegister(Clarity.Rpa.HighValueType.ManagedPtr, valueRegHigh.Type, null);

                            outInstructions.Add(new Clarity.Rpa.Instructions.GetArrayElementPtrInstruction(
                                midInstr.CodeLocation,
                                addrReg,
                                arrayRegHigh,
                                new Clarity.Rpa.HighSsaRegister[] { indexRegHigh }
                                ));
                            outInstructions.Add(new Clarity.Rpa.Instructions.StorePtrInstruction(
                                midInstr.CodeLocation,
                                addrReg,
                                valueRegHigh));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.Switch:
                        {
                            CLR.CLRTypeSpec intType = m_builder.Assemblies.InternVagueType(new CLR.CLRSigTypeSimple(CLR.CLRSigType.ElementType.U4));

                            SsaRegister caseReg = EmitPassiveConversion(midInstr.CodeLocation, midInstr.RegArg, intType, outline, outInstructions);

                            int numCases = midInstr.CfgEdgesArg.Length;
                            Clarity.Rpa.HighCfgNodeHandle[] outNodes = new Clarity.Rpa.HighCfgNodeHandle[numCases];
                            for (int i = 0; i < numCases; i++)
                            {
                                CfgOutboundEdge edge = midInstr.CfgEdgesArg[i];
                                CfgNode caseNode = edge.SuccessorNode;

                                CppTranslatedOutboundEdge outEdge = InternOutboundEdge(cfgNode, edge);

                                outNodes[i] = outEdge.NextNode;
                            }

                            fallthroughMerged = true;
                            CppTranslatedOutboundEdge defaultEdge = InternOutboundEdge(cfgNode, cfgNode.FallThroughEdge);

                            outInstructions.Add(new Clarity.Rpa.Instructions.SwitchInstruction(
                                midInstr.CodeLocation,
                                InternSsaRegister(caseReg),
                                outNodes,
                                defaultEdge.NextNode
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.StoreIndirect:
                        {
                            SsaRegister destReg = midInstr.RegArg;
                            SsaRegister valueReg = EmitPassiveConversion(midInstr.CodeLocation, midInstr.RegArg2, midInstr.RegArg.VType.TypeSpec, outline, outInstructions);

                            outInstructions.Add(new Clarity.Rpa.Instructions.StorePtrInstruction(
                                midInstr.CodeLocation,
                                InternSsaRegister(destReg),
                                InternSsaRegister(valueReg)
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.LoadFieldInfoHandle:
                        {
                            outInstructions.Add(new Clarity.Rpa.Instructions.GetFieldInfoInstruction(
                                midInstr.CodeLocation,
                                InternSsaRegister(midInstr.RegArg),
                                RpaTagFactory.CreateTypeTag(midInstr.TypeSpecArg),
                                midInstr.StrArg,
                                midInstr.FlagArg
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.UnboxPtr:
                        {
                            outInstructions.Add(new Clarity.Rpa.Instructions.UnboxPtrInstruction(
                                midInstr.CodeLocation,
                                InternSsaRegister(midInstr.RegArg2),
                                InternSsaRegister(midInstr.RegArg)
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.UnboxValue:
                        {
                            outInstructions.Add(new Clarity.Rpa.Instructions.UnboxValueInstruction(
                                midInstr.CodeLocation,
                                InternSsaRegister(midInstr.RegArg2),
                                InternSsaRegister(midInstr.RegArg)
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.ZeroFillPtr:
                        outInstructions.Add(new Clarity.Rpa.Instructions.ZeroFillPtrInstruction(
                            midInstr.CodeLocation,
                            InternSsaRegister(midInstr.RegArg)
                            ));
                        break;
                    case MidInstruction.OpcodeEnum.EnterProtectedBlock:
                        {
                            ExceptionHandlingCluster cluster = midInstr.EhClusterArg;

                            Clarity.Rpa.HighRegion tryRegion;
                            {
                                CppRegionEmitter tryEmitter = new CppRegionEmitter(m_builder, cluster.TryRegion, m_regAllocator, m_localLookup);
                                tryRegion = tryEmitter.Emit();
                            }

                            List<HighCatchHandler> catchHandlers = new List<HighCatchHandler>();
                            List<HighRegion> otherRegions = new List<HighRegion>();
                            foreach (ExceptionHandlingRegion handlerRegion in cluster.ExceptionHandlingRegions)
                            {
                                CppRegionEmitter hdlEmitter = new CppRegionEmitter(m_builder, handlerRegion, m_regAllocator, m_localLookup);
                                HighRegion hdlRegion = hdlEmitter.Emit();

                                switch (cluster.ClusterType)
                                {
                                    case ExceptionHandlingCluster.ClusterTypeEnum.TryCatch:
                                        {
                                            HighCfgNode entryNode = hdlRegion.EntryNode.Value;

                                            // Inject a catch landing instruction and recreate the phi node.
                                            // This is safe because III.1.7.5 disallows backward branches with stack,
                                            // so the only valid way to reach a catch handler is by catching, never via
                                            // a predecessor.
                                            if (entryNode.Phis.Length != 1 || entryNode.Phis[0].Links.Length != 0)
                                                throw new Exception("Catch handler should start with an unlinked phi node");

                                            HighSsaRegister exceptionReg = entryNode.Phis[0].Dest;

                                            CodeLocationTag codeLoc = entryNode.Instructions[0].CodeLocation;

                                            List<HighInstruction> catchLandingInstrs = new List<HighInstruction>();
                                            HighSsaRegister catchDest = new HighSsaRegister(HighValueType.ReferenceValue, exceptionReg.Type, null);
                                            catchLandingInstrs.Add(new Clarity.Rpa.Instructions.CatchInstruction(codeLoc, catchDest, exceptionReg.Type));
                                            catchLandingInstrs.Add(new Clarity.Rpa.Instructions.BranchInstruction(codeLoc, hdlRegion.EntryNode));

                                            HighCfgNode landingNode = new HighCfgNode(new HighCfgNodeHandle[0], new HighPhi[0], catchLandingInstrs.ToArray());

                                            HighCfgNodeHandle landingHandle = new HighCfgNodeHandle(landingNode);

                                            entryNode.Predecessors = new HighCfgNodeHandle[] { landingHandle };
                                            entryNode.Phis[0].Links = new HighPhiLink[] { new HighPhiLink(landingHandle, catchDest) };

                                            HighRegion replacementRegion = new HighRegion(landingHandle);

                                            catchHandlers.Add(new HighCatchHandler(
                                                RpaTagFactory.CreateTypeTag(handlerRegion.ExceptionType),
                                                replacementRegion
                                                ));
                                        }
                                        break;
                                    case ExceptionHandlingCluster.ClusterTypeEnum.TryFault:
                                    case ExceptionHandlingCluster.ClusterTypeEnum.TryFinally:
                                        otherRegions.Add(hdlRegion);
                                        break;
                                    default:
                                        throw new Exception();
                                }
                            }

                            List<Clarity.Rpa.HighEscapePathTerminator> terminators = new List<Clarity.Rpa.HighEscapePathTerminator>();
                            foreach (uint escapePath in cluster.EscapePaths)
                            {
                                CfgNode targetNode;
                                if (m_region.EscapeTerminators.TryGetValue(escapePath, out targetNode))
                                {
                                    Clarity.Rpa.HighCfgNodeHandle terminatorNode = InternHighCfgNode(targetNode);
                                    terminators.Add(new Clarity.Rpa.HighEscapePathTerminator(escapePath, terminatorNode));
                                }
                            }

                            Clarity.Rpa.HighProtectedRegion protRegion;
                            switch (cluster.ClusterType)
                            {
                                case ExceptionHandlingCluster.ClusterTypeEnum.TryCatch:
                                    protRegion = new Clarity.Rpa.HighTryCatchRegion(tryRegion, catchHandlers.ToArray());
                                    break;
                                case ExceptionHandlingCluster.ClusterTypeEnum.TryFault:
                                    protRegion = new Clarity.Rpa.HighTryFaultRegion(tryRegion, otherRegions[0]);
                                    break;
                                case ExceptionHandlingCluster.ClusterTypeEnum.TryFinally:
                                    protRegion = new Clarity.Rpa.HighTryFinallyRegion(tryRegion, otherRegions[0]);
                                    break;
                                default:
                                    throw new Exception();
                            }

                            Clarity.Rpa.HighEHCluster highCluster = new Clarity.Rpa.HighEHCluster(protRegion, terminators.ToArray());

                            outInstructions.Add(new Clarity.Rpa.Instructions.EnterProtectedBlockInstruction(
                                midInstr.CodeLocation,
                                highCluster
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.ExitFinally:
                        outInstructions.Add(new Clarity.Rpa.Instructions.ReturnInstruction(midInstr.CodeLocation));
                        break;
                    case MidInstruction.OpcodeEnum.BindDelegate:
                        {
                            SsaRegister objReg = midInstr.RegArg;
                            CppMethodSpec methodSpec = (CppMethodSpec)midInstr.RegArg2.ConstantValue;
                            SsaRegister destReg = midInstr.RegArg3;

                            Clarity.Rpa.MethodSignatureTag sigTag = RpaTagFactory.CreateMethodSignature(methodSpec.CppMethod.MethodSignature);

                            Clarity.Rpa.HighSsaRegister destRegHigh = InternSsaRegister(destReg);

                            Clarity.Rpa.MethodSlotType slotType;

                            if (methodSpec.CppMethod.Static)
                                slotType = Clarity.Rpa.MethodSlotType.Static;
                            else
                            {
                                objReg = EmitPassiveConversion(midInstr.CodeLocation, objReg, methodSpec.CppMethod.DeclaredInClassSpec, outline, outInstructions);
                                if (midInstr.RegArg2.VType.ValType == VType.ValTypeEnum.DelegateSimpleMethod)
                                    slotType = Clarity.Rpa.MethodSlotType.Instance;
                                else if (midInstr.RegArg2.VType.ValType == VType.ValTypeEnum.DelegateVirtualMethod)
                                    slotType = Clarity.Rpa.MethodSlotType.Virtual;
                                else
                                    throw new ArgumentException();
                            }

                            Clarity.Rpa.MethodSpecTag methodSpecTag = RpaTagFactory.CreateMethodSpec(slotType, methodSpec);

                            if (methodSpec.CppMethod.Static)
                            {
                                outInstructions.Add(new Clarity.Rpa.Instructions.BindStaticDelegateInstruction(
                                    midInstr.CodeLocation,
                                    InternSsaRegister(destReg),
                                    methodSpecTag
                                    ));
                            }
                            else if (midInstr.RegArg2.VType.ValType == VType.ValTypeEnum.DelegateSimpleMethod)
                            {
                                outInstructions.Add(new Clarity.Rpa.Instructions.BindInstanceDelegateInstruction(
                                    midInstr.CodeLocation,
                                    InternSsaRegister(destReg),
                                    InternSsaRegister(objReg),
                                    methodSpecTag
                                    ));
                            }
                            else if (midInstr.RegArg2.VType.ValType == VType.ValTypeEnum.DelegateVirtualMethod)
                            {
                                outInstructions.Add(new Clarity.Rpa.Instructions.BindVirtualDelegateInstruction(
                                    midInstr.CodeLocation,
                                    InternSsaRegister(destReg),
                                    InternSsaRegister(objReg),
                                    methodSpecTag
                                    ));
                            }
                        }
                        break;
                    default:
                        throw new ArgumentException("Invalid mid IL opcode");
                }
            }

            if (cfgNode.FallThroughEdge != null && !fallthroughMerged)
            {
                CppTranslatedOutboundEdge outEdge = InternOutboundEdge(cfgNode, cfgNode.FallThroughEdge);

                outInstructions.Add(new Clarity.Rpa.Instructions.BranchInstruction(cfgNode.FallThroughEdge.CodeLocation, outEdge.NextNode));
            }

            List<HighCfgNodeHandle> highPreds = new List<HighCfgNodeHandle>();
            foreach (CppTranslatedOutboundEdge predEdge in predecessorEdges)
                highPreds.Add(predEdge.PrevNode);

            highNode.Value = new HighCfgNode(highPreds.ToArray(), outPhis.ToArray(), outInstructions.ToArray());
        }
コード例 #15
0
            private HighCfgNode GenerateFinallyCleanup(HighEHCluster ehCluster, HighTryFinallyRegion tryFinallyRegion, HighCfgNode handlerNode)
            {
                Instructions.CatchOrRouteInstruction catchInstr = (Instructions.CatchOrRouteInstruction)handlerNode.Instructions[0];

                List<Instructions.RloTerminateRoutesInstruction.RouteTermination> terminations = new List<Instructions.RloTerminateRoutesInstruction.RouteTermination>();

                HighCfgNode trappingFinally = null;

                RegionStack stack = m_regionStack;
                while (stack != null)
                {
                    if (stack != m_regionStack && stack.EHCluster.ProtectedRegion is HighTryFinallyRegion)
                        trappingFinally = stack.ExceptionHandler;

                    foreach (HighEscapePathTerminator terminator in stack.EHCluster.EscapePathTerminators)
                    {
                        int routeID = m_initPass.m_routeCompactionDict[terminator.EscapePath];

                        HighCfgNode successor;
                        if (trappingFinally != null)
                            successor = GenerateRepeatRoute(routeID, trappingFinally);
                        else
                            successor = terminator.CfgNode.Value;
                        terminations.Add(new Instructions.RloTerminateRoutesInstruction.RouteTermination(routeID, successor));
                    }
                    stack = stack.Next;
                }

                List<HighInstruction> instrs = new List<HighInstruction>();
                Instructions.RloTerminateRoutesInstruction trInstr = new Instructions.RloTerminateRoutesInstruction(null, catchInstr.ExceptionDest, catchInstr.RouteDest, terminations.ToArray());

                if (m_regionStack.Next != null)
                    trInstr.ExceptionEdge = new HighCfgEdge(trInstr, new HighCfgNodeHandle(m_regionStack.Next.ExceptionHandler));
                instrs.Add(trInstr);

                return new HighCfgNode(new HighCfgNodeHandle[0], new HighPhi[0], instrs.ToArray());
            }
コード例 #16
0
ファイル: RloInitPass.cs プロジェクト: elasota/clarity
        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);
        }
コード例 #17
0
ファイル: RloInitPass.cs プロジェクト: elasota/clarity
        protected override void ProcessNode(HighCfgNode cfgNode)
        {
            int numInstructions = cfgNode.Instructions.Length;
            if (cfgNode.Instructions.Length == 0)
                throw new Exception("CFG node has no instructions");

            HighInstruction[] instructions = cfgNode.Instructions;
            for (int i = 0; i < numInstructions; i++)
                if (instructions[i].TerminatesControlFlow != (i == numInstructions - 1))
                    throw new Exception("Unexpected control flow instruction location");

            // Validate phis
            ISet<HighCfgNode> nodePreds = m_psPass.PredecessorsForNode(cfgNode);

            foreach (HighPhi phi in cfgNode.Phis)
            {
                HashSet<HighCfgNode> linkPreds = new HashSet<HighCfgNode>();
                foreach (HighPhiLink link in phi.Links)
                {
                    if (!CanPhiMatchVT(link.Reg.ValueType, phi.Dest.ValueType) || link.Reg.Type != phi.Dest.Type)
                        throw new Exception("Phi predecessor type does not match link destination type");
                    if (!linkPreds.Add(link.Predecessor.Value))
                        throw new Exception("Duplicate phi predecessor");
                }

                // It's OK for a phi link predecessor to not be an actual predecessor, but it's not
                // OK for an actual predecessor to be missing a phi link
                if (nodePreds != null)
                {
                    foreach (HighCfgNode nodePred in nodePreds)
                        if (!linkPreds.Contains(nodePred))
                            throw new Exception("Phi is missing a predecessor link");
                }
            }

            // Process instructions
            List<HighInstruction> newInstrs = new List<HighInstruction>();
            foreach (HighInstruction instr in cfgNode.Instructions)
                ProcessInstruction(cfgNode, instr, newInstrs);

            // Add SSA types
            foreach (HighPhi phi in cfgNode.Phis)
            {
                phi.VisitSsaDests(m_addTypeVisitor);
                phi.VisitSsaUses(m_addTypeVisitor);
            }

            foreach (HighInstruction instr in cfgNode.Instructions)
            {
                instr.VisitSsaDests(m_addTypeVisitor);
                instr.VisitSsaUses(m_addTypeVisitor);
            }
        }
コード例 #18
0
            public RegionProcessor(RloInitExceptionsPass initPass, RegionStack regionStack, bool isTry, bool canReturnNothing)
            {
                m_initPass = initPass;
                m_isTry = isTry;
                m_alreadyQueuedNodes = new HashSet<HighCfgNode>();
                m_queuedNodes = new Queue<HighCfgNode>();
                m_canReturnNothing = canReturnNothing;

                if (regionStack != null)
                {
                    m_regionStack = regionStack;
                    if (m_isTry)
                        m_exceptionNode = regionStack.ExceptionHandler;
                    else
                    {
                        RegionStack parent = regionStack.Next;
                        if (parent != null)
                            m_exceptionNode = parent.ExceptionHandler;
                    }

                    HighTryFinallyRegion tryFinallyRegion = regionStack.EHCluster.ProtectedRegion as HighTryFinallyRegion;
                    if (tryFinallyRegion != null && !m_isTry)
                        m_finallyCleanupNode = GenerateFinallyCleanup(regionStack.EHCluster, tryFinallyRegion, regionStack.ExceptionHandler);
                }
            }
コード例 #19
0
 public RegionStack(RegionStack next, HighEHCluster ehCluster, HighCfgNode exceptionHandler)
 {
     m_next = next;
     m_ehCluster = ehCluster;
     m_exceptionHandler = exceptionHandler;
 }
コード例 #20
0
            private void ProcessNode(HighCfgNode cfgNode)
            {
                HighCfgNode lastNode = cfgNode;
                HighInstruction lastInstr = cfgNode.Instructions[cfgNode.Instructions.Length - 1];

                // Rebuild handles so they're definitely not shared, collect handles
                List<HighCfgNodeHandle> successorLinkHandles = new List<HighCfgNodeHandle>();

                IBranchingInstruction brInstr = lastInstr as IBranchingInstruction;
                if (brInstr != null)
                {
                    brInstr.VisitSuccessors(delegate (ref HighCfgEdge edge)
                    {
                        foreach (HighPhi phi in edge.Dest.Value.Phis)
                        {
                            HighPhiLink[] links = phi.Links;
                            for (int i = 0; i < links.Length; i++)
                            {
                                if (links[i].Predecessor.Value == cfgNode)
                                {
                                    HighCfgNodeHandle hdl = new HighCfgNodeHandle(cfgNode);
                                    links[i].Predecessor = hdl;
                                    successorLinkHandles.Add(hdl);
                                }
                            }
                        }

                        if (edge.Dest.Value.Instructions[0] is Rpa.Instructions.CatchInstruction)
                            throw new RpaCompileException("Branch target is a catch instruction");

                        // Relink edges to their new sources
                        edge = new HighCfgEdge(lastInstr, edge.Dest);

                        QueueNode(edge.Dest.Value);
                    });
                }

                List<HighInstruction> newInstructions = new List<HighInstruction>();

                HighInstruction[] originalInstructions = cfgNode.Instructions;
                foreach (HighInstruction instr in originalInstructions)
                {
                    if (instr is Rpa.Instructions.ReturnValueInstruction)
                    {
                        if (m_regionStack != null)
                            throw new RpaCompileException("ReturnValueInstruction in a protected region");
                        newInstructions.Add(instr);
                    }
                    else if (instr is Rpa.Instructions.ReturnInstruction)
                    {
                        if (m_regionStack != null)
                        {
                            if (m_finallyCleanupNode == null)
                                throw new RpaCompileException("ReturnInstruction in a protected region doesn't exit a finally");
                            newInstructions.Add(new Rpa.Instructions.BranchInstruction(instr.CodeLocation, new HighCfgNodeHandle(m_finallyCleanupNode)));
                        }
                        else
                        {
                            if (!m_canReturnNothing)
                                throw new RpaCompileException("ReturnInstruction in a function that returns a value");
                            newInstructions.Add(instr);
                        }
                    }
                    else if (instr is Rpa.Instructions.LeaveRegionInstruction)
                    {
                        Rpa.Instructions.LeaveRegionInstruction tInstr = (Rpa.Instructions.LeaveRegionInstruction)instr;

                        if (m_finallyCleanupNode != null && !m_isTry)
                            throw new RpaCompileException("LeaveRegionInstruction isn't valid in a finally handler");

                        uint routeID = tInstr.RouteID;

                        bool isRouted = false;
                        HighCfgNode matchingNode = null;

                        RegionStack stack = m_regionStack;
                        while (stack != null)
                        {
                            if (stack.EHCluster.ProtectedRegion is HighTryFinallyRegion)
                            {
                                isRouted = true;
                                matchingNode = stack.ExceptionHandler;
                                break;
                            }
                            else
                            {
                                bool matched = false;
                                foreach (HighEscapePathTerminator terminator in stack.EHCluster.EscapePathTerminators)
                                {
                                    if (terminator.EscapePath == routeID)
                                    {
                                        matched = true;
                                        matchingNode = terminator.CfgNode.Value;
                                        break;
                                    }
                                }
                                if (matched)
                                    break;
                            }
                            stack = stack.Next;
                        }

                        if (matchingNode == null)
                            throw new RpaCompileException("Unmatched exception escape route");

                        if (isRouted)
                            newInstructions.Add(new Instructions.RloRoutedBranchInstruction(tInstr.CodeLocation, m_initPass.m_routeCompactionDict[routeID], matchingNode));
                        else
                            newInstructions.Add(new Rpa.Instructions.BranchInstruction(tInstr.CodeLocation, new HighCfgNodeHandle(matchingNode)));
                    }
                    else if (instr is Rpa.Instructions.ThrowInstruction)
                    {
                        Rpa.Instructions.ThrowInstruction tInstr = (Rpa.Instructions.ThrowInstruction)instr;

                        if (m_exceptionNode != null)
                            tInstr.ExceptionEdge = new HighCfgEdge(tInstr, new HighCfgNodeHandle(m_exceptionNode));
                        newInstructions.Add(tInstr);
                    }
                    else if (instr is Rpa.Instructions.CatchInstruction)
                    {
                        throw new RpaCompileException("Invalid location of a catch instruction");
                    }
                    else if (instr is Rpa.Instructions.EnterProtectedBlockInstruction)
                    {
                        Rpa.Instructions.EnterProtectedBlockInstruction tInstr = (Rpa.Instructions.EnterProtectedBlockInstruction)instr;
                        HighEHCluster ehCluster = tInstr.EHCluster;
                        HighProtectedRegion protRegion = ehCluster.ProtectedRegion;

                        AddEscapePaths(ehCluster.EscapePathTerminators);

                        HighCfgNode tryNode;
                        if (protRegion is HighTryCatchRegion)
                        {
                            HighTryCatchRegion tProtRegion = (HighTryCatchRegion)protRegion;
                            RegionStack regionStack = new RegionStack(m_regionStack, ehCluster, GenerateTryCatchHandler(tProtRegion));

                            tryNode = ProcessSubRegion(tProtRegion.TryRegion, regionStack, true);

                            foreach (HighCatchHandler handler in tProtRegion.CatchHandlers)
                                ProcessSubRegion(handler.Region, regionStack, false);
                        }
                        else if (protRegion is HighTryFaultRegion)
                        {
                            HighTryFaultRegion tProtRegion = (HighTryFaultRegion)protRegion;
                            RegionStack regionStack = new RegionStack(m_regionStack, ehCluster, tProtRegion.FaultRegion.EntryNode.Value);

                            tryNode = ProcessSubRegion(tProtRegion.TryRegion, regionStack, true);
                            ProcessSubRegion(tProtRegion.FaultRegion, regionStack, false);
                        }
                        else if (protRegion is HighTryFinallyRegion)
                        {
                            HighTryFinallyRegion tProtRegion = (HighTryFinallyRegion)protRegion;

                            HighCfgNode finallyInit = GenerateFinallyInit(tProtRegion.FinallyRegion.EntryNode.Value);

                            RegionStack regionStack = new RegionStack(m_regionStack, ehCluster, finallyInit);

                            tryNode = ProcessSubRegion(tProtRegion.TryRegion, regionStack, true);
                            ProcessSubRegion(tProtRegion.FinallyRegion, regionStack, false);
                        }
                        else
                            throw new Exception();

                        newInstructions.Add(new Rpa.Instructions.BranchInstruction(instr.CodeLocation, new HighCfgNodeHandle(tryNode)));
                    }
                    else
                    {
                        newInstructions.Add(instr);
                        if (instr.MayThrow)
                        {
                            cfgNode.Instructions = newInstructions.ToArray();
                            HighCfgNode newNode = new HighCfgNode(new HighCfgNodeHandle[0], new HighPhi[0], null);
                            HighCfgNodeHandle destHandle = new HighCfgNodeHandle(newNode);

                            instr.ContinuationEdge = new HighCfgEdge(instr, destHandle);
                            if (m_exceptionNode != null)
                                instr.ExceptionEdge = new HighCfgEdge(instr, new HighCfgNodeHandle(m_exceptionNode));
                            cfgNode = newNode;
                            newInstructions.Clear();
                        }
                    }
                }

                if (newInstructions.Count == 0)
                    throw new Exception();

                cfgNode.Instructions = newInstructions.ToArray();

                foreach (HighCfgNodeHandle linkHdl in successorLinkHandles)
                    linkHdl.Value = cfgNode;
            }
コード例 #21
0
ファイル: CppRegionEmitter.cs プロジェクト: elasota/clarity
        private CppTranslatedOutboundEdge InternOutboundEdge(CfgNode node, CfgOutboundEdge edge)
        {
            CppTranslatedOutboundEdge outboundEdge;
            if (m_translatedOutboundEdges.TryGetValue(edge, out outboundEdge))
                return outboundEdge;

            bool needRegTranslation = false;

            int survivingRegsCount = edge.SurvivingRegs.Length;
            CfgNode successorNode = edge.SuccessorNode;

            for (int i = 0; i < survivingRegsCount; i++)
            {
                CLR.CLRTypeSpec outType = edge.SurvivingRegs[i].VType.TypeSpec;
                CLR.CLRTypeSpec inType = successorNode.EntryTypes[i].TypeSpec;

                if (!outType.Equals(inType))
                {
                    needRegTranslation = true;
                    break;
                }
            }

            Clarity.Rpa.HighCfgNodeHandle prevNode = InternHighCfgNode(node);

            if (!needRegTranslation)
            {
                List<Clarity.Rpa.HighSsaRegister> regs = new List<Clarity.Rpa.HighSsaRegister>();
                foreach (SsaRegister reg in edge.SurvivingRegs)
                    regs.Add(InternSsaRegister(reg));
                Clarity.Rpa.HighCfgNodeHandle nextNode = InternHighCfgNode(edge.SuccessorNode);
                outboundEdge = new CppTranslatedOutboundEdge(prevNode, nextNode, regs);
            }
            else
            {
                List<Clarity.Rpa.HighInstruction> instrs = new List<Clarity.Rpa.HighInstruction>();
                List<Clarity.Rpa.HighSsaRegister> regs = new List<Clarity.Rpa.HighSsaRegister>();
                List<Clarity.Rpa.HighPhi> phis = new List<Clarity.Rpa.HighPhi>();

                Clarity.Rpa.HighCfgNodeHandle nextNode = InternHighCfgNode(edge.SuccessorNode);

                MidInstruction[] midInstrs = edge.SuccessorNode.MidInstructions;
                for (int i = 0; i < survivingRegsCount; i++)
                {
                    MidInstruction midInstr = midInstrs[i];
                    if (midInstr.Opcode != MidInstruction.OpcodeEnum.EntryReg)
                        throw new Exception("Internal error");

                    Clarity.Rpa.HighSsaRegister sourceReg = InternSsaRegister(edge.SurvivingRegs[i]);
                    Clarity.Rpa.HighSsaRegister targetReg = InternSsaRegister(midInstr.RegArg);

                    if (!targetReg.IsConstant)
                    {
                        HighSsaRegister importReg = new HighSsaRegister(sourceReg.ValueType, sourceReg.Type, sourceReg.ConstantValue);
                        HighSsaRegister exportReg = new HighSsaRegister(targetReg.ValueType, targetReg.Type, targetReg.ConstantValue);

                        HighPhiLink phiLink = new HighPhiLink(prevNode, sourceReg);
                        phis.Add(new HighPhi(importReg, new HighPhiLink[] { phiLink }));

                        instrs.Add(new Clarity.Rpa.Instructions.PassiveConvertInstruction(
                            midInstr.CodeLocation,
                            exportReg,
                            importReg
                            ));
                        regs.Add(exportReg);
                    }
                    else
                        regs.Add(targetReg);
                }

                instrs.Add(new Clarity.Rpa.Instructions.BranchInstruction(edge.CodeLocation, nextNode));

                Clarity.Rpa.HighCfgNode cfgNode = new HighCfgNode(new Clarity.Rpa.HighCfgNodeHandle[] { prevNode }, phis.ToArray(), instrs.ToArray());
                Clarity.Rpa.HighCfgNodeHandle cfgNodeHandle = new Clarity.Rpa.HighCfgNodeHandle(cfgNode);

                outboundEdge = new CppTranslatedOutboundEdge(cfgNodeHandle, cfgNodeHandle, regs);
            }

            m_translatedOutboundEdges.Add(edge, outboundEdge);
            return outboundEdge;
        }
コード例 #22
0
 public void QueueNode(HighCfgNode cfgNode)
 {
     if (m_alreadyQueuedNodes.Add(cfgNode))
         m_queuedNodes.Enqueue(cfgNode);
 }