// 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(YaleIlGenerator ilg, ExpressionContext context) { RightChild.Emit(ilg, context); var typeCode = Type.GetTypeCode(LeftChild.ResultType); switch (typeCode) { 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); }
/// <summary> /// Emit the value of a field in the object whose reference is currently on the evaluation stack. /// </summary> /// <param name="fieldInfo"></param> /// <param name="indirect"></param> /// <param name="ilGenerator"></param> private static void EmitLdfld(FieldInfo fieldInfo, bool indirect, YaleIlGenerator ilGenerator) { if (fieldInfo.IsStatic) { ilGenerator.Emit(indirect ? OpCodes.Ldsflda : OpCodes.Ldsfld, fieldInfo); } else { ilGenerator.Emit(indirect ? OpCodes.Ldflda : OpCodes.Ldfld, fieldInfo); } }
private void EmitCast(YaleIlGenerator ilg, Type sourceType, Type destType, ExpressionContext context) { var explicitOperator = GetExplictOverloadedOperator(sourceType, destType); if (ReferenceEquals(sourceType, destType)) { // Identity cast; do nothing return; } if (explicitOperator != null) { ilg.Emit(OpCodes.Call, explicitOperator); } else if (sourceType.IsEnum | destType.IsEnum) { EmitEnumCast(ilg, sourceType, destType, context); } else if (ImplicitConverter.EmitImplicitConvert(sourceType, destType, ilg)) { // Implicit numeric cast; do nothing return; } else if (IsCastableNumericType(sourceType) & IsCastableNumericType(destType)) { // Explicit numeric cast EmitExplicitNumericCast(ilg, sourceType, destType, context); } else if (sourceType.IsValueType) { Debug.Assert(destType.IsValueType == false, "expecting reference type"); ilg.Emit(OpCodes.Box, sourceType); } else { if (destType.IsValueType) { // 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(int value, YaleIlGenerator 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); } }
private static void EmitBitwiseOperation(YaleIlGenerator ilg, AndOrOperation op) { switch (op) { case AndOrOperation.And: ilg.Emit(OpCodes.And); break; case AndOrOperation.Or: ilg.Emit(OpCodes.Or); break; default: throw new InvalidOperationException("Unknown op type"); } }
/// <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> private void EmitLogical(YaleIlGenerator ilg, ShortCircuitInfo info, ExpressionContext context) { // We always have an end label info.Branches.GetLabel(OurEndLabelKey, ilg); // Populate our data structures PopulateData(info); // Emit the sequence EmitLogicalShortCircuit(ilg, info, context); // Get the last operand var terminalOperand = (BaseExpressionElement)info.Operands.Pop(); // Emit it EmitOperand(terminalOperand, info, ilg, context); // And jump to the end var 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(YaleIlGenerator ilg, Label trueTerminal, BranchManager branchManager) { if (ilg.IsTemp) { branchManager.AddBranch(ilg, trueTerminal); ilg.Emit(OpCodes.Brtrue_S, trueTerminal); } else if (branchManager.IsLongBranch(ilg, trueTerminal) == false) { ilg.Emit(OpCodes.Brtrue_S, trueTerminal); } else { ilg.Emit(OpCodes.Brtrue, trueTerminal); } }
protected static void EmitValueTypeLoadAddress(YaleIlGenerator ilg, Type targetType) { var index = ilg.GetTempLocalIndex(targetType); Utility.EmitStoreLocal(ilg, index); ilg.Emit(OpCodes.Ldloca_S, Convert.ToByte(index)); }
/// <summary> /// Emits il that loads a variable from the Variables collection /// </summary> /// <param name="ilg"></param> private void EmitVariableLoad(YaleIlGenerator ilg) { var methodInfo = VariableCollection.GetVariableLoadMethod(valueType); ilg.Emit(OpCodes.Ldstr, MemberName); EmitMethodCall(methodInfo, ilg); }
/// <summary> /// Create the IL used to load the result from another expression /// </summary> /// <param name="expressionKey"></param> /// <param name="ilGenerator"></param> internal void EmitLoad(string expressionKey, YaleIlGenerator ilGenerator) { var propertyInfo = typeof(ExpressionContext).GetProperty(nameof(ExpressionContext.ComputeInstance)); ilGenerator.Emit(OpCodes.Callvirt, propertyInfo.GetGetMethod()); //Find and load expression result var members = typeof(ComputeInstance).FindMembers(MemberTypes.Method, BindingFlags.Instance | BindingFlags.Public, Type.FilterName, "GetResult"); var methodInfo = members.Cast <MethodInfo>().First(method => method.IsGenericMethod); var resultType = ResultType(expressionKey); methodInfo = methodInfo.MakeGenericMethod(resultType); ilGenerator.Emit(OpCodes.Ldstr, expressionKey); ilGenerator.Emit(OpCodes.Call, methodInfo); }
private void EmitShift(YaleIlGenerator ilg) { var typeCode = Type.GetTypeCode(LeftChild.ResultType); var opCode = default(OpCode); switch (typeCode) { case TypeCode.Byte: case TypeCode.SByte: case TypeCode.Int16: case TypeCode.UInt16: case TypeCode.Int32: case TypeCode.Int64: // Signed operand, emit a left shift or arithmetic right shift opCode = operation == ShiftOperation.LeftShift ? OpCodes.Shl : OpCodes.Shr; break; case TypeCode.UInt32: case TypeCode.UInt64: // Unsigned operand, emit left shift or logical right shift opCode = operation == ShiftOperation.LeftShift ? OpCodes.Shl : OpCodes.Shr_Un; break; default: Debug.Assert(false, "unknown left shift operand"); break; } ilg.Emit(opCode); }
/// <summary> /// Emit elements into an array /// </summary> private static void EmitElementArrayLoad(BaseExpressionElement[] elements, Type arrayElementType, YaleIlGenerator ilg, ExpressionContext context) { // 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 var local = ilg.DeclareLocal(arrayElementType.MakeArrayType()); var arrayLocalIndex = local.LocalIndex; Utility.EmitStoreLocal(ilg, arrayLocalIndex); for (var 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) var element = elements[i]; element.Emit(ilg, context); ImplicitConverter.EmitImplicitConvert(element.ResultType, arrayElementType, ilg); // Store it into the array Utility.EmitArrayStore(ilg, arrayElementType); } // Load the array Utility.EmitLoadLocal(ilg, arrayLocalIndex); }
private void EmitEnumCast(YaleIlGenerator ilg, Type sourceType, Type destType, ExpressionContext context) { 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); EmitCast(ilg, sourceType, destType, context); } }
protected static void EmitLoad(long value, YaleIlGenerator ilg) { if (value >= int.MinValue & value <= int.MaxValue) { EmitLoad(Convert.ToInt32(value), ilg); ilg.Emit(OpCodes.Conv_I8); } else if (value >= 0 & value <= int.MaxValue) { EmitLoad(Convert.ToInt32(value), ilg); ilg.Emit(OpCodes.Conv_U8); } else { ilg.Emit(OpCodes.Ldc_I8, value); } }
public override void Emit(YaleIlGenerator ilGenerator, ExpressionContext context) { var resultType = ResultType; MyChild.Emit(ilGenerator, context); ImplicitConverter.EmitImplicitConvert(MyChild.ResultType, resultType, ilGenerator); var methodInfo = Utility.GetSimpleOverloadedOperator(UnaryNegation, resultType, resultType); if (methodInfo == null) { ilGenerator.Emit(OpCodes.Neg); } else { ilGenerator.Emit(OpCodes.Call, methodInfo); } }
protected void EmitOverloadedOperatorCall(MethodInfo method, YaleIlGenerator ilg, ExpressionContext context) { var parameters = method.GetParameters(); var parameterInfoLeft = parameters[0]; var parameterInfoRight = parameters[1]; EmitChildWithConvert(LeftChild, parameterInfoLeft.ParameterType, ilg, context); EmitChildWithConvert(RightChild, parameterInfoRight.ParameterType, ilg, context); ilg.Emit(OpCodes.Call, method); }
private static void EmitStringEquality(YaleIlGenerator ilg, LogicalCompareOperation op, ExpressionContext context) { // Get the StringComparison from the options var options = context.BuilderOptions; var int32LiteralElement = new Int32LiteralElement((int)options.StringComparison); int32LiteralElement.Emit(ilg, context); // and emit the method call var methodInfo = typeof(string).GetMethod("Equals", new[] { typeof(string), typeof(string), typeof(StringComparison) }, null); ilg.Emit(OpCodes.Call, methodInfo); if (op == LogicalCompareOperation.NotEqual) { ilg.Emit(OpCodes.Ldc_I4_0); ilg.Emit(OpCodes.Ceq); } }
public override void Emit(YaleIlGenerator ilGenerator, ExpressionContext context) { var resultType = ResultType; LeftChild.Emit(ilGenerator, context); ImplicitConverter.EmitImplicitConvert(LeftChild.ResultType, resultType, ilGenerator); RightChild.Emit(ilGenerator, context); ImplicitConverter.EmitImplicitConvert(RightChild.ResultType, resultType, ilGenerator); ilGenerator.Emit(OpCodes.Xor); }
protected void EmitLoadOwner(YaleIlGenerator ilg) { ilg.Emit(OpCodes.Ldarg_0); var ownerType = Context.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 (RequiresAddress) { EmitValueTypeLoadAddress(ilg, ownerType); } }
private void EmitValueTypeArrayLoad(YaleIlGenerator ilg, Type elementType) { if (NextRequiresAddress) { ilg.Emit(OpCodes.Ldelema, elementType); } else { Utility.EmitArrayLoad(ilg, elementType); } }
private static void EmitSuperShort(int value, YaleIlGenerator ilGenerator) { var 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; } ilGenerator.Emit(ldcOpcode); }
public override void Emit(YaleIlGenerator ilGenerator, ExpressionContext context) { if (ReferenceEquals(MyChild.ResultType, typeof(bool))) { EmitLogical(ilGenerator, context); } else { MyChild.Emit(ilGenerator, context); ilGenerator.Emit(OpCodes.Not); } }
/// <summary> /// Emit a function call for a value type /// </summary> /// <param name="mi"></param> /// <param name="ilg"></param> private static void EmitValueTypeMethodCall(MethodInfo mi, YaleIlGenerator ilg) { if (mi.IsStatic) { ilg.Emit(OpCodes.Call, mi); } else if ((!ReferenceEquals(mi.DeclaringType, mi.ReflectedType))) { // Method is not defined on the value type if (IsGetTypeMethod(mi)) { // Special GetType method which requires a box ilg.Emit(OpCodes.Box, mi.ReflectedType); ilg.Emit(OpCodes.Call, mi); } else { // Equals, GetHashCode, and ToString methods on the base ilg.Emit(OpCodes.Constrained, mi.ReflectedType); ilg.Emit(OpCodes.Callvirt, mi); } } else { //Call value type implementation ilg.Emit(OpCodes.Call, mi); } }
//Entry point of IL Creation public override void Emit(YaleIlGenerator ilGenerator, ExpressionContext context) { _child.Emit(ilGenerator, context); ImplicitConverter.EmitImplicitConvert(_child.ResultType, _resultType, ilGenerator); //Todo: Verify if this convert stuff works if ("isGeneric".Equals("false")) { ImplicitConverter.EmitImplicitConvert(_resultType, typeof(object), ilGenerator); } ilGenerator.Emit(OpCodes.Ret); }
public override void Emit(YaleIlGenerator ilGenerator, ExpressionContext context) { var index = ilGenerator.GetTempLocalIndex(typeof(DateTime)); Utility.EmitLoadLocalAddress(ilGenerator, index); EmitLoad(_value.Ticks, ilGenerator); var constructor = typeof(DateTime).GetConstructor(new[] { typeof(Int64) }); ilGenerator.Emit(OpCodes.Call, constructor); Utility.EmitLoadLocal(ilGenerator, index); }
private static void EmitBranch(AndOrElement op, YaleIlGenerator ilg, Label target, ShortCircuitInfo info) { if (ilg.IsTemp) { info.Branches.AddBranch(ilg, target); // Temp mode; just emit a short branch and return var shortBranch = GetBranchOpcode(op, false); ilg.Emit(shortBranch, target); return; } // Emit the proper branch opcode // Determine if it is a long branch var longBranch = info.Branches.IsLongBranch(ilg, target); // Get the branch opcode var brOpcode = GetBranchOpcode(op, longBranch); // Emit the branch ilg.Emit(brOpcode, target); }
private void EmitCollectionIn(YaleIlGenerator ilg, ExpressionContext context) { // Get the contains method var methodInfo = GetCollectionContainsMethod(); var firstParameter = methodInfo.GetParameters()[0]; // Load the collection targetCollectionElement.Emit(ilg, context); // Load the argument operand.Emit(ilg, context); // Do an implicit convert if necessary ImplicitConverter.EmitImplicitConvert(operand.ResultType, firstParameter.ParameterType, ilg); // Call the contains method ilg.Emit(OpCodes.Callvirt, methodInfo); }
private void EmitListIn(YaleIlGenerator ilg, ExpressionContext context, BranchManager branchManager) { var compareElement = new CompareElement(); var endLabel = branchManager.FindLabel("endLabel"); var trueTerminal = branchManager.FindLabel("trueTerminal"); // Cache the operand since we will be comparing against it a lot var lb = ilg.DeclareLocal(operand.ResultType); var targetIndex = lb.LocalIndex; operand.Emit(ilg, context); Utility.EmitStoreLocal(ilg, targetIndex); // Wrap our operand in a local shim var targetShim = new LocalBasedElement(operand, targetIndex); // Emit the compares foreach (var argumentElement in arguments) { compareElement.Initialize(targetShim, argumentElement, LogicalCompareOperation.Equal); compareElement.Emit(ilg, context); EmitBranchToTrueTerminal(ilg, trueTerminal, branchManager); } ilg.Emit(OpCodes.Ldc_I4_0); ilg.Emit(OpCodes.Br_S, endLabel); branchManager.MarkLabel(ilg, trueTerminal); ilg.MarkLabel(trueTerminal); ilg.Emit(OpCodes.Ldc_I4_1); branchManager.MarkLabel(ilg, endLabel); ilg.MarkLabel(endLabel); }
private void EmitArrayLoad(YaleIlGenerator ilg, ExpressionContext context) { _indexerElement.Emit(ilg, context); ImplicitConverter.EmitImplicitConvert(_indexerElement.ResultType, typeof(Int32), ilg); var elementType = ResultType; if (elementType.IsValueType == false) { // Simple reference load ilg.Emit(OpCodes.Ldelem_Ref); } else { EmitValueTypeArrayLoad(ilg, elementType); } }
private void EmitConditional(YaleIlGenerator ilg, ExpressionContext context, BranchManager branchManager) { var falseLabel = branchManager.FindLabel("falseLabel"); var endLabel = branchManager.FindLabel("endLabel"); // Emit the condition condition.Emit(ilg, context); // On false go to the false operand if (ilg.IsTemp) { branchManager.AddBranch(ilg, falseLabel); ilg.Emit(OpCodes.Brfalse_S, falseLabel); } else if (branchManager.IsLongBranch(ilg, falseLabel) == false) { ilg.Emit(OpCodes.Brfalse_S, falseLabel); } else { ilg.Emit(OpCodes.Brfalse, falseLabel); } // Emit the true operand whenTrue.Emit(ilg, context); ImplicitConverter.EmitImplicitConvert(whenTrue.ResultType, resultType, ilg); // Jump to end if (ilg.IsTemp) { branchManager.AddBranch(ilg, endLabel); ilg.Emit(OpCodes.Br_S, endLabel); } else if (branchManager.IsLongBranch(ilg, endLabel) == false) { ilg.Emit(OpCodes.Br_S, endLabel); } else { ilg.Emit(OpCodes.Br, endLabel); } branchManager.MarkLabel(ilg, falseLabel); ilg.MarkLabel(falseLabel); // Emit the false operand whenFalse.Emit(ilg, context); ImplicitConverter.EmitImplicitConvert(whenFalse.ResultType, resultType, ilg); // Fall through to end branchManager.MarkLabel(ilg, endLabel); ilg.MarkLabel(endLabel); }