예제 #1
0
        public override void Emit(CodeGen cg)
        {
            // TODO: Improve the following to direct call: Callable.Call(Callable.Create(...))
            //EmitLocation(cg);
            if (_instance != null && !cg.IsDynamicMethod) // damn DM! // go away! // this dangerous too for now
            {
                if (!IsParamsMethod())
                {
                    if (_instance is CodeBlockExpression)
                    {
                        CodeBlockExpression cbe = (CodeBlockExpression)_instance;

                        Debug.Assert(_arguments.Count == _parameterInfos.Length);
                        for (int arg = 0; arg < _parameterInfos.Length; arg++)
                        {
                            Expression argument = _arguments[arg];
                            Type       type     = _parameterInfos[arg].ParameterType;
                            EmitArgument(cg, argument, type);
                        }

                        EmitLocation(cg);

                        if (tailcall)
                        {
                            // TODO: Remove tail calls from list of known non-recursive methods
                            //Console.WriteLine(cbe.Block.Name);
                            tailcall = true;
                        }

                        cbe.EmitDirect(cg, tailcall);

                        if (ScriptDomainManager.Options.LightweightDebugging && !tailcall && Span.IsValid)
                        {
                            cg.EmitConstant(SpanToLong(Span));
                            cg.EmitCall(Debugging.DebugMethods.ExpressionOut);
                        }

                        return;
                    }
                }
                else // 'params'
                {
                }
            }

            if (_method == BuiltinsIsTrue)
            {
                EmitLocation(cg);
                var arg = Unwrap(_arguments[0]);
                if (arg.Type == typeof(bool))
                {
                    arg.Emit(cg);
                }
                else if (arg.Type == typeof(object))
                {
                    Label next = cg.DefineLabel();
                    Label end  = cg.DefineLabel();
                    arg.Emit(cg);
                    cg.Emit(OpCodes.Dup);
                    cg.Emit(OpCodes.Isinst, typeof(bool));
                    cg.Emit(OpCodes.Brfalse, next);

                    cg.EmitUnbox(typeof(bool));
                    cg.Emit(OpCodes.Br, end);

                    cg.MarkLabel(next);
                    cg.Emit(OpCodes.Pop);
                    cg.EmitConstant(true);
                    cg.MarkLabel(end);
                }
                else
                {
                    cg.EmitConstant(true);
                }
                return;
            }

            var ii = _instance;

            ii = Unwrap(ii);

            BoundExpression.Emitter fixup = null;
            bool varargs = false;
            var  pttt    = Array.ConvertAll(_parameterInfos, x => x.ParameterType);

            if (ii is BoundExpression)
            {
                var be = ii as BoundExpression;

                if (BoundExpression.Fixups.ContainsKey(be.Variable.Name))
                {
                    fixup = BoundExpression.Fixups[be.Variable.Name];
                    pttt  = BoundExpression.FixupTypes[be.Variable.Name];
                }
                else
                {
                    CodeGen             rcg;
                    CodeGenDescriptor[] cgd;
                    if (CodeGen._codeBlockLookup.TryGetValue(be.Variable.Name, out rcg))
                    {
                        var lpttt = pt.GetValue(rcg.MethodInfo) as Type[];
                        if (_arguments.Count == lpttt.Length)
                        {
                            _method = rcg.MethodInfo;
                            pttt    = lpttt;
                        }
                    }
                    else if (CodeGen._codeBlockLookupX.TryGetValue(be.Variable.Name, out rcg))
                    {
                        var lpppt = pt.GetValue(rcg.MethodInfo) as Type[];
                        if (lpppt.Length - 1 > _arguments.Count)
                        {
                        }
                        else if (AllArgsAreObject(_arguments))
                        {
                            _method = rcg.MethodInfo;
                            pttt    = lpppt;
                            varargs = true;
                        }
                        else if (_arguments.Count == 1 && lpppt.Length == 1 &&
                                 _arguments[0].Type == typeof(object[]) && _arguments[0] is MethodCallExpression &&
                                 ((MethodCallExpression)_arguments[0])._method.Name == "ListToVector")
                        {
                            _arguments[0] = Unwrap(((MethodCallExpression)_arguments[0]).Arguments[0]);
                            _method       = rcg.MethodInfo;
                            pttt          = lpppt;
                        }
                    }
                    else if (CodeGen._codeBlockLookupN.TryGetValue(be.Variable.Name, out cgd))
                    {
                        if (AllArgsAreObject(_arguments))
                        {
                            foreach (var i in cgd)
                            {
                                if (i.arity == _arguments.Count)
                                {
                                    _method = i.cg.MethodInfo;
                                    pttt    = pt.GetValue(_method) as Type[];
                                    break;
                                }
                            }
                        }
                    }
                }
            }
            // Emit instance, if calling an instance method
            if (!_method.IsStatic)
            {
                Type type = _method.DeclaringType;

                if (type.IsValueType)
                {
                    _instance.EmitAddress(cg, type);
                }
                else
                {
                    if (fixup == null)
                    {
                        _instance.Emit(cg);
                    }
                }
            }

            if (varargs)
            {
                int arg = 0;
                for (; arg < pttt.Length - 1; arg++)
                {
                    Expression argument = _arguments[arg];
                    Type       type     = pttt[arg];
                    EmitArgument(cg, argument, type);
                }
                // make tail
                var tailargs = new List <Expression>();
                for (; arg < _arguments.Count; arg++)
                {
                    tailargs.Add(_arguments[arg]);
                }
                var tailarr = tailargs.ToArray();
                var tail    = Ast.ComplexCallHelper(MakeList(tailarr, true), tailarr);
                EmitArgument(cg, tail, typeof(object));
            }
            else
            {
                // Emit arguments
                // we cant really complain here or show error...
                Debug.Assert(_arguments.Count == pttt.Length);
                for (int arg = 0; arg < pttt.Length && arg < _arguments.Count; arg++)
                {
                    Expression argument = _arguments[arg];
                    Type       type     = pttt[arg];
                    EmitArgument(cg, argument, type);
                }
            }

            // check for possible conversion/boxing needed, disabled tail call
            if (tailcall)
            {
                if (ShouldTailCallBeRemoved(cg))
                {
                    //Console.WriteLine("Removing tail call: {0} in {1}", cg.MethodBase, cg.TypeGen.AssemblyGen.AssemblyBuilder);
                    tailcall = false;
                }
            }

            EmitLocation(cg);

            // Emit the actual call
            if (fixup == null)
            {
                cg.EmitCall(_method, tailcall);
            }
            else
            {
                fixup(cg, tailcall);
            }

            if (ScriptDomainManager.Options.LightweightDebugging && !tailcall && Span.IsValid)
            {
                cg.EmitConstant(SpanToLong(Span));
                cg.EmitCall(Debugging.DebugMethods.ExpressionOut);
            }
        }