public override void GenerateCode(ILGenerator gen, CodeFlow cf) { if (_cachedReadAccessor is not ICompilablePropertyAccessor accessorToUse) { throw new InvalidOperationException("Property accessor is not compilable: " + _cachedReadAccessor); } Label?skipIfNullLabel = null; if (_nullSafe) { skipIfNullLabel = gen.DefineLabel(); gen.Emit(OpCodes.Dup); gen.Emit(OpCodes.Ldnull); gen.Emit(OpCodes.Cgt_Un); gen.Emit(OpCodes.Brfalse, skipIfNullLabel.Value); } accessorToUse.GenerateCode(_name, gen, cf); cf.PushDescriptor(_exitTypeDescriptor); if (_originalPrimitiveExitTypeDescriptor != null) { // The output of the accessor is a primitive but from the block above it might be null, // so to have a common stack element type at skipIfNull target it is necessary // to box the primitive CodeFlow.InsertBoxIfNecessary(gen, _originalPrimitiveExitTypeDescriptor); } if (skipIfNullLabel.HasValue) { gen.MarkLabel(skipIfNullLabel.Value); } }
public override void GenerateCode(ILGenerator gen, CodeFlow cf) { if (_exitTypeDescriptor == TypeDescriptor.STRING) { gen.Emit(OpCodes.Newobj, _sbConstructor); Walk(gen, cf, LeftOperand); Walk(gen, cf, RightOperand); gen.Emit(OpCodes.Callvirt, _toString); } else { _children[0].GenerateCode(gen, cf); var leftDesc = _children[0].ExitDescriptor; var exitDesc = _exitTypeDescriptor; if (exitDesc == null) { throw new InvalidOperationException("No exit type descriptor"); } CodeFlow.InsertNumericUnboxOrPrimitiveTypeCoercion(gen, leftDesc, exitDesc); if (_children.Length > 1) { cf.EnterCompilationScope(); _children[1].GenerateCode(gen, cf); var rightDesc = _children[1].ExitDescriptor; cf.ExitCompilationScope(); CodeFlow.InsertNumericUnboxOrPrimitiveTypeCoercion(gen, rightDesc, exitDesc); gen.Emit(OpCodes.Add); } } cf.PushDescriptor(_exitTypeDescriptor); }
public override void GenerateCode(ILGenerator gen, CodeFlow cf) { // pseudo: if (leftOperandValue) { result=true; } else { result=rightOperandValue; } var elseTarget = gen.DefineLabel(); var endIfTarget = gen.DefineLabel(); var result = gen.DeclareLocal(typeof(bool)); cf.EnterCompilationScope(); LeftOperand.GenerateCode(gen, cf); cf.UnboxBooleanIfNecessary(gen); cf.ExitCompilationScope(); gen.Emit(OpCodes.Brfalse, elseTarget); gen.Emit(OpCodes.Ldc_I4_1); gen.Emit(OpCodes.Stloc, result); gen.Emit(OpCodes.Br, endIfTarget); gen.MarkLabel(elseTarget); cf.EnterCompilationScope(); RightOperand.GenerateCode(gen, cf); cf.UnboxBooleanIfNecessary(gen); cf.ExitCompilationScope(); gen.Emit(OpCodes.Stloc, result); gen.MarkLabel(endIfTarget); gen.Emit(OpCodes.Ldloc, result); cf.PushDescriptor(_exitTypeDescriptor); }
public override void GenerateCode(ILGenerator gen, CodeFlow cf) { CodeFlow.LoadEvaluationContext(gen); var leftDesc = LeftOperand.ExitDescriptor; var rightDesc = RightOperand.ExitDescriptor; var leftPrim = CodeFlow.IsValueType(leftDesc); var rightPrim = CodeFlow.IsValueType(rightDesc); cf.EnterCompilationScope(); LeftOperand.GenerateCode(gen, cf); cf.ExitCompilationScope(); if (leftPrim) { CodeFlow.InsertBoxIfNecessary(gen, leftDesc); } cf.EnterCompilationScope(); RightOperand.GenerateCode(gen, cf); cf.ExitCompilationScope(); if (rightPrim) { CodeFlow.InsertBoxIfNecessary(gen, rightDesc); } gen.Emit(OpCodes.Call, _equalityCheck); cf.PushDescriptor(TypeDescriptor.Z); }
public override void GenerateCode(ILGenerator gen, CodeFlow cf) { LeftOperand.GenerateCode(gen, cf); var leftDesc = LeftOperand.ExitDescriptor; var exitDesc = _exitTypeDescriptor; if (exitDesc == null) { throw new InvalidOperationException("No exit type descriptor"); } CodeFlow.InsertNumericUnboxOrPrimitiveTypeCoercion(gen, leftDesc, exitDesc); if (_children.Length > 1) { cf.EnterCompilationScope(); RightOperand.GenerateCode(gen, cf); var rightDesc = RightOperand.ExitDescriptor; cf.ExitCompilationScope(); CodeFlow.InsertNumericUnboxOrPrimitiveTypeCoercion(gen, rightDesc, exitDesc); gen.Emit(OpCodes.Sub); } else { gen.Emit(OpCodes.Neg); } cf.PushDescriptor(_exitTypeDescriptor); }
public override void GenerateCode(ILGenerator gen, CodeFlow cf) { foreach (var child in _children) { child.GenerateCode(gen, cf); } cf.PushDescriptor(_exitTypeDescriptor); }
public override void GenerateCode(ILGenerator gen, CodeFlow cf) { var constantFieldName = "inlineList$" + cf.NextFieldId(); cf.RegisterNewField(constantFieldName, new List <object>()); cf.RegisterNewInitGenerator((initGenerator, cflow) => { GenerateInitCode(constantFieldName, initGenerator, cflow); }); GenerateLoadListCode(gen, constantFieldName); cf.PushDescriptor(new TypeDescriptor(typeof(IList))); }
public override void GenerateCode(ILGenerator gen, CodeFlow cf) { if (_type == null) { throw new InvalidOperationException("No type available"); } gen.Emit(OpCodes.Ldtoken, _type); gen.Emit(OpCodes.Call, _getTypeFromHandle); cf.PushDescriptor(_exitTypeDescriptor); }
public override void GenerateCode(ILGenerator gen, CodeFlow cf) { // May reach here without it computed if all elements are literals ComputeExitTypeDescriptor(); cf.EnterCompilationScope(); _children[0].GenerateCode(gen, cf); var lastDesc = cf.LastDescriptor() ?? throw new InvalidOperationException("No last descriptor"); if (!CodeFlow.IsValueType(lastDesc)) { gen.Emit(OpCodes.Unbox_Any, typeof(bool)); } cf.ExitCompilationScope(); var elseTarget = gen.DefineLabel(); var endOfIfTarget = gen.DefineLabel(); gen.Emit(OpCodes.Brfalse, elseTarget); cf.EnterCompilationScope(); _children[1].GenerateCode(gen, cf); if (!CodeFlow.IsValueType(_exitTypeDescriptor)) { lastDesc = cf.LastDescriptor(); if (lastDesc == null) { throw new InvalidOperationException("No last descriptor"); } CodeFlow.InsertBoxIfNecessary(gen, lastDesc); } cf.ExitCompilationScope(); gen.Emit(OpCodes.Br, endOfIfTarget); gen.MarkLabel(elseTarget); cf.EnterCompilationScope(); _children[2].GenerateCode(gen, cf); if (!CodeFlow.IsValueType(_exitTypeDescriptor)) { lastDesc = cf.LastDescriptor(); if (lastDesc == null) { throw new InvalidOperationException("No last descriptor"); } CodeFlow.InsertBoxIfNecessary(gen, lastDesc); } cf.ExitCompilationScope(); gen.MarkLabel(endOfIfTarget); cf.PushDescriptor(_exitTypeDescriptor); }
public override void GenerateCode(ILGenerator gen, CodeFlow cf) { var method = _method; if (method == null) { throw new InvalidOperationException("No method handle"); } GenerateCodeForArguments(gen, cf, method, _children); gen.Emit(OpCodes.Call, method); cf.PushDescriptor(_exitTypeDescriptor); }
public override void GenerateCode(ILGenerator gen, CodeFlow cf) { var method = GetTargetMethodAndType(out var classType); if (method.IsStatic) { GenerateStaticMethodCode(gen, cf, method); } else { GenerateInstanceMethodCode(gen, cf, method, classType); } cf.PushDescriptor(_exitTypeDescriptor); }
public override void GenerateCode(ILGenerator gen, CodeFlow cf) { if (_name.Equals(ROOT)) { CodeFlow.LoadTarget(gen); } else { gen.Emit(OpCodes.Ldarg_2); gen.Emit(OpCodes.Ldstr, _name); gen.Emit(OpCodes.Callvirt, GetLookUpVariableMethod()); } CodeFlow.InsertCastClass(gen, _exitTypeDescriptor); cf.PushDescriptor(_exitTypeDescriptor); }
public override void GenerateCode(ILGenerator gen, CodeFlow cf) { var result = gen.DeclareLocal(typeof(bool)); if (_value.Equals(BooleanTypedValue.TRUE)) { gen.Emit(OpCodes.Ldc_I4_1); } else { gen.Emit(OpCodes.Ldc_I4_0); } gen.Emit(OpCodes.Stloc, result); gen.Emit(OpCodes.Ldloc, result); cf.PushDescriptor(_exitTypeDescriptor); }
public override void GenerateCode(ILGenerator gen, CodeFlow cf) { LeftOperand.GenerateCode(gen, cf); CodeFlow.InsertBoxIfNecessary(gen, cf.LastDescriptor()); if (_type == null) { throw new InvalidOperationException("No type available"); } var convert = gen.DeclareLocal(typeof(bool)); gen.Emit(OpCodes.Isinst, _type); gen.Emit(OpCodes.Ldnull); gen.Emit(OpCodes.Cgt_Un); gen.Emit(OpCodes.Stloc, convert); gen.Emit(OpCodes.Ldloc, convert); cf.PushDescriptor(_exitTypeDescriptor); }
public override void GenerateCode(ILGenerator gen, CodeFlow cf) { var executor = (ReflectiveConstructorExecutor)_cachedExecutor; if (executor == null) { throw new InvalidOperationException("No cached executor"); } var constructor = executor.Constructor; // children[0] is the type of the constructor, don't want to include that in argument processing var arguments = new SpelNode[_children.Length - 1]; Array.Copy(_children, 1, arguments, 0, _children.Length - 1); GenerateCodeForArguments(gen, cf, constructor, arguments); gen.Emit(OpCodes.Newobj, constructor); cf.PushDescriptor(_exitTypeDescriptor); }
public override void GenerateCode(ILGenerator gen, CodeFlow cf) { var elseTarget = gen.DefineLabel(); var endIfTarget = gen.DefineLabel(); var result = gen.DeclareLocal(typeof(bool)); var child = _children[0]; child.GenerateCode(gen, cf); cf.UnboxBooleanIfNecessary(gen); gen.Emit(OpCodes.Brtrue, elseTarget); gen.Emit(OpCodes.Ldc_I4_1); gen.Emit(OpCodes.Stloc, result); gen.Emit(OpCodes.Br, endIfTarget); gen.MarkLabel(elseTarget); gen.Emit(OpCodes.Ldc_I4_0); gen.Emit(OpCodes.Stloc, result); gen.MarkLabel(endIfTarget); gen.Emit(OpCodes.Ldloc, result); cf.PushDescriptor(_exitTypeDescriptor); }
public override void GenerateCode(ILGenerator gen, CodeFlow cf) { var intVal = _value.Value; if (intVal == null) { throw new InvalidOperationException("No int value"); } var intValue = (int)intVal; if (intValue == -1) { // Not sure we can get here because -1 is OpMinus gen.Emit(OpCodes.Ldc_I4_M1); } else { gen.Emit(OpCodes.Ldc_I4, intValue); } cf.PushDescriptor(_exitTypeDescriptor); }
public override void GenerateCode(ILGenerator gen, CodeFlow cf) { CodeFlow.LoadEvaluationContext(gen); var leftDesc = LeftOperand.ExitDescriptor; var rightDesc = RightOperand.ExitDescriptor; var leftPrim = CodeFlow.IsValueType(leftDesc); var rightPrim = CodeFlow.IsValueType(rightDesc); cf.EnterCompilationScope(); LeftOperand.GenerateCode(gen, cf); cf.ExitCompilationScope(); if (leftPrim) { CodeFlow.InsertBoxIfNecessary(gen, leftDesc); } cf.EnterCompilationScope(); RightOperand.GenerateCode(gen, cf); cf.ExitCompilationScope(); if (rightPrim) { CodeFlow.InsertBoxIfNecessary(gen, rightDesc); } // returns bool gen.Emit(OpCodes.Call, _equalityCheck); // Invert the boolean var result = gen.DeclareLocal(typeof(bool)); gen.Emit(OpCodes.Ldc_I4_0); gen.Emit(OpCodes.Ceq); gen.Emit(OpCodes.Stloc, result); gen.Emit(OpCodes.Ldloc, result); cf.PushDescriptor(TypeDescriptor.Z); }
public override void GenerateCode(ILGenerator gen, CodeFlow cf) { gen.Emit(OpCodes.Ldc_R4, (float)_value.Value); cf.PushDescriptor(_exitTypeDescriptor); }
public override void GenerateCode(ILGenerator gen, CodeFlow cf) { // exit type descriptor can be null if both components are literal expressions ComputeExitTypeDescriptor(); cf.EnterCompilationScope(); _children[0].GenerateCode(gen, cf); var lastDesc = cf.LastDescriptor(); if (lastDesc == null) { throw new InvalidOperationException("No last descriptor"); } // if primitive result, boxed will be on stack CodeFlow.InsertBoxIfNecessary(gen, lastDesc); cf.ExitCompilationScope(); var ifResult = gen.DeclareLocal(typeof(bool)); var finalResult = gen.DeclareLocal(_exitTypeDescriptor.Value); var loadFinalResult = gen.DefineLabel(); // Save off child1 result var child1Result = gen.DeclareLocal(typeof(object)); gen.Emit(OpCodes.Stloc, child1Result); var child1IsNull = gen.DefineLabel(); gen.Emit(OpCodes.Ldloc, child1Result); // br if child1 null gen.Emit(OpCodes.Brfalse, child1IsNull); // Check for empty string gen.Emit(OpCodes.Ldstr, string.Empty); gen.Emit(OpCodes.Ldloc, child1Result); gen.Emit(OpCodes.Callvirt, _equalsMethod); gen.Emit(OpCodes.Ldc_I4_0); gen.Emit(OpCodes.Ceq); // save empty string result gen.Emit(OpCodes.Stloc, ifResult); var loadCheckIfResults = gen.DefineLabel(); gen.Emit(OpCodes.Br, loadCheckIfResults); // Child1 null, load false for if result gen.MarkLabel(child1IsNull); gen.Emit(OpCodes.Ldc_I4_0); gen.Emit(OpCodes.Stloc, ifResult); // Fall thru to check if results; // Mark Check if Results gen.MarkLabel(loadCheckIfResults); // Load if results; gen.Emit(OpCodes.Ldloc, ifResult); var callChild2 = gen.DefineLabel(); // If faild, call child2 for results gen.Emit(OpCodes.Brfalse, callChild2); // Final result is child 1, save final gen.Emit(OpCodes.Ldloc, child1Result); gen.Emit(OpCodes.Stloc, finalResult); gen.Emit(OpCodes.Br, loadFinalResult); gen.MarkLabel(callChild2); cf.EnterCompilationScope(); _children[1].GenerateCode(gen, cf); if (!CodeFlow.IsValueType(_exitTypeDescriptor)) { lastDesc = cf.LastDescriptor(); if (lastDesc == null) { throw new InvalidOperationException("No last descriptor"); } if (lastDesc == TypeDescriptor.V) { gen.Emit(OpCodes.Ldnull); } else { CodeFlow.InsertBoxIfNecessary(gen, lastDesc); } } cf.ExitCompilationScope(); gen.Emit(OpCodes.Stloc, finalResult); // Load final result on stack gen.MarkLabel(loadFinalResult); gen.Emit(OpCodes.Ldloc, finalResult); cf.PushDescriptor(_exitTypeDescriptor); }
public override void GenerateCode(ILGenerator gen, CodeFlow cf) { var descriptor = cf.LastDescriptor(); if (descriptor == null) { CodeFlow.LoadTarget(gen); } if (_indexedType == IndexedType.ARRAY) { var arrayType = _exitTypeDescriptor.Value.MakeArrayType(); gen.Emit(OpCodes.Castclass, arrayType); var child = _children[0]; cf.EnterCompilationScope(); child.GenerateCode(gen, cf); cf.ExitCompilationScope(); gen.Emit(GetLdElemInsn(_exitTypeDescriptor.Value)); } else if (_indexedType == IndexedType.LIST) { gen.Emit(OpCodes.Castclass, typeof(IList)); cf.EnterCompilationScope(); _children[0].GenerateCode(gen, cf); cf.ExitCompilationScope(); gen.Emit(OpCodes.Callvirt, _listGetItemMethod); } else if (_indexedType == IndexedType.MAP) { gen.Emit(OpCodes.Castclass, typeof(IDictionary)); // Special case when the key is an unquoted string literal that will be parsed as // a property/field reference if (_children[0] is PropertyOrFieldReference reference) { var mapKeyName = reference.Name; gen.Emit(OpCodes.Ldstr, mapKeyName); } else { cf.EnterCompilationScope(); _children[0].GenerateCode(gen, cf); cf.ExitCompilationScope(); } gen.Emit(OpCodes.Callvirt, _dictionaryGetItemMethod); } else if (_indexedType == IndexedType.OBJECT) { if (_cachedReadAccessor is not ReflectivePropertyAccessor.OptimalPropertyAccessor accessor) { throw new InvalidOperationException("No cached read accessor"); } bool isStatic; var method = accessor.Member as MethodInfo; var field = accessor.Member as FieldInfo; if (method != null) { isStatic = method.IsStatic; } else { isStatic = field.IsStatic; } var targetType = accessor.Member.DeclaringType; if (!isStatic && (descriptor == null || targetType != descriptor.Value)) { gen.Emit(OpCodes.Castclass, targetType); } if (method != null) { if (isStatic) { gen.Emit(OpCodes.Call, method); } else { gen.Emit(OpCodes.Callvirt, method); } } else { if (isStatic) { gen.Emit(OpCodes.Ldsfld, field); } else { gen.Emit(OpCodes.Ldfld, field); } } } cf.PushDescriptor(_exitTypeDescriptor); }
protected void GenerateComparisonCode(ILGenerator gen, CodeFlow cf, OpCode brToElseInstruction) { var left = LeftOperand; var right = RightOperand; var leftDesc = left.ExitDescriptor; var rightDesc = right.ExitDescriptor; var elseTarget = gen.DefineLabel(); var endOfIfTarget = gen.DefineLabel(); var unboxLeft = !CodeFlow.IsValueType(leftDesc); var unboxRight = !CodeFlow.IsValueType(rightDesc); cf.EnterCompilationScope(); left.GenerateCode(gen, cf); cf.ExitCompilationScope(); if (CodeFlow.IsValueType(leftDesc)) { gen.Emit(OpCodes.Box, leftDesc.Value); unboxLeft = true; } cf.EnterCompilationScope(); right.GenerateCode(gen, cf); cf.ExitCompilationScope(); if (CodeFlow.IsValueType(rightDesc)) { gen.Emit(OpCodes.Box, rightDesc.Value); unboxRight = true; } var leftLocal = gen.DeclareLocal(typeof(object)); var rightLocal = gen.DeclareLocal(typeof(object)); gen.Emit(OpCodes.Stloc, rightLocal); gen.Emit(OpCodes.Stloc, leftLocal); gen.Emit(OpCodes.Ldloc, leftLocal); gen.Emit(OpCodes.Ldloc, rightLocal); // This code block checks whether the left or right operand is null and handles // those cases before letting the original code (that only handled actual numbers) run var rightIsNonNullTarget = gen.DefineLabel(); // stack: left/right gen.Emit(OpCodes.Brtrue, rightIsNonNullTarget); // stack: left // here: RIGHT==null LEFT==unknown var leftNotNullRightIsNullTarget = gen.DefineLabel(); gen.Emit(OpCodes.Brtrue, leftNotNullRightIsNullTarget); // stack: empty // here: RIGHT==null LEFT==null // load 0 or 1 depending on comparison instruction if (brToElseInstruction == OpCodes.Bge || brToElseInstruction == OpCodes.Ble) { gen.Emit(OpCodes.Ldc_I4_0); } else if (brToElseInstruction == OpCodes.Bgt || brToElseInstruction == OpCodes.Blt) { gen.Emit(OpCodes.Ldc_I4_1); } else { throw new InvalidOperationException("Unsupported: " + brToElseInstruction); } gen.Emit(OpCodes.Br, endOfIfTarget); gen.MarkLabel(leftNotNullRightIsNullTarget); // stack: empty // RIGHT==null LEFT!=null // load 0 or 1 depending on comparison instruction if (brToElseInstruction == OpCodes.Bge || brToElseInstruction == OpCodes.Bgt) { gen.Emit(OpCodes.Ldc_I4_0); } else if (brToElseInstruction == OpCodes.Ble || brToElseInstruction == OpCodes.Blt) { gen.Emit(OpCodes.Ldc_I4_1); } else { throw new InvalidOperationException("Unsupported: " + brToElseInstruction); } gen.Emit(OpCodes.Br, endOfIfTarget); gen.MarkLabel(rightIsNonNullTarget); // stack: left // here: RIGHT!=null LEFT==unknown var neitherRightNorLeftAreNullTarget = gen.DefineLabel(); gen.Emit(OpCodes.Brtrue, neitherRightNorLeftAreNullTarget); // stack: empty // here: RIGHT!=null LEFT==null if (brToElseInstruction == OpCodes.Bge || brToElseInstruction == OpCodes.Bgt) { gen.Emit(OpCodes.Ldc_I4_1); } else if (brToElseInstruction == OpCodes.Ble || brToElseInstruction == OpCodes.Blt) { gen.Emit(OpCodes.Ldc_I4_0); } else { throw new InvalidOperationException("Unsupported: " + brToElseInstruction); } gen.Emit(OpCodes.Br, endOfIfTarget); gen.MarkLabel(neitherRightNorLeftAreNullTarget); // stack: empty // neither were null so unbox and proceed with numeric comparison gen.Emit(OpCodes.Ldloc, leftLocal); if (unboxLeft) { gen.Emit(OpCodes.Unbox_Any, leftDesc.Value); } // stack: left gen.Emit(OpCodes.Ldloc, rightLocal); if (unboxRight) { gen.Emit(OpCodes.Unbox_Any, rightDesc.Value); } // stack: left, right // Br instruction gen.Emit(brToElseInstruction, elseTarget); // Stack: Empty gen.Emit(OpCodes.Ldc_I4_1); gen.Emit(OpCodes.Br, endOfIfTarget); gen.MarkLabel(elseTarget); // Stack: Empty gen.Emit(OpCodes.Ldc_I4_0); gen.MarkLabel(endOfIfTarget); // Stack: result on stack, convert to bool var result = gen.DeclareLocal(typeof(bool)); gen.Emit(OpCodes.Stloc, result); gen.Emit(OpCodes.Ldloc, result); cf.PushDescriptor(TypeDescriptor.Z); }
public override void GenerateCode(ILGenerator gen, CodeFlow cf) { gen.Emit(OpCodes.Ldnull); cf.PushDescriptor(_exitTypeDescriptor); }