private static bool IsUpToDate(CompilerEnvironment env, CST.AssemblyDef assembly, bool complain) { var annot = assembly.Annotations.OfType<CST.AssemblyFileAnnotation>().FirstOrDefault(); if (annot == null) throw new InvalidOperationException("assembly is missing file annotation"); var fn = default(string); var lastCompTime = AssemblyCompiler.LastCompilationTime(env, assembly.Name, out fn); if (lastCompTime.HasValue) { if (annot.LastWriteTime <= lastCompTime.Value) return true; else { if (complain) env.Log (new OutOfDateAssemblyMessage(assembly.Name, annot.CanonicalFileName, fn)); return false; } } else { if (complain) env.Log(new AssemblyNotCompiledMessage(assembly.Name, fn)); return false; } }
// Collect types we need to compile private void CollectTypes() { foreach (var typeDef in assmEnv.Assembly.Types.Where(t => t.Invalid == null)) { var tyconEnv = assmEnv.AddType(typeDef); if (typeDef.IsModule) { // Look for any <Module>::.cctor() // We know both <Module> and the .cctor have no type parameters var methodDef = typeDef.Members.OfType <CST.MethodDef>().Where (m => m.Invalid == null && m.IsStatic && m.IsConstructor).FirstOrDefault(); if (methodDef != null) { moduleInitializer = methodDef.SelfMethodReference(tyconEnv); } } if (typeDef.IsUsed) { typeDefs.Add(typeDef); } else { if (assemblyTrace == null || assemblyTrace.IncludeAssembly) { Env.Log(new UnusedDefinitionMessage(CST.MessageContextBuilders.Env(tyconEnv))); } } } }
public void Add(string traceFileName, bool isInitial) { var name = Path.GetFileNameWithoutExtension(traceFileName); if (TraceMap.ContainsKey(name)) { Env.Log(new InvalidTraceMessage(null, "duplicate trace names")); throw new ExitException(); } var trace = new Trace(this, name, isInitial ? TraceFlavor.Initial : TraceFlavor.OnDemand); trace.Load(this, traceFileName); TraceMap.Add(name, trace); }
public void Emit() { if (Trace.Flavor == TraceFlavor.Remainder) { foreach (var kv in Trace.AssemblyMap) { var compiler = new AssemblyCompiler(this, kv.Value); compiler.Emit(null); } } else { var rootEnv = Env.Global.Environment(); var body = new Seq <JST.Statement>(); body.Add(JST.Statement.Var(RootId, new JST.Identifier(Env.Root).ToE())); foreach (var nm in rootEnv.AllLoadedAssembliesInLoadOrder().Where(Trace.AssemblyMap.ContainsKey)) { var compiler = new AssemblyCompiler(this, Trace.AssemblyMap[nm]); compiler.Emit(body); } var program = new JST.Program (new JST.Statements (new JST.ExpressionStatement (new JST.StatementsPseudoExpression(new JST.Statements(body), null)))); var fileName = Path.Combine(Env.OutputDirectory, Trace.Name + ".js"); program.ToFile(fileName, Env.PrettyPrint); Env.Log(new GeneratedJavaScriptFile("trace '" + Trace.Name + "'", fileName)); } }
private static bool IsUpToDate(CompilerEnvironment env, CST.AssemblyDef assembly, bool complain) { var annot = assembly.Annotations.OfType <CST.AssemblyFileAnnotation>().FirstOrDefault(); if (annot == null) { throw new InvalidOperationException("assembly is missing file annotation"); } var fn = default(string); var lastCompTime = AssemblyCompiler.LastCompilationTime(env, assembly.Name, out fn); if (lastCompTime.HasValue) { if (annot.LastWriteTime <= lastCompTime.Value) { return(true); } else { if (complain) { env.Log (new OutOfDateAssemblyMessage(assembly.Name, annot.CanonicalFileName, fn)); } return(false); } } else { if (complain) { env.Log(new AssemblyNotCompiledMessage(assembly.Name, fn)); } return(false); } }
public static int Main(string[] args) { var env = new CompilerEnvironment(); try { // Collect command line args var cl = new CompilerCommandLine(env.Log, env); cl.MergeFromArgs(args); if (env.CompilationMode == CompilationMode.Traced && env.TraceFileNames.Count == 0 && string.IsNullOrEmpty(env.FinalTraceName)) { env.Log(new UsageMessage("'-mode traced' must be accompanied by at least on of '-trace' or '-finalTraceName' options.")); throw new ExitException(); } env.SetupPrimTracer(); // ---------------------------------------- // Load the assemblies // ---------------------------------------- // Renames var subst = new CST.AssemblyNameSubstitution(env.Log, env.PrimTracer, env.AssemblyNameResolution); foreach (var r in env.RenameRules) { subst.Add(r); } // Augmentations var augmentations = new CST.AugmentationDatabase(subst); foreach (var fn in env.AugmentationFileNames) { augmentations.AddFile(Path.Combine(env.InputDirectory, fn)); } foreach (var sn in env.OriginalStrongNames) { augmentations.AddOriginal(sn); } // Final references var loadedAssemblies = new CST.LoadedAssemblyDatabase(augmentations); foreach (var fileName in env.ReferenceFileNames) { loadedAssemblies.Add(fileName, false); } foreach (var fileName in env.CompileFileNames) { loadedAssemblies.Add(fileName, true); } var loader = new CST.PELoader(loadedAssemblies); var global = loader.Load(); // Done with the loader loader = null; env.SetupMetadata(global); try { env.Validity.Check(); foreach (var assmInfo in loadedAssemblies) { env.Log(new CST.LoadedAssemblyMessage(assmInfo.TargetAssemblyName)); } if (env.Tracer != null) { env.Tracer.Trace ("Loaded assemblies", w => { foreach (var assemblyDef in global.Assemblies) { assemblyDef.Append(w); w.EndLine(); } }); } // ---------------------------------------- // Setup Interop // ---------------------------------------- env.InteropManager.Setup(); // ---------------------------------------- // Collect assemblies // ---------------------------------------- var allAssemblies = new Set <CST.AssemblyDef>(); var compilingAssemblies = new Set <CST.AssemblyDef>(); var referencedAssemblies = new Set <CST.AssemblyDef>(); var ok = true; foreach (var assmInfo in loadedAssemblies) { var assembly = assmInfo.AssemblyDef; allAssemblies.Add(assembly); if (assmInfo.ForCompilation) { if (string.IsNullOrEmpty(env.OutputDirectory)) { env.Log (new SkippingJavaScriptComplilation (assembly.Name, "No output directory was given")); referencedAssemblies.Add(assembly); } else if (env.SkipUpToDate && IsUpToDate(env, assembly, false)) { env.Log (new SkippingJavaScriptComplilation (assembly.Name, "Previously generated JavaScript is up to date")); referencedAssemblies.Add(assembly); } else { compilingAssemblies.Add(assembly); } } else { if (IsUpToDate(env, assembly, true)) { referencedAssemblies.Add(assembly); } else { ok = false; } } } // Done with compilations loadedAssemblies = null; if (!ok) { throw new ExitException(); } if (compilingAssemblies.Count > 0) { // ---------------------------------------- // Compile // ---------------------------------------- switch (env.CompilationMode) { case CompilationMode.Plain: case CompilationMode.Collecting: // Compile all assemblies foreach (var assemblyDef in compilingAssemblies) { var ac = new AssemblyCompiler(env, assemblyDef); ac.Emit(null); } break; case CompilationMode.Traced: // Collect the trace file info if (!string.IsNullOrEmpty(env.InitialTraceFileName)) { env.Traces.Add(env.InitialTraceFileName, true); } foreach (var fn in env.TraceFileNames) { env.Traces.Add(fn, false); } env.Traces.AddFinalOrRemainder(env.FinalTraceName); // Compile all traces and all remaining definitions foreach (var kv in env.Traces.TraceMap) { var compiler = new TraceCompiler(env, kv.Value); compiler.Emit(); } break; default: throw new ArgumentOutOfRangeException(); } // ---------------------------------------- // Runtime // ---------------------------------------- if (env.Global.Assemblies.Any(a => a.EntryPoint != null)) { // Emit the runtime itself var compiler = new RuntimeCompiler(env); compiler.Emit(); } } } finally { env.Teardown(); } } catch (ExitException) { // No-op } catch (Exception e) { Console.WriteLine("Internal error: {0}", e.Message); Console.WriteLine("Please report this error to the developers"); env.NumErrors++; } finally { Console.WriteLine("{0} errors, {1} warnings", env.NumErrors, env.NumWarnings); } return(env.NumErrors == 0 ? 0 : 1); }
public static int Main(string[] args) { var env = new CompilerEnvironment(); try { // Collect command line args var cl = new CompilerCommandLine(env.Log, env); cl.MergeFromArgs(args); if (env.CompilationMode == CompilationMode.Traced && env.TraceFileNames.Count == 0 && string.IsNullOrEmpty(env.FinalTraceName)) { env.Log(new UsageMessage("'-mode traced' must be accompanied by at least on of '-trace' or '-finalTraceName' options.")); throw new ExitException(); } env.SetupPrimTracer(); // ---------------------------------------- // Load the assemblies // ---------------------------------------- // Renames var subst = new CST.AssemblyNameSubstitution(env.Log, env.PrimTracer, env.AssemblyNameResolution); foreach (var r in env.RenameRules) subst.Add(r); // Augmentations var augmentations = new CST.AugmentationDatabase(subst); foreach (var fn in env.AugmentationFileNames) augmentations.AddFile(Path.Combine(env.InputDirectory, fn)); foreach (var sn in env.OriginalStrongNames) augmentations.AddOriginal(sn); // Final references var loadedAssemblies = new CST.LoadedAssemblyDatabase(augmentations); foreach (var fileName in env.ReferenceFileNames) loadedAssemblies.Add(fileName, false); foreach (var fileName in env.CompileFileNames) loadedAssemblies.Add(fileName, true); var loader = new CST.PELoader(loadedAssemblies); var global = loader.Load(); // Done with the loader loader = null; env.SetupMetadata(global); try { env.Validity.Check(); foreach (var assmInfo in loadedAssemblies) env.Log(new CST.LoadedAssemblyMessage(assmInfo.TargetAssemblyName)); if (env.Tracer != null) env.Tracer.Trace ("Loaded assemblies", w => { foreach (var assemblyDef in global.Assemblies) { assemblyDef.Append(w); w.EndLine(); } }); // ---------------------------------------- // Setup Interop // ---------------------------------------- env.InteropManager.Setup(); // ---------------------------------------- // Collect assemblies // ---------------------------------------- var allAssemblies = new Set<CST.AssemblyDef>(); var compilingAssemblies = new Set<CST.AssemblyDef>(); var referencedAssemblies = new Set<CST.AssemblyDef>(); var ok = true; foreach (var assmInfo in loadedAssemblies) { var assembly = assmInfo.AssemblyDef; allAssemblies.Add(assembly); if (assmInfo.ForCompilation) { if (string.IsNullOrEmpty(env.OutputDirectory)) { env.Log (new SkippingJavaScriptComplilation (assembly.Name, "No output directory was given")); referencedAssemblies.Add(assembly); } else if (env.SkipUpToDate && IsUpToDate(env, assembly, false)) { env.Log (new SkippingJavaScriptComplilation (assembly.Name, "Previously generated JavaScript is up to date")); referencedAssemblies.Add(assembly); } else compilingAssemblies.Add(assembly); } else { if (IsUpToDate(env, assembly, true)) referencedAssemblies.Add(assembly); else ok = false; } } // Done with compilations loadedAssemblies = null; if (!ok) throw new ExitException(); if (compilingAssemblies.Count > 0) { // ---------------------------------------- // Compile // ---------------------------------------- switch (env.CompilationMode) { case CompilationMode.Plain: case CompilationMode.Collecting: // Compile all assemblies foreach (var assemblyDef in compilingAssemblies) { var ac = new AssemblyCompiler(env, assemblyDef); ac.Emit(null); } break; case CompilationMode.Traced: // Collect the trace file info if (!string.IsNullOrEmpty(env.InitialTraceFileName)) env.Traces.Add(env.InitialTraceFileName, true); foreach (var fn in env.TraceFileNames) env.Traces.Add(fn, false); env.Traces.AddFinalOrRemainder(env.FinalTraceName); // Compile all traces and all remaining definitions foreach (var kv in env.Traces.TraceMap) { var compiler = new TraceCompiler(env, kv.Value); compiler.Emit(); } break; default: throw new ArgumentOutOfRangeException(); } // ---------------------------------------- // Runtime // ---------------------------------------- if (env.Global.Assemblies.Any(a => a.EntryPoint != null)) { // Emit the runtime itself var compiler = new RuntimeCompiler(env); compiler.Emit(); } } } finally { env.Teardown(); } } catch (ExitException) { // No-op } catch (Exception e) { Console.WriteLine("Internal error: {0}", e.Message); Console.WriteLine("Please report this error to the developers"); env.NumErrors++; } finally { Console.WriteLine("{0} errors, {1} warnings", env.NumErrors, env.NumWarnings); } return env.NumErrors == 0 ? 0 : 1; }
// Collect and filter members for subsequent code gen private void CollectMembers() { var fields = new Seq <CST.FieldDef>(); var events = new Seq <CST.EventDef>(); var properties = new Seq <CST.PropertyDef>(); var methods = new Seq <CST.MethodDef>(); var exportedInstanceMethods = new Seq <CST.MethodDef>(); StaticInitializer = null; DefaultConstructor = null; numRelevantMethods = 0; foreach (var fieldDef in TyconEnv.Type.Members.OfType <CST.FieldDef>().Where(d => d.Invalid == null)) { if (fieldDef.IsUsed) { fields.Add(fieldDef); } else if (TypeTrace == null || TypeTrace.IncludeType) { Env.Log (new UnusedDefinitionMessage (CST.MessageContextBuilders.Member (Env.Global, TyconEnv.Assembly, TyconEnv.Type, fieldDef))); } } foreach (var eventDef in TyconEnv.Type.Members.OfType <CST.EventDef>().Where(d => d.Invalid == null)) { if (eventDef.IsUsed) { events.Add(eventDef); } else if (TypeTrace == null || TypeTrace.IncludeType) { Env.Log (new UnusedDefinitionMessage (CST.MessageContextBuilders.Member (Env.Global, TyconEnv.Assembly, TyconEnv.Type, eventDef))); } } foreach (var propDef in TyconEnv.Type.Members.OfType <CST.PropertyDef>().Where(d => d.Invalid == null)) { if (propDef.IsUsed) { properties.Add(propDef); } else if (TypeTrace == null || TypeTrace.IncludeType) { Env.Log (new UnusedDefinitionMessage (CST.MessageContextBuilders.Member (Env.Global, TyconEnv.Assembly, TyconEnv.Type, propDef))); } } var state = Env.InteropManager.GetTypeRepresentation(TyconEnv.Assembly, TyconEnv.Type).State; var s = TyconEnv.Type.Style; if (!(s is CST.InterfaceTypeStyle || s is CST.DelegateTypeStyle)) { foreach ( var methodDef in TyconEnv.Type.Members.OfType <CST.MethodDef>().Where(d => d.Invalid == null && !d.IsAbstract)) { if (!methodDef.IsUsed) { if (TypeTrace == null || TypeTrace.IncludeType) { Env.Log (new UnusedDefinitionMessage (CST.MessageContextBuilders.Member (Env.Global, TyconEnv.Assembly, TyconEnv.Type, methodDef))); } } else if (!Env.Validity.IsMustHaveADefinition(methodDef.QualifiedMemberName(Env.Global, TyconEnv.Assembly, TyconEnv.Type)) && (Env.InteropManager.IsInlinable(TyconEnv.Assembly, TyconEnv.Type, methodDef, state) || Env.InlinedMethods.IsInlinable(TyconEnv.Assembly, TyconEnv.Type, methodDef))) { if (TypeTrace == null || TypeTrace.IncludeType) { Env.Log (new InlinedDefinitionMessage (CST.MessageContextBuilders.Member (Env.Global, TyconEnv.Assembly, TyconEnv.Type, methodDef))); } } else if (state != InstanceState.JavaScriptOnly && state != InstanceState.ManagedAndJavaScript && !methodDef.IsStatic && methodDef.IsConstructor && methodDef.Arity > 1 && methodDef.ValueParameters[1].Equals(Env.JSContextRef)) { // Silently ignore importing constructors unless they are needed. // (Remember, the managed interop rewriter will interpert 'Merged' as // 'JavaScriptOnly', and thus may need importing constructors.) } else { if (methodDef.IsStatic && methodDef.IsConstructor) { if (methodDef.TypeArity > 0) { throw new InvalidOperationException ("static constructors cannot be polymorphic"); } StaticInitializer = new CST.MethodRef(TyconEnv.AddSelfTypeBoundArguments().TypeRef, methodDef.MethodSignature, null); } else if (!methodDef.IsStatic && methodDef.IsConstructor && methodDef.Arity == 1 && !Env.InteropManager.IsFactory(TyconEnv.Assembly, TyconEnv.Type, methodDef)) { if (methodDef.TypeArity > 0) { throw new InvalidOperationException ("instance constructors cannot be polymorphic"); } DefaultConstructor = new CST.MethodRef(TyconEnv.AddSelfTypeBoundArguments().TypeRef, methodDef.MethodSignature, null); } if (Env.InteropManager.IsExported(TyconEnv.Assembly, TyconEnv.Type, methodDef)) { if (Env.InteropManager.IsBindToInstance (TyconEnv.Assembly, TyconEnv.Type, methodDef)) { exportedInstanceMethods.Add(methodDef); } // else: will be exported by assembly's Initialize function } methods.Add(methodDef); if (TypeTrace == null || TypeTrace.Methods.Contains(methodDef.MethodSignature)) { numRelevantMethods++; } } } } // else: ignore members of interface and delegate types // TODO: Need to emit reflection data for methods of interface types, thus will need // to collect interface methods Fields = fields; Events = events; Properties = properties; Methods = methods; ExportedInstanceMethods = exportedInstanceMethods; }
public void Emit() { var assm = typeof(RuntimeCompiler).Assembly; var res = "Microsoft.LiveLabs.JavaScript.IL2JS." + Constants.RuntimeFileName; var runtime = default(JST.Program); using (var runtimeStream = assm.GetManifestResourceStream(res)) { if (runtimeStream == null) { throw new InvalidOperationException("unable to find runtime resource"); } runtime = JST.Program.FromStream(Constants.RuntimeFileName, runtimeStream, true); } var mode = default(string); switch (env.CompilationMode) { case CompilationMode.Plain: mode = "plain"; break; case CompilationMode.Collecting: mode = "collecting"; break; case CompilationMode.Traced: mode = "traced"; break; default: throw new ArgumentOutOfRangeException(); } var body = default(ISeq <JST.Statement>); if (env.DebugMode) { body = new Seq <JST.Statement>(); body.Add (JST.Statement.Var(Constants.DebugLevel, new JST.NumericLiteral(env.DebugLevel))); body.Add(JST.Statement.Var(Constants.DebugId, new JST.BooleanLiteral(true))); body.Add(JST.Statement.Var(Constants.ModeId, new JST.StringLiteral(mode))); body.Add(JST.Statement.Var(Constants.SafeId, new JST.BooleanLiteral(env.SafeInterop))); foreach (var s in runtime.Body.Body) { body.Add(s); } } else { // Simplify var simpCtxt = new JST.SimplifierContext(true, env.DebugMode, new JST.NameSupply(Constants.Globals), null). InFreshStatements(); simpCtxt.Bind(Constants.DebugId, new JST.BooleanLiteral(false)); simpCtxt.Bind(Constants.ModeId, new JST.StringLiteral(mode)); simpCtxt.Bind(Constants.SafeId, new JST.BooleanLiteral(env.SafeInterop)); simpCtxt.Add(JST.Statement.Var(Constants.DebugLevel, new JST.NumericLiteral(env.DebugLevel))); runtime.Body.Simplify(simpCtxt, EvalTimes.Bottom, false); body = simpCtxt.Statements; } var opts = new OrdMap <JST.Identifier, JST.Expression>(); var mscorlibName = new JST.StringLiteral (CST.CSTWriter.WithAppend(env.Global, CST.WriterStyle.Uniform, env.Global.MsCorLibName.Append)); opts.Add(Constants.SetupMscorlib, mscorlibName); var target = default(string); switch (env.Target) { case Target.Browser: target = "browser"; break; case Target.CScript: target = "cscript"; break; default: throw new ArgumentOutOfRangeException(); } opts.Add(Constants.SetupTarget, new JST.StringLiteral(target)); var loadPaths = env.LoadPaths.Select <string, JST.Expression>(FixupPath).ToSeq(); if (loadPaths.Count == 0) { loadPaths.Add(new JST.StringLiteral("")); } opts.Add(Constants.SetupSearchPaths, new JST.ArrayLiteral(loadPaths)); if (env.DebugMode) { body.Add(new JST.CommentStatement("Setup runtime")); } var rootId = new JST.Identifier(env.Root); body.Add(JST.Statement.Var(rootId, new JST.ObjectLiteral())); body.Add(JST.Statement.Call(Constants.NewRuntime.ToE(), rootId.ToE(), new JST.ObjectLiteral(opts))); var program = new JST.Program(new JST.Statements(body)); var runtimeFileName = Path.Combine(env.OutputDirectory, Constants.RuntimeFileName); program.ToFile(runtimeFileName, env.PrettyPrint); env.Log(new GeneratedJavaScriptFile("runtime", runtimeFileName)); }