// 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(); } }
// ---------------------------------------------------------------------- // 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(); } }