Beispiel #1
0
        // Compile all methods not already compiled by above
        private void CompileMethods(Seq <JST.Statement> body, JST.NameSupply outerNameSupply)
        {
            switch (Env.CompilationMode)
            {
            case CompilationMode.Plain:
            case CompilationMode.Collecting:
                // Already compiled above
                return;

            case CompilationMode.Traced:
                foreach (var methodDef in
                         Methods.Where(d => TypeTrace.Methods.Contains(d.MethodSignature)))
                {
                    if (TypeTrace.Parent.Parent.Flavor == TraceFlavor.Remainder)
                    {
                        // Compile method into stand-alone loader
                        var compiler = new MethodCompiler(this, outerNameSupply, methodDef, MethodCompilationMode.SelfContained);
                        compiler.Emit(body, null);
                    }
                    else
                    {
                        // Bind method definition into method cache
                        var target = TypeDefinitionId.ToE();
                        if (TyconEnv.Type.Arity == 0 && !Env.InteropManager.IsStatic(TyconEnv.Assembly, TyconEnv.Type, methodDef))
                        {
                            target = JST.Expression.Dot
                                         (target, Constants.TypeConstructObject, Constants.prototype);
                        }
                        target = JST.Expression.Dot(target, Constants.TypeMethodCache);
                        var compiler = new MethodCompiler(this, outerNameSupply, methodDef, MethodCompilationMode.DirectBind);
                        compiler.Emit(body, target);
                    }
                }
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }
        }
Beispiel #2
0
        // ----------------------------------------------------------------------
        // Methods
        // ----------------------------------------------------------------------

        // Emit bindings for static or instance methods, but not for virtuals or interface methods
        //  - Invoked from TypeDefinitionCompiler for higher-kinded type definitions
        //  - Invoked from TypeCompiler for first-kinded type definitions
        public void EmitMethods(Seq <JST.Statement> body, JST.Expression lhs, JST.NameSupply outerNameSupply, JST.Expression target, bool isStatic)
        {
            switch (Env.CompilationMode)
            {
            case CompilationMode.Plain:
            {
                // Method definitions are bound directly into target
                foreach (var methodDef in Methods.Where(m => m.Invalid == null))
                {
                    if (Env.InteropManager.IsStatic(TyconEnv.Assembly, TyconEnv.Type, methodDef) == isStatic)
                    {
                        var compiler = new MethodCompiler(this, outerNameSupply, methodDef, MethodCompilationMode.DirectBind);
                        compiler.Emit(body, target);
                    }
                }
                break;
            }

            case CompilationMode.Collecting:
            {
                // Method definitions are bound into MethodCache, redirectors are bound into target
                foreach (var methodDef in Methods.Where(m => m.Invalid == null))
                {
                    if (Env.InteropManager.IsStatic(TyconEnv.Assembly, TyconEnv.Type, methodDef) == isStatic)
                    {
                        var slot       = Env.GlobalMapping.ResolveMethodDefToSlot(TyconEnv.Assembly, TyconEnv.Type, methodDef);
                        var methodName = CST.CSTWriter.WithAppend
                                             (Env.Global, CST.WriterStyle.Uniform, methodDef.MethodSignature.Append);
                        body.Add
                            (JST.Statement.DotCall
                                (RootId.ToE(),
                                Constants.RootCollectingBindMethodBuilder,
                                lhs,
                                new JST.BooleanLiteral(isStatic),
                                new JST.StringLiteral(slot),
                                new JST.StringLiteral(methodName)));
                        var compiler = new MethodCompiler(this, outerNameSupply, methodDef, MethodCompilationMode.DirectBind);
                        compiler.Emit(body, JST.Expression.Dot(target, Constants.TypeMethodCache));
                    }
                }
                break;
            }

            case CompilationMode.Traced:
            {
                // Methods in the initial trace or this trace will be bound directly.
                // Methods in a trace other than above are bound via builder which is given trace name.
                // Remaining methods are built via builder with null trace name.
                var traceToArgs   = new Map <string, Seq <JST.Expression> >();
                var remainingArgs = new Seq <JST.Expression>();
                remainingArgs.Add(TypeDefinitionId.ToE());
                remainingArgs.Add(new JST.BooleanLiteral(isStatic));
                remainingArgs.Add(new JST.NullExpression());
                foreach (var methodDef in Methods.Where(m => m.Invalid == null))
                {
                    if (Env.InteropManager.IsStatic(TyconEnv.Assembly, TyconEnv.Type, methodDef) == isStatic)
                    {
                        var slot     = Env.GlobalMapping.ResolveMethodDefToSlot(TyconEnv.Assembly, TyconEnv.Type, methodDef);
                        var defTrace = Env.Traces.MethodToTrace[methodDef.QualifiedMemberName(Env.Global, TyconEnv.Assembly, TyconEnv.Type)];
                        if (defTrace.Flavor == TraceFlavor.OnDemand && defTrace != TypeTrace.Parent.Parent)
                        {
                            // Method definition in in another trace, bind redirector for it.
                            var args = default(Seq <JST.Expression>);
                            if (!traceToArgs.TryGetValue(defTrace.Name, out args))
                            {
                                args = new Seq <JST.Expression>();
                                args.Add(lhs);
                                args.Add(new JST.BooleanLiteral(isStatic));
                                args.Add(new JST.StringLiteral(defTrace.Name));
                                traceToArgs.Add(defTrace.Name, args);
                            }
                            args.Add(new JST.StringLiteral(slot));
                        }
                        else if (defTrace.Flavor == TraceFlavor.Remainder)
                        {
                            // Method definition is in a stand-alone loader, bind redirector for it.
                            remainingArgs.Add(new JST.StringLiteral(slot));
                        }
                        else
                        {
                            // Method definition is bound directly
                            var compiler = new MethodCompiler(this, outerNameSupply, methodDef, MethodCompilationMode.DirectBind);
                            compiler.Emit(body, target);
                        }
                    }
                }
                foreach (var kv in traceToArgs)
                {
                    body.Add(JST.Statement.DotCall(RootId.ToE(), Constants.RootBindMethodBuilders, kv.Value));
                }
                if (remainingArgs.Count > 3)
                {
                    body.Add(JST.Statement.DotCall(RootId.ToE(), Constants.RootBindMethodBuilders, remainingArgs));
                }
                break;
            }

            default:
                throw new ArgumentOutOfRangeException();
            }
        }