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; }
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); }
public void QueueNode(HighCfgNode cfgNode) { if (!m_alreadyQueuedNodesSet.Add(cfgNode)) return; m_queuedNodes.Enqueue(cfgNode); m_finalQueue.Enqueue(cfgNode); }
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); } }
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); } }
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()); }
protected abstract void ProcessNode(HighCfgNode cfgNode);
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; }
public RloRoutedBranchInstruction(CodeLocationTag codeLocation, int routeID, HighCfgNode destination) : base(codeLocation) { m_routeID = routeID; m_destination = new HighCfgEdge(this, new HighCfgNodeHandle(destination)); }
public RouteTermination(int routeID, HighCfgNode successor) { m_routeID = routeID; m_successor = successor; }
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()); }
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()); }
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); }
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()); }
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()); }
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); }
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); } }
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); } }
public RegionStack(RegionStack next, HighEHCluster ehCluster, HighCfgNode exceptionHandler) { m_next = next; m_ehCluster = ehCluster; m_exceptionHandler = exceptionHandler; }
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; }
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; }
public void QueueNode(HighCfgNode cfgNode) { if (m_alreadyQueuedNodes.Add(cfgNode)) m_queuedNodes.Enqueue(cfgNode); }