// // Copyright (c) Microsoft Corporation. All rights reserved. // #define NONONNULLTYPECHECK // required on Singularity, no affect on other Windows. namespace Bartok { using System; using System.IO; using System.Text; using System.Collections; using Bartok.Utility; using Bartok.Datatype; using Bartok.CfgUtil; using Bartok.Ir; using Bartok.Lir; using Bartok.Analysis; using Bartok.Opt.IrCleanup; using Bartok.Opt.Ir; using Bartok.Opt.Lir; using Bartok.Opt; using Bartok.Regalloc; using Bartok.Opt.Ssa; using Bartok.Backend; #if ON_SINGULARITY using Microsoft.Singularity; #endif // // Bartok.cs // // Main entry point for compiler // "public class Bartok {..}" breaks the namespace lookup of Bartok.* // Is this a bug? public class BartokClass { public static long CHECK_COUNT = 0; public static long CHECK_COUNT_LOWER = 0; public static int Main(String[] args) { #if ON_SINGULARITY // AppRuntime.EnableGCVerify = true; // DebugStub.WriteLine("Bartok: Enabled GC Verifier"); #endif Bartok.MSIL.MetaDataUtil.Configure(new MetaDataOutput()); try { ProcessCmdLine(args); if((fileNames.Count == 0) && (linkNames.Count == 0)) { CHECK_COUNT++; CHECK_COUNT_LOWER++; PrintUsage(); Util.Error("\nno files to process...aborting."); Util.Exit(-11); } if(StageControl.AtomicSupport) { StageControl.TryAllSupport = true; } Util.Message(NoiseLevel.PerPhase, "fileNames = " + new CollectionFormatter(fileNames)); Util.Message(NoiseLevel.PerPhase, "refFileNames = " + new CollectionFormatter(refFileNames)); Util.Message(NoiseLevel.PerPhase, "libDirNames = " + new CollectionFormatter(libDirNames)); Util.Message(NoiseLevel.PerPhase, "outputDirName = " + outputDirName); if (overrideNames.Count > 0) { Util.Message(NoiseLevel.PerPhase, "overrideNames = " + new CollectionFormatter(overrideNames)); } if (entryPoints.Count > 0) { Util.Message(NoiseLevel.PerPhase, "entryPoints = " + new CollectionFormatter(entryPoints)); } // Create helper data structures DateTime startTime = Util.startTime; bool fLoadDebugInfo = StageControl.SymbolicDebug; StageControl.BartokLinkPhase = false; if (StageControl.CompileOnly) { // separate compilation foreach (String fileName in fileNames) { String outputName = ComputeOutputName(fileName, outputDirName); ArrayList loadFileNames = new ArrayList(1); loadFileNames.Add(fileName); String shortName = GetShortName(fileName).ToLower(); // we need to compile mscorlib.dll together with // system.dll bool fDefineOverride = shortName.Equals("mscorlib.dll"); TypeData typeData = new TypeData(); CompileFile(typeData, loadFileNames, refFileNames, overrideNames, overrideDefNames, fDefineOverride, outputName, startTime, fLoadDebugInfo); } } else { // Create output root name. if (outputRootName == null) { outputRootName = (String) fileNames[0]; } // strip off extension, if there is one. int dotIndex = outputRootName.LastIndexOf('.'); if (dotIndex != -1) { String ext = outputRootName.Substring(dotIndex + 1); if (ext.Equals("dll") || ext.Equals("obj") || ext.Equals("exe")) { outputRootName = outputRootName.Substring(0, dotIndex); } } bool fDefineOverride = StageControl.WholeProgram; TypeData typeData = new TypeData(); String objFileName = CompileFile(typeData, fileNames, refFileNames, overrideNames, overrideDefNames, fDefineOverride, outputRootName, startTime, fLoadDebugInfo); linkNames.Add(objFileName); StageControl.BartokLinkPhase = true; #if DO_LINK BartokLinker bartokLinker = new BartokLinker(); typeData = StageControl.WholeProgram ? typeData : null; bartokLinker.Link(typeData, fileNames, linkNames, refFileNames, overrideNames, overrideDefNames, libDirNames, entryPoints, initializerSkips, outputRootName); #endif } } catch(AbortException) { // Abort code already dumped the stack Util.Exit(-1); } catch(Exception e) { Util.Error("Internal uncaught {0} exception", e); Util.Exit(-1); } Util.Message(NoiseLevel.PerPhase, "STATIC COUNT IS: " + CHECK_COUNT); Util.Message(NoiseLevel.PerPhase, "STATIC LOWER IS: " + CHECK_COUNT_LOWER); return 0; } private static String CompileFile(TypeData typeData, ArrayList fileNames, ArrayList refFileNames, ArrayList overrideNames, ArrayList overrideDefNames, bool fDefineOverride, String outputName, DateTime startTime, bool fLoadDebugInfo) { ConvertMsil2Ir(fileNames, refFileNames, overrideNames, overrideDefNames, fDefineOverride, startTime, fLoadDebugInfo, typeData); CHECK_COUNT++; CHECK_COUNT_LOWER++; #if SELF_PROFILING System.GC.Collect(); long memoryUsage = System.GC.GetTotalMemory(false); Util.Message("memory usage: " + memoryUsage); #endif if (entryPoints.Count > 0) { Util.Message(NoiseLevel.PerPhase, "entryPoints = " + new CollectionFormatter(entryPoints)); } if(!StageControl.CompileOnly && (entryPoints.Count == 0)) { Util.Abort("No entry points found"); } typeData.ComputeEntryMethod(entryPoints); Util.Assert(typeData.EntryPoints.Count == entryPoints.Count); // register all global analysis AnalysisRegistry analysisRegistry = RegisterAnalysis(typeData); // Create a series of phases that are each applied to the // whole program. Bartok.Ir.PhaseList phases = new Bartok.Ir.PhaseList("ir"); CHECK_COUNT--; CHECK_COUNT_LOWER--; AddPhases(phases, analysisRegistry, outputName, typeData); Util.Message(phases.ComponentPhases.ToString()); if (StageControl.DumpContainers) { phases.Add(new TypeDataPrettyPhase("After IR:")); } Bartok.Opt.IrCleanup.Statistics.Reset(typeData); BartokList phaseNames = phases.ComponentPhases; foreach(Object phaseObj in phaseNames) { if(!(phaseObj is string)) { Util.Warn("Not string: {0}X", phaseObj.ToString()); continue; } string phaseName = (string)phaseObj; if(phaseName.IndexOf(' ') != -1) { Util.Warn("Phase has a space in name: {0}", phaseName); } } foreach(string phaseName in StageControl.disabledPhaseNames) { if(phaseNames.Contains(phaseName)) { continue; } if(StageControl.disabledPhaseNamesFound.Contains(phaseName)) { continue; } Util.Abort("Couldn't find phase: " + phaseName); } phases.Go(typeData); Bartok.Opt.IrCleanup.Statistics.Summary(); #if SELF_PROFILING memoryUsage = System.GC.GetTotalMemory(false); Util.Message("memory usage: " + memoryUsage); #endif // backend phases: Util.Message("outputRootName = " + outputName); String objFileName = LirPhases.run(typeData, fileNames, outputName, StageControl.GenObjFile); System.GC.Collect(); Util.Message("End of Bartok: " + GC.GetTotalMemory(false)); return objFileName; } private static void ConvertMsil2Ir(ArrayList fileNames, ArrayList refFileNames, ArrayList overrideNames, ArrayList overrideDefNames, bool fDefineOverride, DateTime startTime, bool fLoadDebugInfo, TypeData typeData) { // Remove redundant fileNames // Remove refFileNames that are redundant with fileNames for(int i=0; i= NoiseLevel.PerPhase; Bartok.MSIL.MetaDataResolver libResolver = new Bartok.MSIL.MetaDataResolver(refFileNames, libDirNames, startTime, fLoadDebugInfo, fMsilMessages); Bartok.MSIL.MetaDataResolver overrideResolver; if (fDefineOverride) { // load code overrideResolver = new Bartok.MSIL.MetaDataResolver(overrideNames, startTime, fLoadDebugInfo, fTranslateTryAll, fTranslateAtomic, fMsilMessages); } else { // don't load code overrideResolver = new Bartok.MSIL.MetaDataResolver(overrideNames, libDirNames, startTime, fLoadDebugInfo, fMsilMessages); } Bartok.MSIL.MetaDataResolver overrideDefResolver = new Bartok.MSIL.MetaDataResolver(overrideDefNames, startTime, fLoadDebugInfo, fTranslateTryAll, fTranslateAtomic, fMsilMessages); Bartok.MSIL.MetaDataResolver loadResolver = new Bartok.MSIL.MetaDataResolver(fileNames, startTime, fLoadDebugInfo, fTranslateTryAll, fTranslateAtomic, fMsilMessages); Bartok.MSIL.MetaDataResolver[] resolvers = new Bartok.MSIL.MetaDataResolver[] { libResolver, overrideResolver, overrideDefResolver, loadResolver }; Bartok.MSIL.MetaDataResolver.ResolveCustomAttributes(resolvers); MetaDataParser parser = new MetaDataParser(entryPoints.Count == 0 ? entryPoints : null); Util.TimestampMessage(NoiseLevel.PerPhase, "translating from MSIL"); parser.Parse(loadResolver, overrideResolver, overrideDefResolver, libResolver, typeData, fDefineOverride, false); Util.TimestampMessage(NoiseLevel.PerPhase, "finished translating"); } private static AnalysisRegistry RegisterAnalysis(TypeData typeData) { AnalysisRegistry analysisRegistry = new AnalysisRegistry(typeData); analysisRegistry.RegisterAnalysis(VirtualCallAnalysis.makeFactory()); return analysisRegistry; } private static void AddPhases(Bartok.Ir.PhaseList phases, AnalysisRegistry analysisRegistry, String outputName, TypeData typeData) { if (StageControl.PrintContainers) { phases.Add(new TypeDataPrintPhase("After parse:")); } if (StageControl.DumpContainers) { phases.Add(new TypeDataPrettyPhase("After parse:")); } if (StageControl.SingSharpTemplateRemover) { phases.Add(new SingSharpTemplateRemover()); } if (StageControl.RuntimeMods) { phases.Add(new RuntimeMods()); } if (StageControl.IrMultiPropSimple) { phases.Add(new IrMultiPropSimple("System.GC")); } if (StageControl.IrDeadAssignmentSimple1) { phases.Add(new IrDeadAssignmentSimplePhase("System.GC")); } if (StageControl.IrTreeShake) { phases.Add(new IrTreeShake(typeData.EntryPoints, dynamicLoads, StageControl.WholeProgram, analysisRegistry)); } /* phases.Add (new DynamicCount ("VirtualCallsStart", new DynamicCount.OpcodeFilter (Operator.OpCodes.CallVirtual, Operator.OpCodes.InterfaceCall), DynamicCount.Granularity.PerSite)); */ /* phases.Add (new DynamicCount ("ASCstart", new DynamicCount.OpcodeFilter (Operator.OpCodes.CheckArrayStore, Operator.OpCodes.CheckVectorStore), DynamicCount.Granularity.PerSite)); */ if (StageControl.PtrAnalysis) { phases.Add(PtrTypeSimpleSystem.CreateAnalysis()); phases.Add(PtrTypeHierarchySystem.CreateAnalysis()); phases.Add(PtrTypeSetSystem.CreateAnalysis()); } // create wrapper that insert calls to leaveGCSafeState and // enterGCSafeState. phases.Add(new CreateEntryPointWrapper()); // trap ValueType.Equals and override it by compiler generated // routines. if (StageControl.IrOverrideValueTypeEquals) { phases.Add(new Convert.ValueTypeEquals()); } if (StageControl.LimitedReflection) { phases.Add(new Convert.OverrideVTableInit()); } if (StageControl.IrConvertSizeofPrimitive) { Convert.ToMir.Mask mask = Convert.ToMir.Mask.SizeofPrimitive; phases.Add(new Convert.ToMir(mask)); } /* SPOONS: region related phases: // A temporary pass that cleans up the scratch objects so that the // DemandAnalysis is not confused by the randomness that the tree // shaker leaves behind. phases.Add(new CleanScratch()); // Build a "Foo_layout" for each class "Foo"; other setup required // by DemandAnalysis. phases.Add(new LayoutBuilder()); // Perform first- and last-use analysis; add explicit region // variables and effects. phases.Add(new DemandAnalysis()); // Print the code phases.Add(new TypeDataPrettyPhase("After Demand:")); */ // Perform first- and last-use analaysis; add explicit region // variables and effects. // must happen after DemandAnalysis, but before any inlining / // rearranging basic blocks or calls. #if !VC if(StageControl.TryAllSupport) { phases.Add(new Bartok.Convert.PropagateLogging(analysisRegistry)); phases.Add(new TypeDataDummyPhase()); } #endif if (StageControl.IrScanCallEffects) { phases.Add(new IrScanCallEffects()); } if(StageControl.DumpInheritance) { phases.Add(new DumpInheritancePhase(StageControl.DumpInheritanceFile)); } #if PHX_TODO phases.Add(new TypeDataToPhoenix()); #endif phases.Add(new TypeInit(initializerSkips)); if (StageControl.InstrumentCalls) { phases.Add(new InstrumentCalls()); } if (StageControl.IrStoreChecks) { phases.Add(new IrStoreCheckElim()); } if (StageControl.BuildC2Mods && StageControl.UnmanagedStrings) { phases.Add(new IrUnmanagedStrings()); } phases.Add(IrCleanup.Create()); if (StageControl.BuildC2Mods && StageControl.IdentifyAsMethods) { phases.Add(new IrIdentifyAsMethods()); } if (StageControl.WholeProgram && StageControl.IrDeadAssignmentSimpleFormals && StageControl.IrTreeShake) { phases.Add(new IrDeadAssignmentSimpleFormalsPhase()); phases.Add(new IrTreeShake(typeData.EntryPoints, dynamicLoads, StageControl.WholeProgram, analysisRegistry)); } phases.Add(new Convert.IrInsertDelegate()); IrFieldAnalysis fieldAnalysis = null; if (StageControl.GCType == StageControl.ReferenceCountingCollector && StageControl.RCCollectorOptRCSubsumed && StageControl.RCCollectorOptRCSubsumedByROFields) { IrFieldAnalysis.FieldFilter filter = new IrFieldAnalysis.RCAproposFieldFilter(); fieldAnalysis = new IrFieldAnalysis(true, filter); phases.Add(fieldAnalysis); } if(StageControl.IrInlineConstructor) { phases.Add(new Convert.ToMir(Convert.ToMir.Mask.Constructor)); } // When only one class implements an interface, replace the interface // with the class. if (StageControl.IrInterfaceElim && StageControl.WholeProgram) { phases.Add(new InterfaceElim()); } if (StageControl.IrSimpleInliner) { phases.Add(new IrSimpleInliner(new IrInline(), false, false, false)); } else if (StageControl.IrAttributeInliner) { // inline methods that has [inline] attributes. phases.Add(new IrSimpleInliner(new IrInline(), false, false)); } if (StageControl.FailAfterInliner) { phases.Add(new FailPhase()); } if (StageControl.IrMultiPropSimple) { phases.Add(new IrMultiPropSimple()); } if (StageControl.IrSuppressExnEdges) { phases.Add(new IrSuppressExnEdges()); } if (StageControl.IrLoadStoreOpt) { phases.Add(new IrLoadStoreOpt(analysisRegistry)); } if (StageControl.DevirtualizeCall) { phases.Add(new IrDevirtualizeCall(analysisRegistry)); } if (StageControl.IrSimpleInliner && StageControl.IrInlinerDoIncreaseSize) { phases.Add(new IrSimpleInliner(new IrInline(), true, false, false)); } if (StageControl.LazyTypeInits) { phases.Add(new TypeInit(initializerSkips, true)); } // Eliminate unnecessary instanceOf/check casts. Only makes // 2 passes by punting back edges. if (StageControl.IrTypeTestElimPunt) { phases.Add(new TypeTestElimPunt()); } // Eliminate unnecessary instanceOf/check casts - full iterative // analysis. More expensive than the above analysis, but yields // little improvement in practice. if (StageControl.IrTypeTestElim) { phases.Add(new TypeTestElim()); } // Deletes all CheckCasts and instanceOf IDisposable for sake of // experimentation. Normally not enabled, as it is unsafe. if (StageControl.IrDeleteCheckCasts) { phases.Add(new DeleteCheckCast()); } if (StageControl.IrConvertOpt) { phases.Add(new IrConvertOpt()); phases.Add(new IrDeadAssignmentSimplePhase()); phases.Add(new IrReverseCopyProp()); } // Just do thread analysis once. IrLockedFields locks = null; if (StageControl.ExtendThreadFieldsABCD || StageControl.SsaNullCheckGlobalThreaded) { if (StageControl.IrTreeShake) { phases.Add(new IrTreeShake(typeData.EntryPoints, dynamicLoads, StageControl.WholeProgram, analysisRegistry)); } if(StageControl.OptimisticLocking) { locks = new ClassIrLockedFields(analysisRegistry); } else { locks = new IrLockedFields(analysisRegistry); } phases.Add(locks); } // Array bounds check elimination if (StageControl.ABCD) { phases.Add(new ABCD(analysisRegistry, locks)); } if (StageControl.IrConvertArrayBounds) { Convert.ToMir.Mask mask = Convert.ToMir.Mask.CheckVectorBounds; phases.Add(new Convert.ToMir(mask)); } if (StageControl.IrConvertInferface) { Convert.ToMir.Mask mask = Convert.ToMir.Mask.InterfaceCall; phases.Add(new Convert.ToMir(mask)); } if (StageControl.IrConvertSimpleArrayAccess) { Convert.ToMir.Mask mask = Convert.ToMir.Mask.SimpleArrayAccess; phases.Add(new Convert.ToMir(mask)); } if (StageControl.IrCloneLoopHeader) { phases.Add(new IrCloneLoopHeader()); phases.Add(new IrJumpElim()); phases.Add(new IrMultiPropSimple()); } if (StageControl.SsaOpts) { if (StageControl.SsaNullCheckGlobalThreaded) { phases.Add(SSAPhase.Create(analysisRegistry, locks)); } else { phases.Add(SSAPhase.Create()); } } if(locks != null) { locks = null; } // IrInsertStructCopy phase insert a StructCopy() method // to each struct type, and lower struct Id operators // to a call to StructCopy() method. phases.Add(new Convert.IrInsertStructCopy()); #if !VC if(StageControl.TryAllSupport) { phases.Add(new IrInsertLogging()); } if(StageControl.TryAllSupport && StageControl.AtomicSupportUpdateEnlistOptFlow) { // without the IrLoadStoreOpt here, EnlistIndirects // generated by [Store]StructFields can't be moved. phases.Add(new IrLoadStoreOpt(analysisRegistry)); phases.Add(new IrInsertUpdateEnlistments()); // otherwise CSE misses things that it should be eliminating phases.Add(new IrMultiPropSimple()); } if (StageControl.TryAllSupport && StageControl.IrKeepManager) { phases.Add(new IrKeepManager(analysisRegistry)); } #endif if(StageControl.IrStructVectorOperations) { phases.Add(new IrStruct(true)); } if (StageControl.IrLoadStoreOpt) { phases.Add(new IrLoadStoreOpt(analysisRegistry)); } #if !VC if (StageControl.TryAllSupport && StageControl.AtomicSupportUpdateEnlistOpt) { phases.Add(new IrSimpleAvoidUpgrade()); } #endif if (StageControl.IrConvertComplexArrayAccess) { Convert.ToMir.Mask mask = Convert.ToMir.Mask.ComplexArrayAccess; phases.Add(new Convert.ToMir(mask)); } if (StageControl.IrConvertExpandedArrayAccess) { Convert.ToMir.Mask mask = Convert.ToMir.Mask.ExpandedArrayAccess; phases.Add(new Convert.ToMir(mask)); } if (StageControl.ArraySupportOptimizePass && StageControl.SsaOpts) { phases.Add(SSAPhase.Create()); } #if !VC if (StageControl.TryAllSupport && StageControl.TryAllSupportOptimizePass && StageControl.SsaOpts) { phases.Add(SSAPhase.Create()); } #endif if (StageControl.IrInitStaticField) { phases.Add(new IrInitStaticField()); } if (StageControl.LazyTypeInits && StageControl.TypeInitRemoveEmptyCctors) { phases.Add(new TypeInit(initializerSkips, true)); } if (StageControl.GCType == StageControl.ReferenceCountingCollector) { phases.Add(new IrStructRCUpdate()); } if (StageControl.GCType == StageControl.DeferredReferenceCountingCollector) { phases.Add(new IrStructDRCUpdate()); } if (StageControl.IrTreeShake && StageControl.IrTreeShakeLate) { phases.Add(new IrTreeShake(typeData.EntryPoints, dynamicLoads, StageControl.WholeProgram, analysisRegistry)); } if (StageControl.TypedReference) { phases.Add(new Convert.ToMir(Convert.ToMir.Mask.Vararg1)); // All of vararg1 must finish before vararg2, so we wrap vararg2 // in a typedata phase to enforce that. phases.Add(new TypeDataMethodPhase (new Convert.ToMir(Convert.ToMir.Mask.Vararg2))); } /* // We do not know where all of the calls will be because lowering can // introduce calls. We make a best guess here. If we moved all // call-generating lowering to HIR (via ToMir or equivalent), then // this could be easily done. We are currently missing calls for the // following: // - pinvoke, stubs, etc // - some arithmetic conversions // - casts - can't add because not all are calls // - RC, tryall, atomic // - others? phases.Add (new DynamicCount ("Calls", new DynamicCount.OpcodeFilter (Operator.OpCodes.Call, Operator.OpCodes.CallIndirect, Operator.OpCodes.CallVirtual, Operator.OpCodes.InterfaceCall, Operator.OpCodes.MonitorEnter, Operator.OpCodes.MonitorExit, Operator.OpCodes.IndirectToData, Operator.OpCodes.CustomGetSize, Operator.OpCodes.CheckVectorStore, Operator.OpCodes.CheckVectorElementAddress, Operator.OpCodes.InitVector, Operator.OpCodes.CheckArrayStore, Operator.OpCodes.CheckArrayElementAddress, Operator.OpCodes.InitArray, Operator.OpCodes.InitType, Operator.OpCodes.GetITable, Operator.OpCodes.NewObject, Operator.OpCodes.NewVector, Operator.OpCodes.NewArray), DynamicCount.Granularity.Global)); phases.Add(new TypeDataDummyPhase()); phases.Add (new DynamicCount ("VirtualCallsEnd", new DynamicCount.OpcodeFilter (Operator.OpCodes.CallVirtual, Operator.OpCodes.InterfaceCall), DynamicCount.Granularity.PerSite)); phases.Add (new DynamicCount ("ASCend", new DynamicCount.OpcodeFilter (Operator.OpCodes.CheckArrayStore, Operator.OpCodes.CheckVectorStore), DynamicCount.Granularity.PerSite)); phases.Add(new TypeDataDummyPhase()); phases.Add (new DynamicCount ("WB", new DynamicCount.OpcodeFilter (Operator.OpCodes.LocWriteBarrier), DynamicCount.Granularity.Global)); phases.Add(new TypeDataDummyPhase()); */ if (StageControl.WholeProgram && StageControl.OptRuntimeData) { phases.Add(new RuntimeData()); } if (StageControl.IrConvertArrayOpt) { phases.Add(new IrConvertArrayOpt()); } // insert write barrier after chooserep so we know the size of // of objects. This is needed because we try to remove write // barrier when we store to the young generation, however, // big objects are in the old generation even though it is // newly created. Therefore, we need to know object size to // know if it is a big object. if (StageControl.InsertWriteBarrier) { phases.Add(new IrWriteBarrier()); phases.Add(new Convert.ToMir (Convert.ToMir.Mask.ConvertWriteBarrier)); } // convert type tests and sizeof effect to Mir Convert.ToMir.Mask typeMask = Convert.ToMir.Mask.CheckCast | Convert.ToMir.Mask.Sizeof; if (!(StageControl.GCType == StageControl.ReferenceCountingCollector || StageControl.GCType == StageControl.DeferredReferenceCountingCollector)) { typeMask |= Convert.ToMir.Mask.GetCurrentThread; } if (StageControl.TypedReference) { typeMask |= Convert.ToMir.Mask.TypedRef; } phases.Add(new Convert.ToMir(typeMask)); if (StageControl.IrSimpleInliner) { phases.Add(new IrSimpleInliner(new IrInline(), false, true, true, 0, 0, 0)); } if(StageControl.TypeInitElim) { phases.Add(new IrTypeInitElim(analysisRegistry)); } if (StageControl.IrRemoveDoubleCmp) { phases.Add(new IrCmpElim()); } if (StageControl.IrArrayBaseLength) { phases.Add(new IrArrayBaseLength()); phases.Add(new IrDeadAssignmentSimplePhase()); } if (StageControl.IrInitTypeInliner && StageControl.LazyTypeInits) { phases.Add(new IrInitTypeInliner(typeData, new IrInline())); } if (StageControl.GCType == StageControl.ReferenceCountingCollector) { if (StageControl.RCCollectorShowStatistics) { String message = "Before RC Update Injection"; phases.Add(new IrBBStats(message)); } phases.Add(new IrRCUpdate()); if (StageControl.RCCollectorShowStatistics) { String message = "After RC Update Injection"; phases.Add(new IrBBStats(message)); } if (StageControl.RCCollectorOptImmortals) { phases.Add(new IrImmortalObjectRCUpdates()); } if (StageControl.RCCollectorOptRCSubsumed) { IrSimpleThreadEscape threadLocalObjects = null; if (StageControl.RCCollectorOptThreadLocalAnalysis) { IrLockedFields threadSafeFields = null; if (StageControl.WholeProgram && StageControl. RCCollectorOptRCSubsumedByTSFields) { threadSafeFields = new IrLockedFields(analysisRegistry); phases.Add(threadSafeFields); } threadLocalObjects = new IrSimpleThreadEscape(analysisRegistry, threadSafeFields); phases.Add(threadLocalObjects); } IrRCSubsumedRCUpdates rcSubsumption = new IrRCSubsumedRCUpdates(analysisRegistry, fieldAnalysis, threadLocalObjects); phases.Add(rcSubsumption); } if (StageControl.RCCollectorOptCoalescingUpdates) { phases.Add(new IrBBLocalCoalesceRCUpdates()); } if (StageControl. RCCollectorOptStaticAcyclicRefTypeUpdates) { phases.Add(new IrAcyclicRefTypeRCUpdates()); } if (StageControl.RCCollectorOptNonNullRCUpdates) { phases.Add(SSAPhase.NullCheckAnalysis()); } if (StageControl.RCCollectorShowStatistics) { String message = "After RC Optimizations"; phases.Add(new IrBBStats(message)); } Convert.ToMir.Mask mask = Convert.ToMir.Mask.RCUpdate | Convert.ToMir.Mask.GetCurrentThread; phases.Add(new Convert.ToMir(mask)); if (StageControl.RCCollectorOptInlineRCUpdates && StageControl.IrSimpleInliner) { phases.Add(new IrSimpleInliner(new IrInline(), true, false, true)); } phases.Add(new TypeDataDummyPhase()); } if (StageControl.GCType == StageControl.DeferredReferenceCountingCollector) { if (StageControl.RCCollectorShowStatistics) { String message = "Before DRC Update Injection"; phases.Add(new IrBBStats(message)); } phases.Add(new IrDRCUpdate()); if (StageControl.RCCollectorShowStatistics) { String message = "After DRC Update Injection"; phases.Add(new IrBBStats(message)); } if (StageControl.RCCollectorOptImmortals) { phases.Add(new IrImmortalObjectRCUpdates()); } if (StageControl.RCCollectorOptCoalescingUpdates) { phases.Add(new IrBBLocalCoalesceRCUpdates()); } if (StageControl. RCCollectorOptStaticAcyclicRefTypeUpdates) { phases.Add(new IrAcyclicRefTypeRCUpdates()); } if (StageControl.RCCollectorOptNonNullRCUpdates) { phases.Add(SSAPhase.NullCheckAnalysis()); } if (StageControl.RCCollectorShowStatistics) { String message = "After DRC Optimizations"; phases.Add(new IrBBStats(message)); } Convert.ToMir.Mask mask = Convert.ToMir.Mask.RCUpdate | Convert.ToMir.Mask.GetCurrentThread; phases.Add(new Convert.ToMir(mask)); if (StageControl.RCCollectorOptInlineRCUpdates && StageControl.IrSimpleInliner) { phases.Add(new IrSimpleInliner(new IrInline(), true, false, true)); } phases.Add(new TypeDataDummyPhase()); } #if !VC if(StageControl.TryAllSupport && StageControl.TryAllDecomposeOpt) { phases.Add(new IrDecomposeTransMemChecks(analysisRegistry)); // IrDecomposeTransMemChecks emits GetCurrentThread ops phases.Add(new IrLoadStoreOpt(analysisRegistry)); Convert.ToMir.Mask mask = Convert.ToMir.Mask.GetCurrentThread; phases.Add(new Convert.ToMir(mask)); } if (StageControl.TryAllSupport && StageControl.IrConvertTryAll) { Convert.ToMir.Mask mask = Convert.ToMir.Mask.TryAll; phases.Add(new Convert.ToMir(mask)); if (StageControl.IrSimpleInliner) { phases.Add(new IrSimpleInliner(new IrInline(), true, false)); } } #endif // The inliners may inline some of the methods that handle special // MSIL opcodes, adding in instructions like Id that we // don't expect to see this late in the lowering. Add one more // scan of the code to remove them. phases.Add(new Convert.IrInsertStructCopy()); if (StageControl.IrTreeShake && StageControl.IrTreeShakeLate) { phases.Add(new IrTreeShake(typeData.EntryPoints, dynamicLoads, StageControl.WholeProgram, analysisRegistry)); } if (StageControl.PtrAnalysis) { phases.Add(PtrTypeSimpleSystem.CreateAnalysis()); phases.Add(PtrTypeHierarchySystem.CreateAnalysis()); phases.Add(PtrTypeSetSystem.CreateAnalysis()); } if (StageControl.PrintContainers) { phases.Add(new TypeDataPrintPhase("end of HIR:")); } } public static ArrayList fileNames; public static ArrayList refFileNames; public static ArrayList libDirNames; private static ArrayList outputDirNames; public static String outputDirName; public static ArrayList overrideNames; public static ArrayList overrideDefNames; public static String outputRootName; public static ArrayList entryPoints; public static ArrayList linkNames; private static ArrayList initializerSkips; private static ArrayList dynamicLoads; private static bool alreadyPrintedUsage = false; private static String StripName(String fileName) { // strip off extension, if there is one. int dotIndex = fileName.LastIndexOf('.'); if (dotIndex != -1) { String ext = fileName.Substring(dotIndex + 1); if (ext.Equals("dll") || ext.Equals("obj") || ext.Equals("exe")) { fileName = fileName.Substring(0, dotIndex); } } return fileName; } private static String GetShortName(String fileName) { int charindex = Math.Max(fileName.LastIndexOf('/'), fileName.LastIndexOf('\\')); String shortName = (charindex >= 0) ? fileName.Substring(charindex + 1) : fileName; return shortName; } private static String GetDirName(String fileName) { int charindex = Math.Max(fileName.LastIndexOf('/'), fileName.LastIndexOf('\\')); String dirName = (charindex >= 0) ? fileName.Substring(0, charindex + 1) : ""; return dirName; } private static String ComputeOutputName(String inputFileName, String outputDirName) { String fileName = Path.GetFileNameWithoutExtension(inputFileName); String outputName = outputDirName + '\\' + fileName; return outputName; } private static void ProcessCmdLine(String[] args) { fileNames = new ArrayList(); refFileNames = new ArrayList(); libDirNames = new ArrayList(); overrideNames = new ArrayList(); overrideDefNames = new ArrayList(); outputDirNames = new ArrayList(); entryPoints = new ArrayList(); initializerSkips = new ArrayList(); linkNames = new ArrayList(); dynamicLoads = new ArrayList(); int index = 0; #if ON_SINGULARITY index = 1; #endif while (index < args.Length) { String argument = args[index]; if ((argument[0] == '-') || (argument[0] == '/')) { String option = argument.Substring(1); ProcessOption(argument, option, args, ref index); } else { index++; fileNames.Add(argument); } } switch (outputDirNames.Count) { case 0: { outputDirName = ".\\debug"; break; } case 1: { outputDirName = (String)outputDirNames[0]; break; } default: { Util.Error("Error: specified multiple output directories {0}", new CollectionFormatter(outputDirNames)); break; } } if((StageControl.GCType == StageControl.ReferenceCountingCollector) && StageControl.StructInheritance) { Util.Abort("Error: RC Collector code has not been updated to " + "handle struct inheritance"); } if((StageControl.GCType == StageControl.DeferredReferenceCountingCollector) && StageControl.StructInheritance) { Util.Abort("Error: Deferred RC Collector code has not been updated to " + "handle struct inheritance"); } } private static void ProcessOption(String argument, String option, String[] args, ref int index) { String loweredOption = option.ToLower(); String optionValue; if (IsOption(args, option, loweredOption, "entry:", ref index, out optionValue)) { AddSemicolonDelimitedNames(entryPoints, optionValue); } else if (IsOption(args, option, loweredOption, "reference:", ref index, out optionValue) || IsOption(args, option, loweredOption, "r:", ref index, out optionValue)) { AddSemicolonDelimitedNames(refFileNames, optionValue); } else if (IsOption(args, option, loweredOption, "bartoklink:", ref index, out optionValue)) { AddSemicolonDelimitedNames(linkNames, optionValue); } else if (IsOption(args, option, loweredOption, "override:", ref index, out optionValue)) { AddSemicolonDelimitedNames(overrideNames, optionValue); } else if (IsOption(args, option, loweredOption, "overridedef:", ref index, out optionValue)) { AddSemicolonDelimitedNames(overrideDefNames, optionValue); } else if (IsOption(args, option, loweredOption, "lib:", ref index, out optionValue)) { AddSemicolonDelimitedNames(libDirNames, optionValue); } else if (IsOption(args, option, loweredOption, "out:", ref index, out optionValue)) { outputRootName = optionValue; } else if (IsOption(args, option, loweredOption, "outdir:", ref index, out optionValue)) { AddSemicolonDelimitedNames(outputDirNames, optionValue); } else if (IsOption(args, option, loweredOption, "skip:", ref index, out optionValue)) { AddSemicolonDelimitedNames(initializerSkips, optionValue); } else if (IsOption(args, option, loweredOption, "substitute:", ref index, out optionValue)) { StageControl.substituteString = optionValue; } else if (IsOption(args, option, loweredOption, "disable:", ref index, out optionValue)) { StageControl.disabledPhaseNames.Add(optionValue); } else if (IsOption(args, option, loweredOption, "dynamicload:", ref index, out optionValue)) { AddSemicolonDelimitedNames(dynamicLoads, optionValue); } else if (IsOption(args, option, loweredOption, "features:", ref index, out optionValue)) { StageControl.mixinConditionals = StageControl.mixinConditionals + "," + optionValue; } else if (IsOption(args, option, loweredOption, "noisymethod:", ref index, out optionValue)) { StageControl.noisyMethodNames.Add(optionValue); //Util.Message("noisyMethodNames=" // + StageControl.noisyMethodNames); } else if (IsOption(args, option, loweredOption, "debugmethod:", ref index, out optionValue)) { StageControl.debugMethodNames.Add(optionValue); StageControl.noisyMethodNames.Add(optionValue); //Util.Message("debugMethodNames=" // + StageControl.debugMethodNames); } else if (IsOption(args, option, loweredOption, "verbosity:", ref index, out optionValue)) { Verbosity.FromString(optionValue); } else if (IsOption(args, option, loweredOption, "marksweepgc", ref index, out optionValue)) { StageControl.GCType = StageControl.MarkSweepCollector; StageControl.GCLargeObjectSize = 2040; StageControl.InlineSegregatedFreeList = true; StageControl.InsertWriteBarrier = false; } else if (IsOption(args, option, loweredOption, "semispacegc", ref index, out optionValue)) { StageControl.GCType = StageControl.SemispaceCollector; StageControl.InsertWriteBarrier = true; } else if (IsOption(args, option, loweredOption, "slidinggc", ref index, out optionValue)) { StageControl.GCType = StageControl.SlidingCollector; StageControl.InsertWriteBarrier = true; } else if (IsOption(args, option, loweredOption, "adaptivecopyinggc", ref index, out optionValue)) { StageControl.GCType = StageControl.AdaptiveCopyingCollector; StageControl.InsertWriteBarrier = true; } else if (IsOption(args, option, loweredOption, "referencecountinggc", ref index, out optionValue)) { StageControl.GCType = StageControl.ReferenceCountingCollector; StageControl.InsertWriteBarrier = false; StageControl.GCInlineAllocations = false; StageControl.mixinConditionals = StageControl.mixinConditionals + ",ReferenceCountingGC"; if (StageControl.RCCollectorVerifyRefCounts) { StageControl.UseVTableBits = true; StageControl.mixinConditionals = StageControl.mixinConditionals + ",ReferenceCountingGCVerification"; } } else if (IsOption (args, option, loweredOption, "deferredreferencecountinggc", ref index, out optionValue)) { StageControl.GCType = StageControl.DeferredReferenceCountingCollector; StageControl.InsertWriteBarrier = false; StageControl.GCInlineAllocations = false; StageControl.mixinConditionals = StageControl.mixinConditionals + ",DeferredReferenceCountingGC"; if (StageControl.RCCollectorVerifyRefCounts) { StageControl.UseVTableBits = true; StageControl.mixinConditionals = StageControl.mixinConditionals + ",DeferredReferenceCountingGCVerification"; } } else if (IsOption(args, option, loweredOption, "concurrentmsgc", ref index, out optionValue)) { StageControl.GCType = StageControl.ConcurrentMSCollector; StageControl.GCLargeObjectSize = 2040; StageControl.Wb = StageControl.WbCMS; StageControl.GCInlineAllocations = false; StageControl.InlineSegregatedFreeList = true; StageControl.PreWriteBarrier = true; StageControl.InsertWriteBarrier = true; StageControl.GCInlineWriteBarrier = false; StageControl.GCWriteBarrierTracksStaticFields = true; StageControl.mixinConditionals = StageControl.mixinConditionals + ",ConcurrentMSGC"; } else if (IsOption(args, option, loweredOption, "nullgc", ref index, out optionValue)) { StageControl.GCType = StageControl.NullCollector; StageControl.InsertWriteBarrier = false; } else if (IsOption(args, option, loweredOption, "atomicrcgc", ref index, out optionValue)) { StageControl.GCType = StageControl.AtomicRCCollector; StageControl.GCLargeObjectSize = 2040; StageControl.Wb = StageControl.WbARC; StageControl.GCInlineAllocations = false; StageControl.InlineSegregatedFreeList = true; StageControl.InsertWriteBarrier = true; StageControl.GCInlineWriteBarrier = false; StageControl.GCWriteBarrierTracksStaticFields = true; } else if (IsOption(args, option, loweredOption, "minopt", ref index, out optionValue)) { StageControl.SsaOpts = false; StageControl.IrInterfaceElim = false; StageControl.DevirtualizeCall = false; StageControl.IrTypeTestElimPunt = false; StageControl.IrTypeTestElim = false; StageControl.IrSimpleInliner = false; // IR clean up optimizations StageControl.IrDeadAssignmentSimple2 = false; StageControl.IrCleanupStructOperations = false; StageControl.IrShortCircuitBBlocks = false; StageControl.IrTreeShakeLate = false; StageControl.IrArrayLoadStoreOpt = false; StageControl.IrConvertSimpleArrayAccess = false; // from the backend StageControl.RegAllocCoalesce = false; StageControl.RegAllocSpill = StageControl.SpillOptimizeSinglePass; StageControl.OptLirCompactify = false; StageControl.OptLirGlobalConstantProp = false; StageControl.OptLirLocalConstantProp = true; StageControl.OptLirImproveCC = false; StageControl.OptLirPeephole = false; StageControl.OptLirReverseCSE = false; StageControl.OptLirGlobalCopyProp = false; StageControl.OptLirLocalCopyProp = true; StageControl.LayoutLoopHeaderLast = false; if (StageControl.SymbolicDebug) { StageControl.OptimizeLocals = false; } } else if (IsOption(args, option, loweredOption, "nohiropt", ref index, out optionValue)) { StageControl.ABCD = false; StageControl.DevirtualizeCall = false; StageControl.IdentifyAsMethods = false; StageControl.IrAttributeInliner = false; StageControl.IrBBLocalCopyProp = false; StageControl.IrCleanup = false; StageControl.IrCleanupStructOperations = false; StageControl.IrCloneLoopHeader = false; StageControl.IrConvertOpt = false; StageControl.IrDeadAssignmentSimple1 = false; StageControl.IrDeadAssignmentSimple2 = false; StageControl.IrInitStaticField = false; StageControl.IrInterfaceElim = false; StageControl.IrJumpElim = false; StageControl.IrLoadStoreOpt = false; StageControl.IrMultiPropSimple = false; StageControl.IrPeepholeNull = false; StageControl.IrRemoveDoubleCmp = false; StageControl.IrReverseCopyProp = false; StageControl.IrShortCircuitBBlocks = false; StageControl.IrSimpleInliner = false; StageControl.IrStoreChecks = false; StageControl.IrTreeShakeLate = false; StageControl.IrTypeTestElimPunt = false; StageControl.SsaArraySimple = false; StageControl.SsaDeadCode = false; StageControl.SsaLoopInv = false; StageControl.SsaNullCheck = false; StageControl.SsaOpts = false; StageControl.TypeInitRemoveEmptyCctors = false; StageControl.UnmanagedStrings = false; } else if (IsOption(args, option, loweredOption, "singularity", ref index, out optionValue)) { StageControl.SingSharpTemplateRemover = true; StageControl.DisablePInvoke = true; StageControl.StrictEcma = true; StageControl.CustomAllocatorTypes = true; StageControl.SurrogateBoxing = true; StageControl.StructInheritance = true; StageControl.IrTreeShakeCreatePointedToStructs = true; StageControl.IrTreeShakeLate = false; // not tested StageControl.TypeInitRemoveEmptyCctors = false; // not tested StageControl.CheckNoHeapAllocation = true; } else if (IsOption(args, option, loweredOption, "verbosehelp", ref index, out optionValue)) { PrintUsage(); StageControl.PrintUsage(); } else if (IsOption(args, option, loweredOption, "verbosehelpalpha", ref index, out optionValue)) { PrintUsage(); StageControl.PrintUsageAlpha(); } else if (IsOption(args, option, loweredOption, "x86", ref index, out optionValue)) { StageControl.TargetArch = StageControl.X86; StageControl.Target64Bit = false; } else if (IsOption(args, option, loweredOption, "x64", ref index, out optionValue)) { StageControl.TargetArch = StageControl.X64; StageControl.Target64Bit = true; } else if (IsOption(args, option, loweredOption, "help", ref index, out optionValue) || IsOption(args, option, loweredOption, "?", ref index, out optionValue)) { PrintUsage(); } else if (IsOption (args, option, loweredOption, "centralpt", ref index, out optionValue)) { StageControl.PTType = StageControl.CentralPT; } else if (IsOption (args, option, loweredOption, "centralpthimem", ref index, out optionValue)) { StageControl.PTType = StageControl.CentralPTHimem; } else if (IsOption (args, option, loweredOption, "flatdistributedpt", ref index, out optionValue)) { StageControl.PTType = StageControl.FlatDistributedPT; } else if (IsOption (args, option, loweredOption, "flatdistributedtestpt", ref index, out optionValue)) { StageControl.PTType = StageControl.FlatDistributedPTTest; } else if (StageControl.SetOptionFromCommandLine(loweredOption)) { index++; } else if (loweredOption.StartsWith("stagecontrol")) { Util.AbortUserCE("/stagecontrol no longer supported; " + "use the option directly"); } else { Util.AbortUserCE("Unknown option: " + option); } } private static bool IsOption(String[] args, String option, String loweredOption, String possibleOptionName, ref int index, out String optionValue) { if(possibleOptionName.EndsWith(":")) { if(loweredOption.StartsWith(possibleOptionName)) { index++; if(option.Length == possibleOptionName.Length) { // case: "/option: value" optionValue = args[index++]; } else { // case: "/option:value" optionValue = option.Substring(possibleOptionName.Length); } return true; } } else { if(loweredOption == possibleOptionName) { index++; optionValue = null; return true; } } optionValue = null; return false; } private static void AddSemicolonDelimitedNames(ArrayList names, String argument) { int index = 0; StringBuilder buf = new StringBuilder(); while (index < argument.Length) { if (argument[index] != ';') { buf.Append(argument[index]); index++; } else { if (buf.Length > 0) { names.Add(buf.ToString()); buf = new StringBuilder(); } index++; } } names.Add(buf.ToString()); } public static void PrintUsage() { if (alreadyPrintedUsage) { return; } alreadyPrintedUsage = true; Util.Message( @"Usage: bartok [options] files Bartok main options (case insensitive): /entry: ;;... specify entry points /reference: ;;... reference metadata from assembly files /r: ;;... short form of /reference: /bartoklink: ;;... reference precompiled object files /override: ;;... files overriding /r: metadata /lib: ;;... additional dirs to search for references /out: output file name /outdir: dir for output .exe, asm, obj, etc. (defaults to .\\debug) /skip: ;;... specify type initializers to disable if building static ordering /substitute:=, rename TypeRefs before performing lookup =,... /disable: disable a phase /dynamicload: make type available for dynamic loading /features: << TODO >> /noisymethod: enable noisy output for meth /debugmethod: enable debug+noisy output for meth /verbosity: set output level {Silence,PerPhase, PerClass,PerMethod,PerBlock, PerInstruction} (defaults to PerPhase) /marksweepgc compile for mark-sweep collector /semispacegc compile for semispace collector /slidinggc compile for sliding collector /adaptivecopyinggc compile for semispace-sliding hybrid collector /referencecountinggc compile for reference counting collector /deferredreferencecountinggc compile for deferred reference counting collector /concurrentmsgc compile for concurrent mark-sweep collector /nullgc compile for no collector /minopt disable most optimizations /nohiropt disable all HIR optimizations /singularity set default Singularity options /verbosehelp help message including stage control options by category /verbosehelpalpha help message including stage control options in alphabetical order /help or /? help message"); } } internal class MetaDataOutput : Bartok.MSIL.IMetaDataOutput { public TextWriter Log { get { return Util.Log; } } public TextWriter ErrorOut { get { return Util.ErrorOut; } } public TextWriter WarnOut { get { return Util.WarnOut; } } public void Error(string msg) { Util.Error(msg); } public void Error(string format, params Object[] objs) { Util.Error(format, objs); } public void ErrorDetail(string msg) { Util.ErrorDetail(msg); } public void Warn(string msg) { Util.Warn(msg); } public void Warn(string format, params Object[] objs) { Util.Warn(format, objs); } public void WarnDetail(string msg) { Util.WarnDetail(msg); } public void Message(string msg) { Util.Message(msg); } } }