// Copyright © Microsoft Corporation. // This source file is subject to the Microsoft Permissive License. // See http://www.microsoft.com/resources/sharedsource/licensingbasics/sharedsourcelicenses.mspx. // All other rights reserved. #if !NoReflection && !MinimalReader && WHIDBEY using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection.Emit; #if CCINamespace using Microsoft.Cci.Metadata; namespace Microsoft.Cci{ #else using System.Compiler.Metadata; using ElementType = System.Compiler.Metadata.ElementType; namespace System.Compiler { #endif public class ReGenerator { protected TrivialHashtable/*!*/ exceptionStartCount = new TrivialHashtable(); protected TrivialHashtable/*!*/ catchStart = new TrivialHashtable(); protected TrivialHashtable/*!*/ catchTypeNode = new TrivialHashtable(); protected TrivialHashtable/*!*/ finallyStart = new TrivialHashtable(); protected TrivialHashtable/*!*/ exceptionEndCount = new TrivialHashtable(); protected ILGenerator/*!*/ ILGenerator; protected TrivialHashtable/*!*/ labelIndex = new TrivialHashtable(); protected List/*!*/ locals = new List(); protected TrivialHashtable/*!*/ localsIndex = new TrivialHashtable(); public ReGenerator(ILGenerator/*!*/ ilGenerator) { this.ILGenerator = ilGenerator; //^ base(); } public virtual void VisitMethod(Method method) { if (method == null) { Debug.Assert(false); return; } this.VisitExceptionHandlers(method.ExceptionHandlers); this.VisitBlock(method.Body); } protected virtual void VisitExceptionHandlers(ExceptionHandlerList ehandlers) { //TODO: the list of ehandlers is sorted so that nested blocks always come first //When a handler does not have exactly the same start and end blocks as the previous handler, it is either a parent or a sibling. //When this transition occurs an end exception can be emitted when processing the last handler block of the previous handler. //Need to keep counts of the number of times a block starts a handler protected region and the number of times that a block //is the one following a handler exceptional region. } protected virtual Label GetLabel(Block/*!*/ block) { object label = this.labelIndex[block.UniqueKey]; if (label == null) { label = this.ILGenerator.DefineLabel(); this.labelIndex[block.UniqueKey] = label; } return (Label)label; } protected virtual int GetLocalVarIndex(Local/*!*/ loc) { object index = this.localsIndex[loc.UniqueKey]; if (index is int) return (int)index; Type ltype = loc.Type == null ? null : loc.Type.GetRuntimeType(); if (ltype == null) { Debug.Fail(""); return 0; } LocalBuilder locb = this.ILGenerator.DeclareLocal(ltype, loc.Pinned); int i = this.locals.Count; this.locals.Add(locb); this.localsIndex[loc.UniqueKey] = i; return i; } protected virtual void Visit(Node node) { if (node == null) return; switch (node.NodeType) { case NodeType.AddressDereference: this.VisitAddressDereference((AddressDereference)node); return; case NodeType.Arglist: this.VisitExpression((Expression)node); return; case NodeType.AssignmentStatement: this.VisitAssignmentStatement((AssignmentStatement)node); return; case NodeType.Base: this.VisitBase((Base)node); return; case NodeType.Block: this.VisitBlock((Block)node); return; case NodeType.BlockExpression: this.VisitBlockExpression((BlockExpression)node); return; case NodeType.Branch: this.VisitBranch((Branch)node); return; case NodeType.DebugBreak: this.VisitStatement((Statement)node); return; case NodeType.Call: case NodeType.Calli: case NodeType.Callvirt: case NodeType.Jmp: case NodeType.MethodCall: this.VisitMethodCall((MethodCall)node); return; case NodeType.Construct: this.VisitConstruct((Construct)node); return; case NodeType.ConstructArray: this.VisitConstructArray((ConstructArray)node); return; case NodeType.Dup: this.VisitExpression((Expression)node); return; case NodeType.EndFilter: this.VisitEndFilter((EndFilter)node); return; case NodeType.EndFinally: this.VisitStatement((Statement)node); return; case NodeType.ExpressionStatement: this.VisitExpressionStatement((ExpressionStatement)node); return; case NodeType.Indexer: this.VisitIndexer((Indexer)node); return; case NodeType.Literal: this.VisitLiteral((Literal)node); return; case NodeType.Local: this.VisitLocal((Local)node); return; case NodeType.MemberBinding: this.VisitMemberBinding((MemberBinding)node); return; case NodeType.Nop: this.VisitStatement((Statement)node); return; case NodeType.Parameter: this.VisitParameter((Parameter)node); return; case NodeType.Pop: this.VisitExpression((Expression)node); return; case NodeType.Rethrow: case NodeType.Throw: this.VisitThrow((Throw)node); return; case NodeType.Return: this.VisitReturn((Return)node); return; case NodeType.SwitchCaseBottom: return; case NodeType.SwitchInstruction: this.VisitSwitchInstruction((SwitchInstruction)node); return; case NodeType.This: this.VisitThis((This)node); return; case NodeType.Cpblk: case NodeType.Initblk: this.VisitTernaryExpression((TernaryExpression)node); return; case NodeType.Add: case NodeType.Add_Ovf: case NodeType.Add_Ovf_Un: case NodeType.And: case NodeType.Box: case NodeType.Castclass: case NodeType.Ceq: case NodeType.Cgt: case NodeType.Cgt_Un: case NodeType.Clt: case NodeType.Clt_Un: case NodeType.Div: case NodeType.Div_Un: case NodeType.Eq: case NodeType.Ge: case NodeType.Gt: case NodeType.Is: case NodeType.Isinst: case NodeType.Ldvirtftn: case NodeType.Le: case NodeType.Lt: case NodeType.Mkrefany: case NodeType.Mul: case NodeType.Mul_Ovf: case NodeType.Mul_Ovf_Un: case NodeType.Ne: case NodeType.Or: case NodeType.Refanyval: case NodeType.Rem: case NodeType.Rem_Un: case NodeType.Shl: case NodeType.Shr: case NodeType.Shr_Un: case NodeType.Sub: case NodeType.Sub_Ovf: case NodeType.Sub_Ovf_Un: case NodeType.Unbox: case NodeType.UnboxAny: case NodeType.Xor: this.VisitBinaryExpression((BinaryExpression)node); return; case NodeType.AddressOf: case NodeType.OutAddress: case NodeType.RefAddress: case NodeType.ReadOnlyAddressOf: this.VisitAddressOf((UnaryExpression)node); return; case NodeType.Ckfinite: case NodeType.Conv_I: case NodeType.Conv_I1: case NodeType.Conv_I2: case NodeType.Conv_I4: case NodeType.Conv_I8: case NodeType.Conv_Ovf_I: case NodeType.Conv_Ovf_I1: case NodeType.Conv_Ovf_I1_Un: case NodeType.Conv_Ovf_I2: case NodeType.Conv_Ovf_I2_Un: case NodeType.Conv_Ovf_I4: case NodeType.Conv_Ovf_I4_Un: case NodeType.Conv_Ovf_I8: case NodeType.Conv_Ovf_I8_Un: case NodeType.Conv_Ovf_I_Un: case NodeType.Conv_Ovf_U: case NodeType.Conv_Ovf_U1: case NodeType.Conv_Ovf_U1_Un: case NodeType.Conv_Ovf_U2: case NodeType.Conv_Ovf_U2_Un: case NodeType.Conv_Ovf_U4: case NodeType.Conv_Ovf_U4_Un: case NodeType.Conv_Ovf_U8: case NodeType.Conv_Ovf_U8_Un: case NodeType.Conv_Ovf_U_Un: case NodeType.Conv_R4: case NodeType.Conv_R8: case NodeType.Conv_R_Un: case NodeType.Conv_U: case NodeType.Conv_U1: case NodeType.Conv_U2: case NodeType.Conv_U4: case NodeType.Conv_U8: case NodeType.Ldftn: case NodeType.Ldlen: case NodeType.Ldtoken: case NodeType.Localloc: case NodeType.Neg: case NodeType.Not: case NodeType.Refanytype: case NodeType.Sizeof: this.VisitUnaryExpression((UnaryExpression)node); return; default: Debug.Assert(false, "invalid node: " + node.NodeType.ToString()); return; } } protected virtual void VisitAddressDereference(AddressDereference adr) { if (adr == null) return; this.Visit(adr.Address); if (adr.Alignment > 0) this.ILGenerator.Emit(OpCodes.Unaligned, (byte)adr.Alignment); if (adr.Volatile) this.ILGenerator.Emit(OpCodes.Volatile); if (adr.Type == null) return; switch (adr.Type.typeCode) { case ElementType.Int8: this.ILGenerator.Emit(OpCodes.Ldind_I1); return; case ElementType.UInt8: this.ILGenerator.Emit(OpCodes.Ldind_U1); return; case ElementType.Int16: this.ILGenerator.Emit(OpCodes.Ldind_I2); return; case ElementType.Char: case ElementType.UInt16: this.ILGenerator.Emit(OpCodes.Ldind_U2); return; case ElementType.Int32: this.ILGenerator.Emit(OpCodes.Ldind_I4); return; case ElementType.UInt32: this.ILGenerator.Emit(OpCodes.Ldind_U4); return; case ElementType.Int64: case ElementType.UInt64: this.ILGenerator.Emit(OpCodes.Ldind_I8); return; case ElementType.UIntPtr: case ElementType.IntPtr: this.ILGenerator.Emit(OpCodes.Ldind_I); return; case ElementType.Single: this.ILGenerator.Emit(OpCodes.Ldind_R4); return; case ElementType.Double: this.ILGenerator.Emit(OpCodes.Ldind_R8); return; default: if (adr.Type.IsValueType && !(adr.Type is TypeParameter)) { this.ILGenerator.Emit(OpCodes.Ldobj, adr.Type.GetRuntimeType()); return; } else if (TypeNode.StripModifiers(adr.Type) is Pointer) { this.ILGenerator.Emit(OpCodes.Ldind_I); return; } this.ILGenerator.Emit(OpCodes.Ldind_Ref); return; } } protected virtual void VisitAddressOf(UnaryExpression expr) { if (expr == null) return; Expression operand = expr.Operand; if (operand == null) return; switch (operand.NodeType) { case NodeType.Indexer: Indexer indexer = (Indexer)operand; this.Visit(indexer.Object); if (indexer.Operands != null && indexer.Operands.Count == 1) this.Visit(indexer.Operands[0]); if (expr.NodeType == NodeType.ReadOnlyAddressOf) this.ILGenerator.Emit(OpCodes.Readonly); if (indexer.ElementType != null) this.ILGenerator.Emit(OpCodes.Ldelema, indexer.ElementType.GetRuntimeType()); return; case NodeType.Local: int li = this.GetLocalVarIndex((Local)operand); if (li < 256) this.ILGenerator.Emit(OpCodes.Ldloca_S, this.locals[li]); else this.ILGenerator.Emit(OpCodes.Ldloca, this.locals[li]); return; case NodeType.MemberBinding: MemberBinding mb = (MemberBinding)operand; Field f = mb.BoundMember as Field; if (f == null) { Debug.Fail(""); return; } System.Reflection.FieldInfo fieldInfo = f.GetFieldInfo(); if (fieldInfo == null) { Debug.Fail(""); return; } if (mb.TargetObject != null) { this.Visit(mb.TargetObject); this.ILGenerator.Emit(OpCodes.Ldflda, fieldInfo); } else { this.ILGenerator.Emit(OpCodes.Ldsflda, fieldInfo); } return; case NodeType.Parameter: ParameterBinding pb = operand as ParameterBinding; if (pb != null) operand = pb.BoundParameter; int pi = ((Parameter)operand).ArgumentListIndex; if (pi < 256) this.ILGenerator.Emit(OpCodes.Ldarga_S, (byte)pi); else this.ILGenerator.Emit(OpCodes.Ldarga, (ushort)pi); return; } } protected virtual void VisitAssignmentStatement(AssignmentStatement assignment) { if (assignment == null) return; Expression target = assignment.Target; if (target == null) { Debug.Fail(""); return; } switch (target.NodeType) { case NodeType.Local: Local loc = (Local)target; this.Visit(assignment.Source); int li = this.GetLocalVarIndex(loc); switch (li) { case 0: this.ILGenerator.Emit(OpCodes.Stloc_0); return; case 1: this.ILGenerator.Emit(OpCodes.Stloc_1); return; case 2: this.ILGenerator.Emit(OpCodes.Stloc_2); return; case 3: this.ILGenerator.Emit(OpCodes.Stloc_3); return; default: if (li < 256) this.ILGenerator.Emit(OpCodes.Stloc_S, this.locals[li]); else this.ILGenerator.Emit(OpCodes.Stloc, this.locals[li]); return; } case NodeType.MemberBinding: MemberBinding mb = (MemberBinding)target; Field f = mb.BoundMember as Field; if (f == null) { Debug.Fail(""); return; } System.Reflection.FieldInfo fieldInfo = f.GetFieldInfo(); if (fieldInfo == null) { Debug.Fail(""); return; } if (mb.TargetObject != null) this.Visit(mb.TargetObject); this.Visit(assignment.Source); if (mb.TargetObject != null) { if (mb.Alignment != -1) this.ILGenerator.Emit(OpCodes.Unaligned, (byte)mb.Alignment); if (mb.Volatile) this.ILGenerator.Emit(OpCodes.Volatile); this.ILGenerator.Emit(OpCodes.Stfld, fieldInfo); } else this.ILGenerator.Emit(OpCodes.Stsfld, fieldInfo); return; case NodeType.Parameter: ParameterBinding pb = target as ParameterBinding; if (pb != null) target = pb.BoundParameter; Parameter par = (Parameter)target; this.Visit(assignment.Source); int pi = par.ArgumentListIndex; if (pi < 256) this.ILGenerator.Emit(OpCodes.Starg_S, (byte)pi); else this.ILGenerator.Emit(OpCodes.Starg, (ushort)pi); return; case NodeType.Indexer: Indexer indexer = (Indexer)target; this.Visit(indexer.Object); if (indexer.Operands != null && indexer.Operands.Count == 1) this.Visit(indexer.Operands[0]); this.Visit(assignment.Source); Type elementType = indexer.ElementType == null ? null : indexer.ElementType.GetRuntimeType(); if (elementType == null) { Debug.Fail(""); return; } this.ILGenerator.Emit(OpCodes.Ldelema, elementType); System.Reflection.Emit.OpCode opCode; //^ assert indexer.ElementType != null; switch (indexer.ElementType.typeCode) { case ElementType.UIntPtr: case ElementType.IntPtr: opCode = OpCodes.Stelem_I; break; case ElementType.Boolean: case ElementType.Int8: case ElementType.UInt8: opCode = OpCodes.Stelem_I1; break; case ElementType.Char: case ElementType.Int16: case ElementType.UInt16: opCode = OpCodes.Stelem_I2; break; case ElementType.Int32: case ElementType.UInt32: opCode = OpCodes.Stelem_I4; break; case ElementType.Int64: case ElementType.UInt64: opCode = OpCodes.Stelem_I8; break; case ElementType.Single: opCode = OpCodes.Stelem_R4; break; case ElementType.Double: opCode = OpCodes.Stelem_R8; break; default: if (indexer.ElementType.NodeType == NodeType.TypeParameter || indexer.ElementType.NodeType == NodeType.ClassParameter) opCode = OpCodes.Stelem; else if (TypeNode.StripModifiers(indexer.ElementType) is Pointer) opCode = OpCodes.Stelem_I; else opCode = OpCodes.Stelem_Ref; break; } if (opCode.Name == OpCodes.Stelem.Name) this.ILGenerator.Emit(opCode, indexer.ElementType.GetRuntimeType()); else this.ILGenerator.Emit(opCode); return; case NodeType.AddressDereference: AddressDereference adr = (AddressDereference)target; if (adr.Type == null) { Debug.Fail(""); return; } this.Visit(adr.Address); if (adr.Type.IsValueType || adr.Type is TypeParameter) { Literal lit = assignment.Source as Literal; if (lit != null && lit.Value == null) { this.ILGenerator.Emit(OpCodes.Initobj, adr.Type.GetRuntimeType()); return; } } this.Visit(assignment.Source); if (adr.Alignment > 0) this.ILGenerator.Emit(OpCodes.Unaligned, (byte)adr.Alignment); if (adr.Volatile) this.ILGenerator.Emit(OpCodes.Volatile); TypeNode adrType = TypeNode.StripModifiers(adr.Type); //^ assert adrType != null; switch (adrType.typeCode) { case ElementType.Int8: case ElementType.UInt8: this.ILGenerator.Emit(OpCodes.Stind_I1); return; case ElementType.Int16: case ElementType.UInt16: this.ILGenerator.Emit(OpCodes.Stind_I2); return; case ElementType.Int32: case ElementType.UInt32: this.ILGenerator.Emit(OpCodes.Stind_I4); return; case ElementType.Int64: case ElementType.UInt64: this.ILGenerator.Emit(OpCodes.Stind_I8); return; case ElementType.Single: this.ILGenerator.Emit(OpCodes.Stind_R4); return; case ElementType.Double: this.ILGenerator.Emit(OpCodes.Stind_R8); return; case ElementType.UIntPtr: case ElementType.IntPtr: this.ILGenerator.Emit(OpCodes.Stind_I); return; default: if (adrType != null && (adrType.IsValueType || adrType.NodeType == NodeType.TypeParameter || adrType.NodeType == NodeType.ClassParameter)) { this.ILGenerator.Emit(OpCodes.Stobj, adrType.GetRuntimeType()); return; } if (adrType.NodeType == NodeType.Pointer) { this.ILGenerator.Emit(OpCodes.Stind_I); return; } this.ILGenerator.Emit(OpCodes.Stind_Ref); return; } default: Debug.Assert(false, "unexpected assignment target"); return; } } protected virtual void VisitBase(Base Base) { this.ILGenerator.Emit(OpCodes.Ldarg_0); } protected virtual void VisitBinaryExpression(BinaryExpression binaryExpression) { if (binaryExpression == null) return; System.Reflection.Emit.OpCode opCode = OpCodes.Nop; this.Visit(binaryExpression.Operand1); switch (binaryExpression.NodeType) { case NodeType.Castclass: opCode = OpCodes.Castclass; goto writeOpCodeAndToken; case NodeType.Isinst: opCode = OpCodes.Isinst; goto writeOpCodeAndToken; case NodeType.Unbox: opCode = OpCodes.Unbox; goto writeOpCodeAndToken; case NodeType.UnboxAny: opCode = OpCodes.Unbox_Any; goto writeOpCodeAndToken; case NodeType.Box: opCode = OpCodes.Box; goto writeOpCodeAndToken; case NodeType.Refanyval: opCode = OpCodes.Refanyval; goto writeOpCodeAndToken; case NodeType.Mkrefany: opCode = OpCodes.Mkrefany; goto writeOpCodeAndToken; writeOpCodeAndToken: Literal lit = binaryExpression.Operand2 as Literal; if (lit != null) this.ILGenerator.Emit(opCode, ((TypeNode)lit.Value).GetRuntimeType()); else this.ILGenerator.Emit(opCode, ((TypeNode)((MemberBinding)binaryExpression.Operand2).BoundMember).GetRuntimeType()); return; case NodeType.Ldvirtftn: System.Reflection.MethodInfo meth = ((Method)((MemberBinding)binaryExpression.Operand2).BoundMember).GetMethodInfo(); if (meth == null) { Debug.Fail(""); return; } this.ILGenerator.Emit(OpCodes.Ldvirtftn, meth); return; } this.Visit(binaryExpression.Operand2); switch (binaryExpression.NodeType) { case NodeType.Add: opCode = OpCodes.Add; break; case NodeType.Sub: opCode = OpCodes.Sub; break; case NodeType.Mul: opCode = OpCodes.Mul; break; case NodeType.Div: opCode = OpCodes.Div; break; case NodeType.Div_Un: opCode = OpCodes.Div_Un; break; case NodeType.Rem: opCode = OpCodes.Rem; break; case NodeType.Rem_Un: opCode = OpCodes.Rem_Un; break; case NodeType.And: opCode = OpCodes.And; break; case NodeType.Or: opCode = OpCodes.Or; break; case NodeType.Xor: opCode = OpCodes.Xor; break; case NodeType.Shl: opCode = OpCodes.Shl; break; case NodeType.Shr: opCode = OpCodes.Shr; break; case NodeType.Shr_Un: opCode = OpCodes.Shr_Un; break; case NodeType.Add_Ovf: opCode = OpCodes.Add_Ovf; break; case NodeType.Add_Ovf_Un: opCode = OpCodes.Add_Ovf_Un; break; case NodeType.Mul_Ovf: opCode = OpCodes.Mul_Ovf; break; case NodeType.Mul_Ovf_Un: opCode = OpCodes.Mul_Ovf_Un; break; case NodeType.Sub_Ovf: opCode = OpCodes.Sub_Ovf; break; case NodeType.Sub_Ovf_Un: opCode = OpCodes.Sub_Ovf_Un; break; case NodeType.Ceq: opCode = OpCodes.Ceq; break; case NodeType.Cgt: opCode = OpCodes.Cgt; break; case NodeType.Cgt_Un: opCode = OpCodes.Cgt_Un; break; case NodeType.Clt: opCode = OpCodes.Clt; break; case NodeType.Clt_Un: opCode = OpCodes.Clt_Un; break; } this.ILGenerator.Emit(opCode); } protected virtual void VisitBlock(Block block) { if (block == null) return; if (this.catchStart[block.UniqueKey] != null) this.ILGenerator.BeginCatchBlock((Type)this.catchTypeNode[block.UniqueKey]); else if (this.finallyStart[block.UniqueKey] != null) this.ILGenerator.BeginFinallyBlock(); else { object count = this.exceptionEndCount[block.UniqueKey]; for (int i = 0, n = count == null ? 0 : (int)count; i < n; i++) this.ILGenerator.EndExceptionBlock(); count = this.exceptionStartCount[block.UniqueKey]; for (int i = 0, n = count == null ? 0 : (int)count; i < n; i++) this.ILGenerator.BeginExceptionBlock(); } Label label = this.GetLabel(block); this.ILGenerator.MarkLabel(label); StatementList statements = block.Statements; if (statements == null) return; if (block.HasLocals) this.ILGenerator.BeginScope(); for (int i = 0, n = statements.Count; i < n; i++) this.Visit(statements[i]); if (block.HasLocals) this.ILGenerator.EndScope(); } protected virtual void VisitBlockExpression(BlockExpression blockExpression) { if (blockExpression == null) return; this.VisitBlock(blockExpression.Block); } protected virtual void VisitBranch(Branch branch) { if (branch == null) return; BinaryExpression bex = branch.Condition as BinaryExpression; UnaryExpression uex = null; NodeType typeOfCondition = NodeType.Nop; if (bex != null) { switch (bex.NodeType) { case NodeType.Eq: case NodeType.Ge: case NodeType.Gt: case NodeType.Le: case NodeType.Lt: case NodeType.Ne: this.Visit(bex.Operand1); this.Visit(bex.Operand2); if (bex.Operand1 != null && bex.Operand1.Type != null && bex.Operand1.Type.IsUnsignedPrimitiveNumeric) branch.BranchIfUnordered = true; //Overloaded to mean branch if unsigned for integer operands typeOfCondition = bex.NodeType; break; case NodeType.And: case NodeType.Or: case NodeType.Xor: case NodeType.Isinst: case NodeType.Castclass: typeOfCondition = NodeType.If; goto default; default: this.Visit(branch.Condition); break; } } else { uex = branch.Condition as UnaryExpression; if (uex != null && uex.NodeType == NodeType.LogicalNot) { this.Visit(uex.Operand); typeOfCondition = NodeType.LogicalNot; } else if (branch.Condition != null) { typeOfCondition = NodeType.If; this.Visit(branch.Condition); } } Label target = this.GetLabel(branch.Target); System.Reflection.Emit.OpCode opCode = OpCodes.Nop; if (branch.ShortOffset) { switch (typeOfCondition) { case NodeType.Nop: if (branch.Condition == null) { if (branch.LeavesExceptionBlock) opCode = OpCodes.Leave_S; else opCode = OpCodes.Br_S; break; } else { opCode = OpCodes.Brtrue_S; break; } case NodeType.If: opCode = OpCodes.Brtrue_S; break; case NodeType.LogicalNot: opCode = OpCodes.Brfalse_S; break; case NodeType.Eq: opCode = OpCodes.Beq_S; break; case NodeType.Ge: if (branch.BranchIfUnordered) opCode = OpCodes.Bge_Un_S; else opCode = OpCodes.Bge_S; break; case NodeType.Gt: if (branch.BranchIfUnordered) opCode = OpCodes.Bgt_Un_S; else opCode = OpCodes.Bgt_S; break; case NodeType.Le: if (branch.BranchIfUnordered) opCode = OpCodes.Ble_Un_S; else opCode = OpCodes.Ble_S; break; case NodeType.Lt: if (branch.BranchIfUnordered) opCode = OpCodes.Blt_Un_S; else opCode = OpCodes.Blt_S; break; case NodeType.Ne: opCode = OpCodes.Bne_Un_S; break; } this.ILGenerator.Emit(opCode, target); } else { switch (typeOfCondition) { case NodeType.Nop: if (branch.Condition == null) { if (branch.LeavesExceptionBlock) opCode = OpCodes.Leave; else opCode = OpCodes.Br; break; } else { opCode = OpCodes.Brtrue; break; } case NodeType.If: opCode = OpCodes.Brtrue; break; case NodeType.LogicalNot: opCode = OpCodes.Brfalse; break; case NodeType.Eq: opCode = OpCodes.Beq; break; case NodeType.Ge: if (branch.BranchIfUnordered) opCode = OpCodes.Bge_Un; else opCode = OpCodes.Bge; break; case NodeType.Gt: if (branch.BranchIfUnordered) opCode = OpCodes.Bgt_Un; else opCode = OpCodes.Bgt; break; case NodeType.Le: if (branch.BranchIfUnordered) opCode = OpCodes.Ble_Un; else opCode = OpCodes.Ble; break; case NodeType.Lt: if (branch.BranchIfUnordered) opCode = OpCodes.Blt_Un; else opCode = OpCodes.Blt; break; case NodeType.Ne: opCode = OpCodes.Bne_Un; break; } this.ILGenerator.Emit(opCode, target); } } protected virtual void VisitMethodCall(MethodCall call) { if (call == null) return; MemberBinding mb = (MemberBinding)call.Callee; this.Visit(mb.TargetObject); ExpressionList arguments = call.Operands; if (arguments == null) arguments = new ExpressionList(0); this.VisitExpressionList(arguments); if (call.IsTailCall) this.ILGenerator.Emit(OpCodes.Tailcall); else if (call.Constraint != null) this.ILGenerator.Emit(OpCodes.Constrained, call.Constraint.GetRuntimeType()); if (call.NodeType == NodeType.Calli) { FunctionPointer fp = (FunctionPointer)mb.BoundMember; CallingConventionFlags callConv = fp.CallingConvention & CallingConventionFlags.ArgumentConvention; if (callConv != CallingConventionFlags.VarArg) { Type[] parameterTypes = new Type[fp.ParameterTypes.Count]; for (int i = 0, n = fp.ParameterTypes.Count; i < n; i++) { parameterTypes[i] = fp.ParameterTypes[i].GetRuntimeType(); } this.ILGenerator.EmitCalli(OpCodes.Calli, (System.Runtime.InteropServices.CallingConvention)callConv, fp.ReturnType.GetRuntimeType(), parameterTypes); } else { Type[] parameterTypes = new Type[fp.VarArgStart]; Type[] optionalParameterTypes = new Type[fp.ParameterTypes.Count - fp.VarArgStart]; for (int i = 0, n = fp.ParameterTypes.Count; i < n; i++) { if (i < fp.VarArgStart) parameterTypes[i] = fp.ParameterTypes[i].GetRuntimeType(); else optionalParameterTypes[i - fp.VarArgStart] = fp.ParameterTypes[i].GetRuntimeType(); } this.ILGenerator.EmitCalli(OpCodes.Calli, (System.Reflection.CallingConventions)callConv, fp.ReturnType.GetRuntimeType(), parameterTypes, optionalParameterTypes); } return; } Method method = (Method)mb.BoundMember; System.Reflection.MethodInfo methodInfo = method.GetMethodInfo(); if (methodInfo == null) { Debug.Fail(""); return; } System.Reflection.Emit.OpCode opCode; switch (call.NodeType) { case NodeType.Callvirt: opCode = OpCodes.Callvirt; break; case NodeType.Jmp: opCode = OpCodes.Jmp; break; default: opCode = OpCodes.Call; break; } if ((method.CallingConvention & CallingConventionFlags.ArgumentConvention) == CallingConventionFlags.VarArg || (method.CallingConvention & CallingConventionFlags.ArgumentConvention) == CallingConventionFlags.C) { int varArgStart = method.Parameters.Count; Type[] optionalParameterTypes = new Type[arguments.Count - varArgStart]; for (int i = varArgStart, n = arguments.Count; i < n; i++) optionalParameterTypes[i - varArgStart] = arguments[i].Type.GetRuntimeType(); this.ILGenerator.EmitCall(opCode, methodInfo, optionalParameterTypes); } else this.ILGenerator.EmitCall(opCode, methodInfo, null); } protected virtual void VisitConstruct(Construct cons) { if (cons == null) return; ExpressionList operands = cons.Operands; if (operands != null) { this.VisitExpressionList(cons.Operands); } Method method = (Method)((MemberBinding)cons.Constructor).BoundMember; System.Reflection.MethodInfo methodInfo = method.GetMethodInfo(); if (methodInfo != null) this.ILGenerator.Emit(OpCodes.Newobj, methodInfo); } protected virtual void VisitConstructArray(ConstructArray consArr) { if (consArr == null || consArr.Operands == null || consArr.Operands.Count == 0) return; this.Visit(consArr.Operands[0]); this.ILGenerator.Emit(OpCodes.Newarr, consArr.ElementType.GetRuntimeType()); } protected virtual void VisitEndFilter(EndFilter endFilter) { this.ILGenerator.Emit(OpCodes.Endfilter); } protected virtual void VisitExpression(Expression expression) { if (expression == null) return; switch (expression.NodeType) { case NodeType.Dup: this.ILGenerator.Emit(OpCodes.Dup); return; case NodeType.Pop: UnaryExpression unex = expression as UnaryExpression; if (unex != null) { this.Visit(unex.Operand); this.ILGenerator.Emit(OpCodes.Pop); } return; case NodeType.Arglist: this.ILGenerator.Emit(OpCodes.Arglist); return; } } protected virtual void VisitExpressionList(ExpressionList expressions) { if (expressions == null) return; for (int i = 0, n = expressions.Count; i < n; i++) this.Visit(expressions[i]); } protected virtual void VisitExpressionStatement(ExpressionStatement statement) { if (statement == null) return; this.Visit(statement.Expression); } protected virtual void VisitIndexer(Indexer indexer) { if (indexer == null || indexer.Operands == null || indexer.Operands.Count == 0) return; this.Visit(indexer.Object); this.Visit(indexer.Operands[0]); System.Reflection.Emit.OpCode opCode; switch (indexer.ElementType.typeCode) { case ElementType.Boolean: case ElementType.Int8: opCode = OpCodes.Ldelem_I1; break; case ElementType.UInt8: opCode = OpCodes.Ldelem_U1; break; case ElementType.Int16: opCode = OpCodes.Ldelem_I2; break; case ElementType.Char: case ElementType.UInt16: opCode = OpCodes.Ldelem_U2; break; case ElementType.Int32: opCode = OpCodes.Ldelem_I4; break; case ElementType.UInt32: opCode = OpCodes.Ldelem_U4; break; case ElementType.Int64: case ElementType.UInt64: opCode = OpCodes.Ldelem_I8; break; case ElementType.UIntPtr: case ElementType.IntPtr: opCode = OpCodes.Ldelem_I; break; case ElementType.Single: opCode = OpCodes.Ldelem_R4; break; case ElementType.Double: opCode = OpCodes.Ldelem_R8; break; default: if (indexer.ElementType.NodeType == NodeType.TypeParameter || indexer.ElementType.NodeType == NodeType.ClassParameter) opCode = OpCodes.Ldelem; else if (indexer.ElementType is Pointer) opCode = OpCodes.Ldelem_I; else opCode = OpCodes.Ldelem_Ref; break; } if (opCode.Name == OpCodes.Ldelem.Name) this.ILGenerator.Emit(opCode, indexer.ElementType.GetRuntimeType()); else this.ILGenerator.Emit(opCode); } protected virtual void VisitLocal(Local local) { if (local == null) return; int li = this.GetLocalVarIndex(local); switch (li) { case 0: this.ILGenerator.Emit(OpCodes.Ldloc_0); return; case 1: this.ILGenerator.Emit(OpCodes.Ldloc_1); return; case 2: this.ILGenerator.Emit(OpCodes.Ldloc_2); return; case 3: this.ILGenerator.Emit(OpCodes.Ldloc_3); return; default: if (li < 256) this.ILGenerator.Emit(OpCodes.Ldloc_S, (byte)li); else this.ILGenerator.Emit(OpCodes.Ldloc, (ushort)li); return; } } protected virtual void VisitLiteral(Literal literal) { if (literal == null) return; IConvertible ic = literal.Value as IConvertible; if (ic == null) { Debug.Assert(literal.Value == null && !literal.Type.IsValueType); this.ILGenerator.Emit(OpCodes.Ldnull); return; } TypeCode tc = ic.GetTypeCode(); switch (tc) { case TypeCode.Boolean: case TypeCode.SByte: case TypeCode.Byte: case TypeCode.Char: case TypeCode.Int16: case TypeCode.UInt16: case TypeCode.Int32: case TypeCode.UInt32: case TypeCode.Int64: long n = ic.ToInt64(null); switch (n) { case -1: this.ILGenerator.Emit(OpCodes.Ldc_I4_M1); break; case 0: this.ILGenerator.Emit(OpCodes.Ldc_I4_0); break; case 1: this.ILGenerator.Emit(OpCodes.Ldc_I4_1); break; case 2: this.ILGenerator.Emit(OpCodes.Ldc_I4_2); break; case 3: this.ILGenerator.Emit(OpCodes.Ldc_I4_3); break; case 4: this.ILGenerator.Emit(OpCodes.Ldc_I4_4); break; case 5: this.ILGenerator.Emit(OpCodes.Ldc_I4_5); break; case 6: this.ILGenerator.Emit(OpCodes.Ldc_I4_6); break; case 7: this.ILGenerator.Emit(OpCodes.Ldc_I4_7); break; case 8: this.ILGenerator.Emit(OpCodes.Ldc_I4_8); break; default: if (n >= System.SByte.MinValue && n <= System.SByte.MaxValue) { this.ILGenerator.Emit(OpCodes.Ldc_I4_S, (byte)n); } else if (n >= System.Int32.MinValue && n <= System.Int32.MaxValue || n <= System.UInt32.MaxValue && (tc == TypeCode.Char || tc == TypeCode.UInt16 || tc == TypeCode.UInt32)) { if (n == System.UInt32.MaxValue && tc != TypeCode.Int64) this.ILGenerator.Emit(OpCodes.Ldc_I4_M1); else { this.ILGenerator.Emit(OpCodes.Ldc_I4, (int)n); } } else { this.ILGenerator.Emit(OpCodes.Ldc_I8, (long)n); tc = TypeCode.Empty; //Suppress conversion to long } break; } if (tc == TypeCode.Int64) this.ILGenerator.Emit(OpCodes.Conv_I8); return; case TypeCode.UInt64: this.ILGenerator.Emit(OpCodes.Ldc_I8, ic.ToUInt64(null)); return; case TypeCode.Single: this.ILGenerator.Emit(OpCodes.Ldc_R4, ic.ToSingle(null)); return; case TypeCode.Double: this.ILGenerator.Emit(OpCodes.Ldc_R8, ic.ToDouble(null)); return; case TypeCode.String: this.ILGenerator.Emit(OpCodes.Ldstr, (string)literal.Value); return; } Debug.Assert(false, "Unexpected literal type"); } protected virtual void VisitMemberBinding(MemberBinding memberBinding) { if (memberBinding == null) return; System.Reflection.FieldInfo fieldInfo = ((Field)memberBinding.BoundMember).GetFieldInfo(); if (memberBinding.TargetObject != null) { this.Visit(memberBinding.TargetObject); this.ILGenerator.Emit(OpCodes.Ldfld, fieldInfo); } else { this.ILGenerator.Emit(OpCodes.Ldsfld, fieldInfo); } return; } protected virtual void VisitParameter(Parameter parameter) { if (parameter == null) return; ParameterBinding pb = parameter as ParameterBinding; if (pb != null) parameter = pb.BoundParameter; int pi = parameter.ArgumentListIndex; switch (pi) { case 0: this.ILGenerator.Emit(OpCodes.Ldarg_0); return; case 1: this.ILGenerator.Emit(OpCodes.Ldarg_1); return; case 2: this.ILGenerator.Emit(OpCodes.Ldarg_2); return; case 3: this.ILGenerator.Emit(OpCodes.Ldarg_3); return; default: if (pi < 256) this.ILGenerator.Emit(OpCodes.Ldarg_S, (byte)pi); else this.ILGenerator.Emit(OpCodes.Ldarg, (ushort)pi); return; } } protected virtual void VisitReturn(Return Return) { if (Return == null) return; if (Return.Expression != null) { this.Visit(Return.Expression); } this.ILGenerator.Emit(OpCodes.Ret); } protected virtual void VisitStatement(Statement statement) { if (statement == null) return; switch (statement.NodeType) { case NodeType.Nop: this.ILGenerator.Emit(OpCodes.Nop); break; case NodeType.DebugBreak: this.ILGenerator.Emit(OpCodes.Break); break; case NodeType.EndFinally: this.ILGenerator.Emit(OpCodes.Endfinally); break; } } protected virtual void VisitSwitchInstruction(SwitchInstruction switchInstruction) { if (switchInstruction == null) return; this.Visit(switchInstruction.Expression); BlockList targets = switchInstruction.Targets; int n = targets != null ? targets.Count : 0; Label[] labelTable = new Label[n]; for (int i = 0; i < n; i++) labelTable[i] = this.GetLabel(targets[i]); this.ILGenerator.Emit(OpCodes.Switch, labelTable); } protected virtual void VisitTernaryExpression(TernaryExpression expression) { if (expression == null) return; this.Visit(expression.Operand1); this.Visit(expression.Operand2); this.Visit(expression.Operand3); if (expression.NodeType == NodeType.Cpblk) this.ILGenerator.Emit(OpCodes.Cpblk); else this.ILGenerator.Emit(OpCodes.Initblk); } protected virtual void VisitThis(This This) { this.ILGenerator.Emit(OpCodes.Ldarg_0); } protected virtual void VisitThrow(Throw Throw) { if (Throw == null) return; if (Throw.NodeType == NodeType.Rethrow) this.ILGenerator.Emit(OpCodes.Rethrow); else { this.Visit(Throw.Expression); this.ILGenerator.Emit(OpCodes.Throw); } } protected virtual void VisitUnaryExpression(UnaryExpression unaryExpression) { if (unaryExpression == null) return; switch (unaryExpression.NodeType) { case NodeType.Ldtoken: Literal lit = unaryExpression.Operand as Literal; if (lit != null) this.ILGenerator.Emit(OpCodes.Ldtoken, ((TypeNode)lit.Value).GetRuntimeType()); else { Member m = ((MemberBinding)unaryExpression.Operand).BoundMember; Method meth = m as Method; if (meth != null) { System.Reflection.MethodInfo methInfo = meth.GetMethodInfo(); if (methInfo == null) return; this.ILGenerator.Emit(OpCodes.Ldtoken, methInfo); } else { System.Reflection.FieldInfo fieldInfo = ((Field)m).GetFieldInfo(); if (fieldInfo == null) return; this.ILGenerator.Emit(OpCodes.Ldtoken, fieldInfo); } } return; case NodeType.Ldftn: { System.Reflection.MethodInfo methInfo = ((Method)((MemberBinding)unaryExpression.Operand).BoundMember).GetMethodInfo(); if (methInfo != null) this.ILGenerator.Emit(OpCodes.Ldftn, methInfo); return; } case NodeType.Sizeof: this.ILGenerator.Emit(OpCodes.Sizeof, ((TypeNode)((Literal)unaryExpression.Operand).Value).GetRuntimeType()); return; } this.Visit(unaryExpression.Operand); System.Reflection.Emit.OpCode opCode = OpCodes.Nop; switch (unaryExpression.NodeType) { case NodeType.Neg: opCode = OpCodes.Neg; break; case NodeType.Not: opCode = OpCodes.Not; break; case NodeType.Conv_I1: opCode = OpCodes.Conv_I1; break; case NodeType.Conv_I2: opCode = OpCodes.Conv_I2; break; case NodeType.Conv_I4: opCode = OpCodes.Conv_I4; break; case NodeType.Conv_I8: opCode = OpCodes.Conv_I8; break; case NodeType.Conv_R4: opCode = OpCodes.Conv_R4; break; case NodeType.Conv_R8: opCode = OpCodes.Conv_R8; break; case NodeType.Conv_U4: opCode = OpCodes.Conv_U4; break; case NodeType.Conv_U8: opCode = OpCodes.Conv_U8; break; case NodeType.Conv_R_Un: opCode = OpCodes.Conv_R_Un; break; case NodeType.Conv_Ovf_I1_Un: opCode = OpCodes.Conv_Ovf_I1_Un; break; case NodeType.Conv_Ovf_I2_Un: opCode = OpCodes.Conv_Ovf_I2_Un; break; case NodeType.Conv_Ovf_I4_Un: opCode = OpCodes.Conv_Ovf_I4_Un; break; case NodeType.Conv_Ovf_I8_Un: opCode = OpCodes.Conv_Ovf_I8_Un; break; case NodeType.Conv_Ovf_U1_Un: opCode = OpCodes.Conv_Ovf_U1_Un; break; case NodeType.Conv_Ovf_U2_Un: opCode = OpCodes.Conv_Ovf_U2_Un; break; case NodeType.Conv_Ovf_U4_Un: opCode = OpCodes.Conv_Ovf_U4_Un; break; case NodeType.Conv_Ovf_U8_Un: opCode = OpCodes.Conv_Ovf_U8_Un; break; case NodeType.Conv_Ovf_I_Un: opCode = OpCodes.Conv_Ovf_I_Un; break; case NodeType.Conv_Ovf_U_Un: opCode = OpCodes.Conv_Ovf_U_Un; break; case NodeType.Ldlen: opCode = OpCodes.Ldlen; break; case NodeType.Conv_Ovf_I1: opCode = OpCodes.Conv_Ovf_I1; break; case NodeType.Conv_Ovf_U1: opCode = OpCodes.Conv_Ovf_U1; break; case NodeType.Conv_Ovf_I2: opCode = OpCodes.Conv_Ovf_I2; break; case NodeType.Conv_Ovf_U2: opCode = OpCodes.Conv_Ovf_U2; break; case NodeType.Conv_Ovf_I4: opCode = OpCodes.Conv_Ovf_I4; break; case NodeType.Conv_Ovf_U4: opCode = OpCodes.Conv_Ovf_U4; break; case NodeType.Conv_Ovf_I8: opCode = OpCodes.Conv_Ovf_I8; break; case NodeType.Conv_Ovf_U8: opCode = OpCodes.Conv_Ovf_U8; break; case NodeType.Ckfinite: opCode = OpCodes.Ckfinite; break; case NodeType.Conv_U2: opCode = OpCodes.Conv_U2; break; case NodeType.Conv_U1: opCode = OpCodes.Conv_U1; break; case NodeType.Conv_I: opCode = OpCodes.Conv_I; break; case NodeType.Conv_Ovf_I: opCode = OpCodes.Conv_Ovf_I; break; case NodeType.Conv_Ovf_U: opCode = OpCodes.Conv_Ovf_U; break; case NodeType.Conv_U: opCode = OpCodes.Conv_U; break; case NodeType.Localloc: opCode = OpCodes.Localloc; break; case NodeType.Refanytype: opCode = OpCodes.Refanytype; break; } this.ILGenerator.Emit(opCode); } } } #endif