/// <summary> /// Compiles the provided C# and then translates it into JavaScript. /// On success, returns the JS. On failure, throws. /// </summary> public static CompiledSnippet Compile(string csharp, bool deleteTempFiles) { var result = new CompiledSnippet { OriginalSource = csharp }; int tempDirId = Interlocked.Increment(ref NextTempDirId); var tempPath = Path.Combine(Path.GetTempPath(), "JSIL.Try", tempDirId.ToString()); if (!Directory.Exists(tempPath)) { Directory.CreateDirectory(tempPath); } try { string resultPath, entryPointName, compilerOutput, resultFullName; long compileStarted = DateTime.UtcNow.Ticks; CompileAssembly( tempPath, csharp, out compilerOutput, out resultPath, out resultFullName, out entryPointName ); result.CompileElapsed = TimeSpan.FromTicks(DateTime.UtcNow.Ticks - compileStarted).TotalSeconds; if ((resultPath == null) || !File.Exists(resultPath)) { if (String.IsNullOrWhiteSpace(compilerOutput)) { throw new Exception("Compile failed with unknown error."); } else { throw new Exception(compilerOutput); } } var translatorConfiguration = new Configuration { ApplyDefaults = false, Assemblies = { Stubbed = { "mscorlib,", "System.*", "Microsoft.*" }, Ignored = { "Microsoft.VisualC,", "Accessibility,", "SMDiagnostics,", "System.EnterpriseServices,", "JSIL.Meta," } }, FrameworkVersion = 4.0, GenerateSkeletonsForStubbedAssemblies = false, GenerateContentManifest = false, IncludeDependencies = false, UseSymbols = true, UseThreads = false }; var translatorOutput = new StringBuilder(); var typeInfo = CachedTypeInfo.Value; // Don't use a cached type provider if this snippet contains a proxy. bool disableCaching = csharp.Contains("JSProxy"); using (var translator = new AssemblyTranslator( translatorConfiguration, // Reuse the cached type info provider, if one exists. disableCaching ? null : typeInfo, // Can't reuse a manifest meaningfully here. null, // Reuse the assembly cache so that mscorlib doesn't get loaded every time. AssemblyCache )) { translator.CouldNotDecompileMethod += (s, exception) => { lock (translatorOutput) translatorOutput.AppendFormat( "Could not decompile method '{0}': {1}{2}", s, exception.Message, Environment.NewLine ); }; translator.CouldNotResolveAssembly += (s, exception) => { lock (translatorOutput) translatorOutput.AppendFormat( "Could not resolve assembly '{0}': {1}{2}", s, exception.Message, Environment.NewLine ); }; translator.Warning += (s) => { lock (translatorOutput) translatorOutput.AppendLine(s); }; var translateStarted = DateTime.UtcNow.Ticks; var translationResult = translator.Translate(resultPath, true); AssemblyTranslator.GenerateManifest( translator.Manifest, Path.GetDirectoryName(resultPath), translationResult ); result.EntryPoint = String.Format( "{0}.{1}", translator.Manifest.GetPrivateToken(resultFullName).IDString, entryPointName ); result.Warnings = translatorOutput.ToString().Trim(); result.TranslateElapsed = TimeSpan.FromTicks(DateTime.UtcNow.Ticks - translateStarted).TotalSeconds; result.JavaScript = translationResult.WriteToString(); if (typeInfo != null) { // Remove the temporary assembly from the type info provider. typeInfo.Remove(translationResult.Assemblies.ToArray()); } else if (!disableCaching) { // We didn't have a type info provider to reuse, so store the translator's. CachedTypeInfo.Value = typeInfo = translator.GetTypeInfoProvider(); } /* * result.Warnings += String.Format( * "{1} assemblies loaded{0}", * Environment.NewLine, AppDomain.CurrentDomain.GetAssemblies().Length * ); */ /* * result.Warnings += String.Format( * "TypeInfo.Count = {1}{0}AssemblyCache.Count = {2}{0}", * Environment.NewLine, TypeInfo.Count, AssemblyCache.Count * ); */ } /* * * GC.Collect(); * * result.Warnings += String.Format( * "{1} byte(s) GC heap {0}", * Environment.NewLine, GC.GetTotalMemory(true) * ); */ return(result); } finally { try { if (deleteTempFiles) { Directory.Delete(tempPath, true); } } catch (Exception exc) { Console.WriteLine("Failed to empty temporary directory: {0}", exc.Message); } } }
/// <summary> /// Compiles the provided C# and then translates it into JavaScript. /// On success, returns the JS. On failure, throws. /// </summary> public static CompiledSnippet Compile(string csharp, bool deleteTempFiles) { var result = new CompiledSnippet { OriginalSource = csharp }; int tempDirId = Interlocked.Increment(ref NextTempDirId); var tempPath = Path.Combine(Path.GetTempPath(), "JSIL.Try", tempDirId.ToString()); if (!Directory.Exists(tempPath)) Directory.CreateDirectory(tempPath); try { string resultPath, entryPointName, compilerOutput, resultFullName; long compileStarted = DateTime.UtcNow.Ticks; CompileAssembly( tempPath, csharp, out compilerOutput, out resultPath, out resultFullName, out entryPointName ); result.CompileElapsed = TimeSpan.FromTicks(DateTime.UtcNow.Ticks - compileStarted).TotalSeconds; if ((resultPath == null) || !File.Exists(resultPath)) { if (String.IsNullOrWhiteSpace(compilerOutput)) throw new Exception("Compile failed with unknown error."); else throw new Exception(compilerOutput); } var translatorConfiguration = new Configuration { ApplyDefaults = false, Assemblies = { Stubbed = { "mscorlib,", "System.*", "Microsoft.*" }, Ignored = { "Microsoft.VisualC,", "Accessibility,", "SMDiagnostics,", "System.EnterpriseServices,", "JSIL.Meta," } }, FrameworkVersion = 4.0, GenerateSkeletonsForStubbedAssemblies = false, GenerateContentManifest = false, IncludeDependencies = false, UseSymbols = true, UseThreads = false }; var translatorOutput = new StringBuilder(); var typeInfo = CachedTypeInfo.Value; // Don't use a cached type provider if this snippet contains a proxy. bool disableCaching = csharp.Contains("JSProxy"); using (var translator = new AssemblyTranslator( translatorConfiguration, // Reuse the cached type info provider, if one exists. disableCaching ? null : typeInfo, // Can't reuse a manifest meaningfully here. null, // Reuse the assembly cache so that mscorlib doesn't get loaded every time. AssemblyCache )) { translator.CouldNotDecompileMethod += (s, exception) => { lock (translatorOutput) translatorOutput.AppendFormat( "Could not decompile method '{0}': {1}{2}", s, exception.Message, Environment.NewLine ); }; translator.CouldNotResolveAssembly += (s, exception) => { lock (translatorOutput) translatorOutput.AppendFormat( "Could not resolve assembly '{0}': {1}{2}", s, exception.Message, Environment.NewLine ); }; translator.Warning += (s) => { lock (translatorOutput) translatorOutput.AppendLine(s); }; var translateStarted = DateTime.UtcNow.Ticks; var translationResult = translator.Translate(resultPath, true); AssemblyTranslator.GenerateManifest( translator.Manifest, Path.GetDirectoryName(resultPath), translationResult ); result.EntryPoint = String.Format( "{0}.{1}", translator.Manifest.GetPrivateToken(resultFullName).IDString, entryPointName ); result.Warnings = translatorOutput.ToString().Trim(); result.TranslateElapsed = TimeSpan.FromTicks(DateTime.UtcNow.Ticks - translateStarted).TotalSeconds; result.JavaScript = translationResult.WriteToString(); if (typeInfo != null) { // Remove the temporary assembly from the type info provider. typeInfo.Remove(translationResult.Assemblies.ToArray()); } else if (!disableCaching) { // We didn't have a type info provider to reuse, so store the translator's. CachedTypeInfo.Value = typeInfo = translator.GetTypeInfoProvider(); } /* result.Warnings += String.Format( "{1} assemblies loaded{0}", Environment.NewLine, AppDomain.CurrentDomain.GetAssemblies().Length ); */ /* result.Warnings += String.Format( "TypeInfo.Count = {1}{0}AssemblyCache.Count = {2}{0}", Environment.NewLine, TypeInfo.Count, AssemblyCache.Count ); */ } /* GC.Collect(); result.Warnings += String.Format( "{1} byte(s) GC heap {0}", Environment.NewLine, GC.GetTotalMemory(true) ); */ return result; } finally { try { if (deleteTempFiles) Directory.Delete(tempPath, true); } catch (Exception exc) { Console.WriteLine("Failed to empty temporary directory: {0}", exc.Message); } } }