diff options
Diffstat (limited to 'tools/Sandcastle/Source/CCI/ILGenerator.cs')
-rw-r--r-- | tools/Sandcastle/Source/CCI/ILGenerator.cs | 1152 |
1 files changed, 1152 insertions, 0 deletions
diff --git a/tools/Sandcastle/Source/CCI/ILGenerator.cs b/tools/Sandcastle/Source/CCI/ILGenerator.cs new file mode 100644 index 0000000..6010762 --- /dev/null +++ b/tools/Sandcastle/Source/CCI/ILGenerator.cs @@ -0,0 +1,1152 @@ +// 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<LocalBuilder/*!*/>/*!*/ locals = new List<LocalBuilder/*!*/>(); + 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
\ No newline at end of file |