/// <summary> /// Emit the end cases for a short-circuit /// </summary> /// <param name="info"></param> /// <param name="ilg"></param> /// <param name="endLabel"></param> private static void EmitTerminals(ShortCircuitInfo info, FleeILGenerator ilg, Label endLabel) { // Emit the false case if it was used if (info.Branches.HasLabel(OurFalseTerminalKey) == true) { Label falseLabel = info.Branches.FindLabel(OurFalseTerminalKey); // Mark the label and note its position ilg.MarkLabel(falseLabel); MarkBranchTarget(info, falseLabel, ilg); ilg.Emit(OpCodes.Ldc_I4_0); // If we also have a true terminal, then skip over it if (info.Branches.HasLabel(OurTrueTerminalKey) == true) { ilg.Emit(OpCodes.Br_S, endLabel); } } // Emit the true case if it was used if (info.Branches.HasLabel(OurTrueTerminalKey) == true) { Label trueLabel = info.Branches.FindLabel(OurTrueTerminalKey); // Mark the label and note its position ilg.MarkLabel(trueLabel); MarkBranchTarget(info, trueLabel, ilg); ilg.Emit(OpCodes.Ldc_I4_1); } }
// If the shift count is greater than the number of bits in the number, the result is undefined. // So we play it safe and force the shift count to 32/64 bits by ANDing it with the appropriate mask. private void EmitShiftCount(FleeILGenerator ilg, IServiceProvider services) { MyRightChild.Emit(ilg, services); TypeCode tc = Type.GetTypeCode(MyLeftChild.ResultType); switch (tc) { case TypeCode.Byte: case TypeCode.SByte: case TypeCode.Int16: case TypeCode.UInt16: case TypeCode.Int32: case TypeCode.UInt32: ilg.Emit(OpCodes.Ldc_I4_S, Convert.ToSByte(0x1f)); break; case TypeCode.Int64: case TypeCode.UInt64: ilg.Emit(OpCodes.Ldc_I4_S, Convert.ToSByte(0x3f)); break; default: Debug.Assert(false, "unknown left shift operand"); break; } ilg.Emit(OpCodes.And); }
private void EmitOptimizedPower(FleeILGenerator ilg, bool emitOverflow, bool unsigned) { Int32LiteralElement right = (Int32LiteralElement)MyRightChild; if (right.Value == 0) { ilg.Emit(OpCodes.Pop); IntegralLiteralElement.EmitLoad(1, ilg); ImplicitConverter.EmitImplicitNumericConvert(typeof(Int32), MyLeftChild.ResultType, ilg); return; } if (right.Value == 1) { return; } // Start at 1 since left operand has already been emited once for (int i = 1; i <= right.Value - 1; i++) { ilg.Emit(OpCodes.Dup); } for (int i = 1; i <= right.Value - 1; i++) { this.EmitMultiply(ilg, emitOverflow, unsigned); } }
private static void EmitLdfld(System.Reflection.FieldInfo fi, bool indirect, FleeILGenerator ilg) { if (fi.IsStatic == true) { if (indirect == true) { ilg.Emit(OpCodes.Ldsflda, fi); } else { ilg.Emit(OpCodes.Ldsfld, fi); } } else { if (indirect == true) { ilg.Emit(OpCodes.Ldflda, fi); } else { ilg.Emit(OpCodes.Ldfld, fi); } } }
internal void EmitLoad(string tailName, FleeILGenerator ilg) { PropertyInfo pi = typeof(ExpressionContext).GetProperty("CalculationEngine"); ilg.Emit(OpCodes.Callvirt, pi.GetGetMethod()); // Load the tail MemberInfo[] methods = typeof(CalculationEngine).FindMembers(MemberTypes.Method, BindingFlags.Instance | BindingFlags.Public, Type.FilterNameIgnoreCase, "GetResult"); MethodInfo mi = null; foreach (MethodInfo method in methods) { if (method.IsGenericMethod == true) { mi = method; break; // TODO: might not be correct. Was : Exit For } } Type resultType = this.ResolveTailType(tailName); mi = mi.MakeGenericMethod(resultType); ilg.Emit(OpCodes.Ldstr, tailName); ilg.Emit(OpCodes.Call, mi); }
private void EmitListIn(FleeILGenerator ilg, IServiceProvider services) { CompareElement ce = new CompareElement(); Label endLabel = ilg.DefineLabel(); Label trueTerminal = ilg.DefineLabel(); // Cache the operand since we will be comparing against it a lot LocalBuilder lb = ilg.DeclareLocal(MyOperand.ResultType); int targetIndex = lb.LocalIndex; MyOperand.Emit(ilg, services); Utility.EmitStoreLocal(ilg, targetIndex); // Wrap our operand in a local shim LocalBasedElement targetShim = new LocalBasedElement(MyOperand, targetIndex); // Emit the compares foreach (ExpressionElement argumentElement in MyArguments) { ce.Initialize(targetShim, argumentElement, LogicalCompareOperation.Equal); ce.Emit(ilg, services); EmitBranchToTrueTerminal(ilg, trueTerminal); } ilg.Emit(OpCodes.Ldc_I4_0); ilg.Emit(OpCodes.Br_S, endLabel); ilg.MarkLabel(trueTerminal); ilg.Emit(OpCodes.Ldc_I4_1); ilg.MarkLabel(endLabel); }
protected static void EmitLoad(bool value, FleeILGenerator ilg) { if (value == true) { ilg.Emit(OpCodes.Ldc_I4_1); } else { ilg.Emit(OpCodes.Ldc_I4_0); } }
private static void EmitReferenceTypeMethodCall(MethodInfo mi, FleeILGenerator ilg) { if (mi.IsStatic == true) { ilg.Emit(OpCodes.Call, mi); } else { ilg.Emit(OpCodes.Callvirt, mi); } }
private void EmitCast(FleeILGenerator ilg, Type sourceType, Type destType, IServiceProvider services) { MethodInfo explicitOperator = this.GetExplictOverloadedOperator(sourceType, destType); if (object.ReferenceEquals(sourceType, destType)) { // Identity cast; do nothing return; } else if ((explicitOperator != null)) { ilg.Emit(OpCodes.Call, explicitOperator); } else if (sourceType.IsEnum == true | destType.IsEnum == true) { this.EmitEnumCast(ilg, sourceType, destType, services); } else if (ImplicitConverter.EmitImplicitConvert(sourceType, destType, ilg) == true) { // Implicit numeric cast; do nothing return; } else if (IsCastableNumericType(sourceType) & IsCastableNumericType(destType)) { // Explicit numeric cast EmitExplicitNumericCast(ilg, sourceType, destType, services); } else if (sourceType.IsValueType == true) { Debug.Assert(destType.IsValueType == false, "expecting reference type"); ilg.Emit(OpCodes.Box, sourceType); } else { if (destType.IsValueType == true) { // Reference type to value type ilg.Emit(OpCodes.Unbox_Any, destType); } else { // Reference type to reference type if (destType.IsAssignableFrom(sourceType) == false) { // Only emit cast if it is an explicit cast ilg.Emit(OpCodes.Castclass, destType); } } } }
public static void EmitLoad(Int32 value, FleeILGenerator ilg) { if (value >= -1 & value <= 8) { EmitSuperShort(value, ilg); } else if (value >= sbyte.MinValue & value <= sbyte.MaxValue) { ilg.Emit(OpCodes.Ldc_I4_S, Convert.ToSByte(value)); } else { ilg.Emit(OpCodes.Ldc_I4, value); } }
/// <summary> /// Emit a string concatenation /// </summary> /// <param name="ilg"></param> /// <param name="services"></param> private void EmitStringConcat(FleeILGenerator ilg, IServiceProvider services) { Type argType = default(Type); System.Reflection.MethodInfo concatMethodInfo = default(System.Reflection.MethodInfo); // Pick the most specific concat method if (this.AreBothChildrenOfType(typeof(string)) == true) { concatMethodInfo = _ourStringConcatMethodInfo; argType = typeof(string); } else { Debug.Assert(this.IsEitherChildOfType(typeof(string)), "one child must be a string"); concatMethodInfo = _ourObjectConcatMethodInfo; argType = typeof(object); } // Emit the operands and call the function MyLeftChild.Emit(ilg, services); ImplicitConverter.EmitImplicitConvert(MyLeftChild.ResultType, argType, ilg); MyRightChild.Emit(ilg, services); ImplicitConverter.EmitImplicitConvert(MyRightChild.ResultType, argType, ilg); ilg.Emit(OpCodes.Call, concatMethodInfo); }
protected static void EmitValueTypeLoadAddress(FleeILGenerator ilg, Type targetType) { int index = ilg.GetTempLocalIndex(targetType); Utility.EmitStoreLocal(ilg, index); ilg.Emit(OpCodes.Ldloca_S, Convert.ToByte(index)); }
private void EmitVariableLoad(FleeILGenerator ilg) { MethodInfo mi = VariableCollection.GetVariableLoadMethod(_myVariableType); ilg.Emit(OpCodes.Ldstr, MyName); this.EmitMethodCall(mi, ilg); }
/// <summary> /// Emit elements into an array /// </summary> /// <param name="elements"></param> /// <param name="arrayElementType"></param> /// <param name="ilg"></param> /// <param name="services"></param> private static void EmitElementArrayLoad(ExpressionElement[] elements, Type arrayElementType, FleeILGenerator ilg, IServiceProvider services) { // Load the array length LiteralElement.EmitLoad(elements.Length, ilg); // Create the array ilg.Emit(OpCodes.Newarr, arrayElementType); // Store the new array in a unique local and remember the index LocalBuilder local = ilg.DeclareLocal(arrayElementType.MakeArrayType()); int arrayLocalIndex = local.LocalIndex; Utility.EmitStoreLocal(ilg, arrayLocalIndex); for (int i = 0; i <= elements.Length - 1; i++) { // Load the array Utility.EmitLoadLocal(ilg, arrayLocalIndex); // Load the index LiteralElement.EmitLoad(i, ilg); // Emit the element (with any required conversions) ExpressionElement element = elements[i]; element.Emit(ilg, services); ImplicitConverter.EmitImplicitConvert(element.ResultType, arrayElementType, ilg); // Store it into the array Utility.EmitArrayStore(ilg, arrayElementType); } // Load the array Utility.EmitLoadLocal(ilg, arrayLocalIndex); }
/// <summary> /// Emit a short-circuited logical operation sequence /// The idea: Store all the leaf operands in a stack with the leftmost at the top and rightmost at the bottom. /// For each operand, emit it and try to find an end point for when it short-circuits. This means we go up through /// the stack of operators (ignoring siblings) until we find a different operation (then emit a branch to its right operand) /// or we reach the root (emit a branch to a true/false). /// Repeat the process for all operands and then emit the true/false/last operand end cases. /// </summary> /// <param name="ilg"></param> /// <param name="info"></param> /// <param name="services"></param> private void EmitLogical(FleeILGenerator ilg, ShortCircuitInfo info, IServiceProvider services) { // We always have an end label info.Branches.GetLabel(OurEndLabelKey, ilg); // Populate our data structures this.PopulateData(info); // Emit the sequence EmitLogicalShortCircuit(ilg, info, services); // Get the last operand ExpressionElement terminalOperand = (ExpressionElement)info.Operands.Pop(); // Emit it EmitOperand(terminalOperand, info, ilg, services); // And jump to the end Label endLabel = info.Branches.FindLabel(OurEndLabelKey); ilg.Emit(OpCodes.Br_S, endLabel); // Emit our true/false terminals EmitTerminals(info, ilg, endLabel); // Mark the end ilg.MarkLabel(endLabel); }
private static void EmitBranchToTrueTerminal(FleeILGenerator ilg, Label trueTerminal, BranchManager bm) { if (ilg.IsTemp == true) { bm.AddBranch(ilg, trueTerminal); ilg.Emit(OpCodes.Brtrue_S, trueTerminal); } else if (bm.IsLongBranch(ilg, trueTerminal) == false) { ilg.Emit(OpCodes.Brtrue_S, trueTerminal); } else { ilg.Emit(OpCodes.Brtrue, trueTerminal); } }
private void EmitEnumCast(FleeILGenerator ilg, Type sourceType, Type destType, IServiceProvider services) { if (destType.IsValueType == false) { ilg.Emit(OpCodes.Box, sourceType); } else if (sourceType.IsValueType == false) { ilg.Emit(OpCodes.Unbox_Any, destType); } else { sourceType = GetUnderlyingEnumType(sourceType); destType = GetUnderlyingEnumType(destType); this.EmitCast(ilg, sourceType, destType, services); } }
public override void Emit(FleeILGenerator ilg, IServiceProvider services) { EmitChild(_operand, _operand.ResultType, ilg, services); EmitChild(_from, _operand.ResultType, ilg, services); EmitChild(_to, _operand.ResultType, ilg, services); ilg.Emit(OpCodes.Call, _betweenMethodInfo.MakeGenericMethod(_operand.ResultType)); }
private static void EmitBitwiseOperation(FleeILGenerator ilg, AndOrOperation op) { switch (op) { case AndOrOperation.And: ilg.Emit(OpCodes.And); break; case AndOrOperation.Or: ilg.Emit(OpCodes.Or); break; default: Debug.Fail("Unknown op type"); break; } }
protected static void EmitLoad(Int64 value, FleeILGenerator ilg) { if (value >= Int32.MinValue & value <= Int32.MaxValue) { EmitLoad(Convert.ToInt32(value), ilg); ilg.Emit(OpCodes.Conv_I8); } else if (value >= 0 & value <= UInt32.MaxValue) { EmitLoad(Convert.ToInt32(value), ilg); ilg.Emit(OpCodes.Conv_U8); } else { ilg.Emit(OpCodes.Ldc_I8, value); } }
private static void EmitStringEquality(FleeILGenerator ilg, LogicalCompareOperation op, IServiceProvider services) { // Get the StringComparison from the options ExpressionOptions options = (ExpressionOptions)services.GetService(typeof(ExpressionOptions)); Int32LiteralElement ic = new Int32LiteralElement((int)options.StringComparison); ic.Emit(ilg, services); // and emit the method call System.Reflection.MethodInfo mi = typeof(string).GetMethod("Equals", new Type[] { typeof(string), typeof(string), typeof(StringComparison) }, null); ilg.Emit(OpCodes.Call, mi); if (op == LogicalCompareOperation.NotEqual) { ilg.Emit(OpCodes.Ldc_I4_0); ilg.Emit(OpCodes.Ceq); } }
private void EmitMultiply(FleeILGenerator ilg, bool emitOverflow, bool unsigned) { if (emitOverflow == true) { if (unsigned == true) { ilg.Emit(OpCodes.Mul_Ovf_Un); } else { ilg.Emit(OpCodes.Mul_Ovf); } } else { ilg.Emit(OpCodes.Mul); } }
public override void Emit(FleeILGenerator ilg, IServiceProvider services) { Type resultType = this.ResultType; MyChild.Emit(ilg, services); ImplicitConverter.EmitImplicitConvert(MyChild.ResultType, resultType, ilg); MethodInfo mi = Utility.GetSimpleOverloadedOperator("UnaryNegation", resultType, null); if (mi == null) { ilg.Emit(OpCodes.Neg); } else { ilg.Emit(OpCodes.Call, mi); } }
private void EmitCustomInMethod(FleeILGenerator ilg, IServiceProvider services) { int arraySize = _myArguments.Count; Type arrayElementType = _myOperand.ResultType; Type arrayType = arrayElementType.MakeArrayType(); // Load the array length LdcI4(ilg, arraySize); // Create the array ilg.Emit(OpCodes.Newarr, arrayElementType); // Store the new array in a unique local and remember the index LocalBuilder local = ilg.DeclareLocal(arrayType); int arrayLocalIndex = local.LocalIndex; Utility.EmitStoreLocal(ilg, arrayLocalIndex); for (int i = 0; i < _myArguments.Count; i++) { ExpressionElement argumentElement = _myArguments[i]; // Load the array Utility.EmitLoadLocal(ilg, arrayLocalIndex); // Load the index LdcI4(ilg, i); EmitChild(argumentElement, arrayElementType, ilg, services); // Store it into the array Utility.EmitArrayStore(ilg, arrayElementType); } EmitChild(_myOperand, arrayElementType, ilg, services); // Load the array Utility.EmitLoadLocal(ilg, arrayLocalIndex); MethodInfo genericMethod = s_InMethodInfo.MakeGenericMethod(arrayElementType); ilg.Emit(OpCodes.Call, genericMethod); }
public override void Emit(FleeILGenerator ilg, IServiceProvider services) { Type resultType = this.ResultType; MyLeftChild.Emit(ilg, services); ImplicitConverter.EmitImplicitConvert(MyLeftChild.ResultType, resultType, ilg); MyRightChild.Emit(ilg, services); ImplicitConverter.EmitImplicitConvert(MyRightChild.ResultType, resultType, ilg); ilg.Emit(OpCodes.Xor); }
protected void EmitOverloadedOperatorCall(MethodInfo method, FleeILGenerator ilg, IServiceProvider services) { ParameterInfo[] @params = method.GetParameters(); ParameterInfo pLeft = @params[0]; ParameterInfo pRight = @params[1]; EmitChildWithConvert(MyLeftChild, pLeft.ParameterType, ilg, services); EmitChildWithConvert(MyRightChild, pRight.ParameterType, ilg, services); ilg.Emit(OpCodes.Call, method); }
protected void EmitLoadOwner(FleeILGenerator ilg) { ilg.Emit(OpCodes.Ldarg_0); Type ownerType = MyOptions.OwnerType; if (ownerType.IsValueType == false) { return; } ilg.Emit(OpCodes.Unbox, ownerType); ilg.Emit(OpCodes.Ldobj, ownerType); // Emit usual stuff for value types but use the owner type as the target if (this.RequiresAddress == true) { EmitValueTypeLoadAddress(ilg, ownerType); } }
private void EmitValueTypeArrayLoad(FleeILGenerator ilg, Type elementType) { if (this.NextRequiresAddress == true) { ilg.Emit(OpCodes.Ldelema, elementType); } else { Utility.EmitArrayLoad(ilg, elementType); } }
private void EmitPower(FleeILGenerator ilg, bool emitOverflow, bool unsigned) { if (this.IsOptimizablePower == true) { this.EmitOptimizedPower(ilg, emitOverflow, unsigned); } else { ilg.Emit(OpCodes.Call, _ourPowerMethodInfo); } }
private static void EmitSuperShort(Int32 value, FleeILGenerator ilg) { OpCode ldcOpcode = default(OpCode); switch (value) { case 0: ldcOpcode = OpCodes.Ldc_I4_0; break; case 1: ldcOpcode = OpCodes.Ldc_I4_1; break; case 2: ldcOpcode = OpCodes.Ldc_I4_2; break; case 3: ldcOpcode = OpCodes.Ldc_I4_3; break; case 4: ldcOpcode = OpCodes.Ldc_I4_4; break; case 5: ldcOpcode = OpCodes.Ldc_I4_5; break; case 6: ldcOpcode = OpCodes.Ldc_I4_6; break; case 7: ldcOpcode = OpCodes.Ldc_I4_7; break; case 8: ldcOpcode = OpCodes.Ldc_I4_8; break; case -1: ldcOpcode = OpCodes.Ldc_I4_M1; break; default: Debug.Assert(false, "value out of range"); break; } ilg.Emit(ldcOpcode); }