protected static void GenerateCodeForArgument(ILGenerator gen, CodeFlow cf, SpelNode argument, TypeDescriptor paramDesc) { cf.EnterCompilationScope(); argument.GenerateCode(gen, cf); var lastDesc = cf.LastDescriptor(); if (lastDesc == null) { throw new InvalidOperationException("No last descriptor"); } var valueTypeOnStack = CodeFlow.IsValueType(lastDesc); // Check if need to box it for the method reference? if (valueTypeOnStack && paramDesc.IsReferenceType) { CodeFlow.InsertBoxIfNecessary(gen, lastDesc); } else if (paramDesc.IsValueType && !paramDesc.IsBoxed && !valueTypeOnStack) { gen.Emit(OpCodes.Unbox_Any, paramDesc.Value); } else { // This would be unnecessary in the case of subtyping (e.g. method takes Number but Integer passed in) CodeFlow.InsertCastClass(gen, paramDesc); } cf.ExitCompilationScope(); }
private void GenerateInstanceMethodCode(ILGenerator gen, CodeFlow cf, MethodInfo targetMethod, Type targetType) { var stackDescriptor = cf.LastDescriptor(); if (stackDescriptor == null) { // Nothing on the stack but something is needed CodeFlow.LoadTarget(gen); stackDescriptor = TypeDescriptor.OBJECT; } Label?skipIfNullTarget = null; if (_nullSafe) { skipIfNullTarget = GenerateNullCheckCode(gen); } if (targetType.IsValueType) { if (stackDescriptor.IsBoxed || stackDescriptor.IsReferenceType) { gen.Emit(OpCodes.Unbox_Any, targetType); } var local = gen.DeclareLocal(targetType); gen.Emit(OpCodes.Stloc, local); gen.Emit(OpCodes.Ldloca, local); } else { if (stackDescriptor.Value != targetType) { CodeFlow.InsertCastClass(gen, new TypeDescriptor(targetType)); } } GenerateCodeForArguments(gen, cf, targetMethod, _children); if (targetType.IsValueType) { gen.Emit(OpCodes.Call, targetMethod); } else { gen.Emit(OpCodes.Callvirt, targetMethod); } if (_originalPrimitiveExitTypeDescriptor != null) { // The output of the accessor will be a primitive but from the block above it might be null, // so to have a 'common stack' element at skipIfNull target we need to box the primitive CodeFlow.InsertBoxIfNecessary(gen, _originalPrimitiveExitTypeDescriptor); } if (skipIfNullTarget.HasValue) { gen.MarkLabel(skipIfNullTarget.Value); } }
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); }
private Label GenerateNullCheckCode(ILGenerator gen) { var skipIfNullTarget = gen.DefineLabel(); var continueTarget = gen.DefineLabel(); gen.Emit(OpCodes.Dup); gen.Emit(OpCodes.Ldnull); gen.Emit(OpCodes.Cgt_Un); gen.Emit(OpCodes.Brtrue, continueTarget); // cast null on stack to result type CodeFlow.InsertCastClass(gen, _exitTypeDescriptor); gen.Emit(OpCodes.Br, skipIfNullTarget); gen.MarkLabel(continueTarget); return(skipIfNullTarget); }