Example #1
0
        public void EmitPredefined(EmitContext ec, MethodSpec method, Arguments Arguments, Location?loc = null)
        {
            Expression instance_copy = null;

            if (!HasAwaitArguments && ec.HasSet(BuilderContext.Options.AsyncBody))
            {
                HasAwaitArguments = Arguments != null && Arguments.ContainsEmitWithAwait();
                if (HasAwaitArguments && InstanceExpressionOnStack)
                {
                    throw new NotSupportedException();
                }
            }

            OpCode         call_op;
            LocalTemporary lt = null;

            if (method.IsStatic)
            {
                call_op = OpCodes.Call;
            }
            else
            {
                if (IsVirtualCallRequired(InstanceExpression, method))
                {
                    call_op = OpCodes.Callvirt;
                }
                else
                {
                    call_op = OpCodes.Call;
                }

                if (HasAwaitArguments)
                {
                    instance_copy = InstanceExpression.EmitToField(ec);
                    if (Arguments == null)
                    {
                        EmitCallInstance(ec, instance_copy, method.DeclaringType, call_op);
                    }
                }
                else if (!InstanceExpressionOnStack)
                {
                    var instance_on_stack_type = EmitCallInstance(ec, InstanceExpression, method.DeclaringType, call_op);

                    if (DuplicateArguments)
                    {
                        ec.Emit(OpCodes.Dup);
                        if (Arguments != null && Arguments.Count != 0)
                        {
                            lt = new LocalTemporary(instance_on_stack_type);
                            lt.Store(ec);
                            instance_copy = lt;
                        }
                    }
                }
            }

            if (Arguments != null && !InstanceExpressionOnStack)
            {
                EmittedArguments = Arguments.Emit(ec, DuplicateArguments, HasAwaitArguments);
                if (EmittedArguments != null)
                {
                    if (instance_copy != null)
                    {
                        EmitCallInstance(ec, instance_copy, method.DeclaringType, call_op);

                        if (lt != null)
                        {
                            lt.Release(ec);
                        }
                    }

                    EmittedArguments.Emit(ec);
                }
            }

            if (call_op == OpCodes.Callvirt && (InstanceExpression.Type.IsGenericParameter || InstanceExpression.Type.IsStructOrEnum))
            {
                ec.Emit(OpCodes.Constrained, InstanceExpression.Type);
            }

            if (loc != null)
            {
                //
                // Emit explicit sequence point for expressions like Foo.Bar () to help debugger to
                // break at right place when LHS expression can be stepped-into
                //
                ec.MarkCallEntry(loc.Value);
            }

            //
            // Set instance expression to actual result expression. When it contains await it can be
            // picked up by caller
            //
            InstanceExpression = instance_copy;

            if (method.Parameters.HasArglist)
            {
                var varargs_types = GetVarargsTypes(method, Arguments);
                ec.Emit(call_op, method, varargs_types);
                return;
            }

            //
            // If you have:
            // this.DoFoo ();
            // and DoFoo is not virtual, you can omit the callvirt,
            // because you don't need the null checking behavior.
            //
            ec.Emit(call_op, method);
        }
Example #2
0
		public void EmitPredefined (EmitContext ec, MethodSpec method, Arguments Arguments, bool statement = false, Location? loc = null)
		{
			Expression instance_copy = null;

			if (!HasAwaitArguments && ec.HasSet (BuilderContext.Options.AsyncBody)) {
				HasAwaitArguments = Arguments != null && Arguments.ContainsEmitWithAwait ();
				if (HasAwaitArguments && InstanceExpressionOnStack) {
					throw new NotSupportedException ();
				}
			}

			OpCode call_op;
			LocalTemporary lt = null;

			if (method.IsStatic) {
				call_op = OpCodes.Call;
			} else {
				call_op = IsVirtualCallRequired (InstanceExpression, method) ? OpCodes.Callvirt : OpCodes.Call;

				if (HasAwaitArguments) {
					instance_copy = InstanceExpression.EmitToField (ec);
					var ie = new InstanceEmitter (instance_copy, IsAddressCall (instance_copy, call_op, method.DeclaringType));

					if (Arguments == null) {
						ie.EmitLoad (ec, true);
					}
				} else if (!InstanceExpressionOnStack) {
					var ie = new InstanceEmitter (InstanceExpression, IsAddressCall (InstanceExpression, call_op, method.DeclaringType));
					ie.Emit (ec, ConditionalAccess);

					if (DuplicateArguments) {
						ec.Emit (OpCodes.Dup);
						if (Arguments != null && Arguments.Count != 0) {
							lt = new LocalTemporary (ie.GetStackType (ec));
							lt.Store (ec);
							instance_copy = lt;
						}
					}
				}
			}

			if (Arguments != null && !InstanceExpressionOnStack) {
				EmittedArguments = Arguments.Emit (ec, DuplicateArguments, HasAwaitArguments);
				if (EmittedArguments != null) {
					if (instance_copy != null) {
						var ie = new InstanceEmitter (instance_copy, IsAddressCall (instance_copy, call_op, method.DeclaringType));
						ie.Emit (ec, ConditionalAccess);

						if (lt != null)
							lt.Release (ec);
					}

					EmittedArguments.Emit (ec);
				}
			}

			if (call_op == OpCodes.Callvirt && (InstanceExpression.Type.IsGenericParameter || InstanceExpression.Type.IsStructOrEnum)) {
				ec.Emit (OpCodes.Constrained, InstanceExpression.Type);
			}

			if (loc != null) {
				//
				// Emit explicit sequence point for expressions like Foo.Bar () to help debugger to
				// break at right place when LHS expression can be stepped-into
				//
				ec.MarkCallEntry (loc.Value);
			}

			//
			// Set instance expression to actual result expression. When it contains await it can be
			// picked up by caller
			//
			InstanceExpression = instance_copy;

			if (method.Parameters.HasArglist) {
				var varargs_types = GetVarargsTypes (method, Arguments);
				ec.Emit (call_op, method, varargs_types);
			} else {
				//
				// If you have:
				// this.DoFoo ();
				// and DoFoo is not virtual, you can omit the callvirt,
				// because you don't need the null checking behavior.
				//
				ec.Emit (call_op, method);
			}

			// 
			// Pop the return value if there is one and stack should be empty
			//
			if (statement && method.ReturnType.Kind != MemberKind.Void)
				ec.Emit (OpCodes.Pop);
		}
Example #3
0
        public void EmitPredefined(EmitContext ec, MethodSpec method, Arguments Arguments, bool statement = false, Location?loc = null)
        {
            Expression instance_copy = null;

            if (!HasAwaitArguments && ec.HasSet(BuilderContext.Options.AsyncBody))
            {
                HasAwaitArguments = Arguments != null && Arguments.ContainsEmitWithAwait();
                if (HasAwaitArguments && InstanceExpressionOnStack)
                {
                    throw new NotSupportedException();
                }
            }

            OpCode          call_op;
            LocalTemporary  lt = null;
            InstanceEmitter ie = new InstanceEmitter();

            if (method.IsStatic)
            {
                call_op = OpCodes.Call;
            }
            else
            {
                if (IsVirtualCallRequired(InstanceExpression, method))
                {
                    call_op = OpCodes.Callvirt;
                }
                else
                {
                    call_op = OpCodes.Call;
                }

                if (HasAwaitArguments)
                {
                    instance_copy = InstanceExpression.EmitToField(ec);
                    ie            = new InstanceEmitter(instance_copy, IsAddressCall(instance_copy, call_op, method.DeclaringType));

                    if (Arguments == null)
                    {
                        ie.EmitLoad(ec);
                    }
                }
                else if (!InstanceExpressionOnStack)
                {
                    ie = new InstanceEmitter(InstanceExpression, IsAddressCall(InstanceExpression, call_op, method.DeclaringType));
                    ie.NullShortCircuit = NullShortCircuit;
                    ie.Emit(ec);

                    if (NullShortCircuit)
                    {
                        NullOperatorLabel = ie.NullOperatorLabel;
                    }

                    if (DuplicateArguments)
                    {
                        ec.Emit(OpCodes.Dup);
                        if (Arguments != null && Arguments.Count != 0)
                        {
                            lt = new LocalTemporary(ie.GetStackType(ec));
                            lt.Store(ec);
                            instance_copy = lt;
                        }
                    }
                }
            }

            if (Arguments != null && !InstanceExpressionOnStack)
            {
                EmittedArguments = Arguments.Emit(ec, DuplicateArguments, HasAwaitArguments);
                if (EmittedArguments != null)
                {
                    if (instance_copy != null)
                    {
                        ie = new InstanceEmitter(instance_copy, IsAddressCall(instance_copy, call_op, method.DeclaringType));
                        ie.Emit(ec);

                        if (lt != null)
                        {
                            lt.Release(ec);
                        }
                    }

                    EmittedArguments.Emit(ec);
                }
            }

            if (call_op == OpCodes.Callvirt && (InstanceExpression.Type.IsGenericParameter || InstanceExpression.Type.IsStructOrEnum))
            {
                ec.Emit(OpCodes.Constrained, InstanceExpression.Type);
            }

            if (loc != null)
            {
                //
                // Emit explicit sequence point for expressions like Foo.Bar () to help debugger to
                // break at right place when LHS expression can be stepped-into
                //
                ec.MarkCallEntry(loc.Value);
            }

            //
            // Set instance expression to actual result expression. When it contains await it can be
            // picked up by caller
            //
            InstanceExpression = instance_copy;

            if (method.Parameters.HasArglist)
            {
                var varargs_types = GetVarargsTypes(method, Arguments);
                ec.Emit(call_op, method, varargs_types);
            }
            else
            {
                //
                // If you have:
                // this.DoFoo ();
                // and DoFoo is not virtual, you can omit the callvirt,
                // because you don't need the null checking behavior.
                //
                ec.Emit(call_op, method);
            }

            //
            // Pop the return value if there is one and stack should be empty
            //
            if (statement && method.ReturnType.Kind != MemberKind.Void)
            {
                ec.Emit(OpCodes.Pop);
            }

            if (NullShortCircuit && !DuplicateArguments)
            {
                ie.EmitResultLift(ec, method.ReturnType, statement);
            }
        }
Example #4
0
		public void EmitPredefined (EmitContext ec, MethodSpec method, Arguments Arguments)
		{
			Expression instance_copy = null;

			if (!HasAwaitArguments && ec.HasSet (BuilderContext.Options.AsyncBody)) {
				HasAwaitArguments = Arguments != null && Arguments.ContainsEmitWithAwait ();
				if (HasAwaitArguments && InstanceExpressionOnStack) {
					throw new NotSupportedException ();
				}
			}

			OpCode call_op;
			LocalTemporary lt = null;

			if (method.IsStatic) {
				call_op = OpCodes.Call;
			} else {
				if (IsVirtualCallRequired (InstanceExpression, method)) {
					call_op = OpCodes.Callvirt;
				} else {
					call_op = OpCodes.Call;
				}

				if (HasAwaitArguments) {
					instance_copy = InstanceExpression.EmitToField (ec);
					if (Arguments == null)
						EmitCallInstance (ec, instance_copy, method.DeclaringType, call_op);
				} else if (!InstanceExpressionOnStack) {
					var instance_on_stack_type = EmitCallInstance (ec, InstanceExpression, method.DeclaringType, call_op);

					if (DuplicateArguments) {
						ec.Emit (OpCodes.Dup);
						if (Arguments != null && Arguments.Count != 0) {
							lt = new LocalTemporary (instance_on_stack_type);
							lt.Store (ec);
							instance_copy = lt;
						}
					}
				}
			}

			if (Arguments != null && !InstanceExpressionOnStack) {
				EmittedArguments = Arguments.Emit (ec, DuplicateArguments, HasAwaitArguments);
				if (EmittedArguments != null) {
					if (instance_copy != null) {
						EmitCallInstance (ec, instance_copy, method.DeclaringType, call_op);

						if (lt != null)
							lt.Release (ec);
					}

					EmittedArguments.Emit (ec);
				}
			}

			if (call_op == OpCodes.Callvirt && (InstanceExpression.Type.IsGenericParameter || InstanceExpression.Type.IsStruct)) {
				ec.Emit (OpCodes.Constrained, InstanceExpression.Type);
			}

			//
			// Set instance expression to actual result expression. When it contains await it can be
			// picked up by caller
			//
			InstanceExpression = instance_copy;

			if (method.Parameters.HasArglist) {
				var varargs_types = GetVarargsTypes (method, Arguments);
				ec.Emit (call_op, method, varargs_types);
				return;
			}

			//
			// If you have:
			// this.DoFoo ();
			// and DoFoo is not virtual, you can omit the callvirt,
			// because you don't need the null checking behavior.
			//
			ec.Emit (call_op, method);
		}
		public void EmitPredefined (EmitContext ec, MethodSpec method, Arguments Arguments, Location? loc = null)
		{
			Expression instance_copy = null;

			if (!HasAwaitArguments && ec.HasSet (BuilderContext.Options.AsyncBody)) {
				HasAwaitArguments = Arguments != null && Arguments.ContainsEmitWithAwait ();
				if (HasAwaitArguments && InstanceExpressionOnStack) {
					throw new NotSupportedException ();
				}
			}

			OpCode call_op;
			LocalTemporary lt = null;

			if (method.IsStatic) {
				call_op = OpCodes.Call;
			} else {
				if (IsVirtualCallRequired (InstanceExpression, method)) {
					call_op = OpCodes.Callvirt;
				} else {
					call_op = OpCodes.Call;
				}

				if (HasAwaitArguments) {
					instance_copy = InstanceExpression.EmitToField (ec);
					if (Arguments == null)
						EmitCallInstance (ec, instance_copy, method.DeclaringType, call_op);
				} else if (!InstanceExpressionOnStack) {
					var instance_on_stack_type = EmitCallInstance (ec, InstanceExpression, method.DeclaringType, call_op);

					if (DuplicateArguments) {
						ec.Emit (OpCodes.Dup);
						if (Arguments != null && Arguments.Count != 0) {
							lt = new LocalTemporary (instance_on_stack_type);
							lt.Store (ec);
							instance_copy = lt;
						}
					}
				}
			}

			if (Arguments != null && !InstanceExpressionOnStack) {
				EmittedArguments = Arguments.Emit (ec, DuplicateArguments, HasAwaitArguments);
				if (EmittedArguments != null) {
					if (instance_copy != null) {
						EmitCallInstance (ec, instance_copy, method.DeclaringType, call_op);

						if (lt != null)
							lt.Release (ec);
					}

					EmittedArguments.Emit (ec);
				}
			}

			if (call_op == OpCodes.Callvirt && (InstanceExpression.Type.IsGenericParameter || InstanceExpression.Type.IsStruct)) {
				ec.Emit (OpCodes.Constrained, InstanceExpression.Type);
			}

			if (loc != null) {
				//
				// Emit explicit sequence point for expressions like Foo.Bar () to help debugger to
				// break at right place when LHS expression can be stepped-into
				//
				// TODO: The list is probably not comprehensive, need to do more testing
				//
				if (InstanceExpression is PropertyExpr || InstanceExpression is Invocation || InstanceExpression is IndexerExpr ||
					InstanceExpression is New || InstanceExpression is DelegateInvocation)
					ec.Mark (loc.Value);
			}

			//
			// Set instance expression to actual result expression. When it contains await it can be
			// picked up by caller
			//
			InstanceExpression = instance_copy;

			if (method.Parameters.HasArglist) {
				var varargs_types = GetVarargsTypes (method, Arguments);
				ec.Emit (call_op, method, varargs_types);
				return;
			}

			//
			// If you have:
			// this.DoFoo ();
			// and DoFoo is not virtual, you can omit the callvirt,
			// because you don't need the null checking behavior.
			//
			ec.Emit (call_op, method);
		}
		// `dup_args' leaves an extra copy of the arguments on the stack
		// `omit_args' does not leave any arguments at all.
		// So, basically, you could make one call with `dup_args' set to true,
		// and then another with `omit_args' set to true, and the two calls
		// would have the same set of arguments. However, each argument would
		// only have been evaluated once.
		public static void EmitCall (EmitContext ec, bool is_base,
					     Expression instance_expr,
					     MethodBase method, Arguments Arguments, Location loc,
		                             bool dup_args, bool omit_args)
		{
			ILGenerator ig = ec.ig;
			bool struct_call = false;
			bool this_call = false;
			LocalTemporary this_arg = null;

			Type decl_type = method.DeclaringType;

			if (IsMethodExcluded (method, loc))
				return;
			
			bool is_static = method.IsStatic;
			if (!is_static){
				this_call = instance_expr is This;
				if (TypeManager.IsStruct (decl_type) || TypeManager.IsEnumType (decl_type))
					struct_call = true;

				//
				// If this is ourselves, push "this"
				//
				if (!omit_args) {
					Type t = null;
					Type iexpr_type = instance_expr.Type;

					//
					// Push the instance expression
					//
					if (TypeManager.IsValueType (iexpr_type) || TypeManager.IsGenericParameter (iexpr_type)) {
						//
						// Special case: calls to a function declared in a 
						// reference-type with a value-type argument need
						// to have their value boxed.
						if (TypeManager.IsStruct (decl_type) ||
						    TypeManager.IsGenericParameter (iexpr_type)) {
							//
							// If the expression implements IMemoryLocation, then
							// we can optimize and use AddressOf on the
							// return.
							//
							// If not we have to use some temporary storage for
							// it.
							if (instance_expr is IMemoryLocation) {
								((IMemoryLocation)instance_expr).
									AddressOf (ec, AddressOp.LoadStore);
							} else {
								LocalTemporary temp = new LocalTemporary (iexpr_type);
								instance_expr.Emit (ec);
								temp.Store (ec);
								temp.AddressOf (ec, AddressOp.Load);
							}

							// avoid the overhead of doing this all the time.
							if (dup_args)
								t = TypeManager.GetReferenceType (iexpr_type);
						} else {
							instance_expr.Emit (ec);
							
							// FIXME: should use instance_expr is IMemoryLocation + constraint.
							// to help JIT to produce better code
							ig.Emit (OpCodes.Box, instance_expr.Type);
							t = TypeManager.object_type;
						}
					} else {
						instance_expr.Emit (ec);
						t = instance_expr.Type;
					}

					if (dup_args) {
						ig.Emit (OpCodes.Dup);
						if (Arguments != null && Arguments.Count != 0) {
							this_arg = new LocalTemporary (t);
							this_arg.Store (ec);
						}
					}
				}
			}

			if (!omit_args && Arguments != null)
				Arguments.Emit (ec, dup_args, this_arg);

			OpCode call_op;
			if (is_static || struct_call || is_base || (this_call && !method.IsVirtual)) {
				call_op = OpCodes.Call;
			} else {
				call_op = OpCodes.Callvirt;
				
#if GMCS_SOURCE
				if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
					ig.Emit (OpCodes.Constrained, instance_expr.Type);
#endif
			}

			if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
				Type[] varargs_types = GetVarargsTypes (method, Arguments);
				ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
				return;
			}

			//
			// If you have:
			// this.DoFoo ();
			// and DoFoo is not virtual, you can omit the callvirt,
			// because you don't need the null checking behavior.
			//
			if (method is MethodInfo)
				ig.Emit (call_op, (MethodInfo) method);
			else
				ig.Emit (call_op, (ConstructorInfo) method);
		}