File: BuildProvidersCompiler.cs

package info (click to toggle)
mono 6.14.1%2Bds2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,282,732 kB
  • sloc: cs: 11,182,461; xml: 2,850,281; ansic: 699,123; cpp: 122,919; perl: 58,604; javascript: 30,841; asm: 21,845; makefile: 19,602; sh: 10,973; python: 4,772; pascal: 925; sql: 859; sed: 16; php: 1
file content (823 lines) | stat: -rw-r--r-- 33,354 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
//------------------------------------------------------------------------------
// <copyright file="BuildProvidersCompiler.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//------------------------------------------------------------------------------



namespace System.Web.Compilation {

using System;
using System.IO;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Specialized;
using System.Reflection;
using System.Globalization;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Configuration;
using System.Linq;
using System.Runtime.ExceptionServices;
using System.Threading.Tasks;
using System.Web.Hosting;
using System.Web.Util;
using System.Web.Caching;
using System.Web.UI;
using System.Web.Configuration;

internal class BuildProvidersCompiler {
    private ICollection _buildProviders;
    private VirtualPath _configPath;
    private bool _supportLocalization;

    // The set of assemblies that we need to reference when compiling
    private ICollection _referencedAssemblies;
    internal ICollection ReferencedAssemblies { get { return _referencedAssemblies; } }

    private AssemblyBuilder _assemblyBuilder;

    // Key: CultureName string, Value: AssemblyBuilder
    private IDictionary _satelliteAssemblyBuilders = null;

    // If this is set, we only generate the source files into this directory
    // without compiling them.
    // This is used to implement ClientBuildManager.GetCodeDirectoryInformation
    private string _generatedFilesDir;

    internal BuildProvidersCompiler(VirtualPath configPath, string outputAssemblyName) : 
        this(configPath, false, outputAssemblyName) { }

    internal BuildProvidersCompiler(VirtualPath configPath, bool supportLocalization, 
        string outputAssemblyName) {
        _configPath = configPath;
        _supportLocalization = supportLocalization;
        _compConfig = MTConfigUtil.GetCompilationConfig(_configPath);
        _referencedAssemblies = BuildManager.GetReferencedAssemblies(CompConfig);
        _outputAssemblyName = outputAssemblyName;
    }

    internal BuildProvidersCompiler(VirtualPath configPath, bool supportLocalization,
        string generatedFilesDir, int index) {
        _configPath = configPath;
        _supportLocalization = supportLocalization;
        _compConfig = MTConfigUtil.GetCompilationConfig(_configPath);
        _referencedAssemblies = BuildManager.GetReferencedAssemblies(CompConfig, index);
        _generatedFilesDir = generatedFilesDir;
    }

    // The <compilation> config section for the set of build providers that we handle
    private CompilationSection _compConfig;
    internal CompilationSection CompConfig { get { return _compConfig; } }

    private string _outputAssemblyName;
    internal string OutputAssemblyName {
        get { return _outputAssemblyName; }
    }

    private bool CbmGenerateOnlyMode {
        get { return _generatedFilesDir != null; }
    }

    internal void SetBuildProviders(ICollection buildProviders) {
        _buildProviders = buildProviders;
    }

    private void ProcessBuildProviders() {

        CompilerType compilerType = null;
        BuildProvider firstLanguageBuildProvider = null;

        // First, delete all the existing satellite assemblies of the assembly
        // we're about to build (VSWhidbey 87022) (only if it has a fixed name)
        if (OutputAssemblyName != null) {
            Debug.Assert(!CbmGenerateOnlyMode);
            StandardDiskBuildResultCache.RemoveSatelliteAssemblies(OutputAssemblyName);
        }

        // List of BuildProvider's that don't ask for a specific language
        ArrayList languageFreeBuildProviders = null;

        foreach (BuildProvider buildProvider in _buildProviders) {

            // If it's an InternalBuildProvider, give it the assembly references early on
            buildProvider.SetReferencedAssemblies(_referencedAssemblies);

            // Instruct the internal build providers to continue processing for more parse errors.
            if (!BuildManager.ThrowOnFirstParseError) {
                InternalBuildProvider provider = buildProvider as InternalBuildProvider;
                if (provider != null) {
                    provider.ThrowOnFirstParseError = false;
                }
            }

            // Get the language and culture
            CompilerType ctwp = BuildProvider.GetCompilerTypeFromBuildProvider(buildProvider);

            // Only look for a culture if we're supposed to (basically, in the resources directories)
            string cultureName = null;
            if (_supportLocalization)
                cultureName = buildProvider.GetCultureName();

            // Is it asking for a specific language?
            if (ctwp != null) {

                // If it specifies a language, it can't also have a culture
                if (cultureName != null) {
                    throw new HttpException(SR.GetString(SR.Both_culture_and_language, BuildProvider.GetDisplayName(buildProvider)));
                }

                // Do we already know the language we'll be using
                if (compilerType != null) {

                    // If it's different from the current one, fail
                    if (!ctwp.Equals(compilerType)) {
                        throw new HttpException(SR.GetString(SR.Inconsistent_language,
                            BuildProvider.GetDisplayName(buildProvider),
                            BuildProvider.GetDisplayName(firstLanguageBuildProvider)));
                    }
                }
                else {
                    // Keep track of the build provider of error handling purpose
                    firstLanguageBuildProvider = buildProvider;

                    // Keep track of the language
                    compilerType = ctwp;
                    _assemblyBuilder = compilerType.CreateAssemblyBuilder(
                        CompConfig, _referencedAssemblies, _generatedFilesDir, OutputAssemblyName);
                }
            }
            else {
                if (cultureName != null) {
                    // Ignore the culture files in generate-only mode
                    if (CbmGenerateOnlyMode)
                        continue;

                    if (_satelliteAssemblyBuilders == null) {
                        _satelliteAssemblyBuilders = new Hashtable(
                            StringComparer.OrdinalIgnoreCase);
                    }

                    // Check if we already have an assembly builder for this culture
                    AssemblyBuilder satelliteAssemblyBuilder =
                        (AssemblyBuilder) _satelliteAssemblyBuilders[cultureName];

                    // If not, create one and store it in the hashtable
                    if (satelliteAssemblyBuilder == null) {
                        satelliteAssemblyBuilder = CompilerType.GetDefaultAssemblyBuilder(
                            CompConfig, _referencedAssemblies, _configPath, OutputAssemblyName);
                        satelliteAssemblyBuilder.CultureName = cultureName;
                        _satelliteAssemblyBuilders[cultureName] = satelliteAssemblyBuilder;
                    }

                    satelliteAssemblyBuilder.AddBuildProvider(buildProvider);
                    continue;
                }

                if (_assemblyBuilder == null) {
                    // If this provider doesn't need a specific language, and we don't know
                    // the language yet, just keep track of it
                    if (languageFreeBuildProviders == null)
                        languageFreeBuildProviders = new ArrayList();
                    languageFreeBuildProviders.Add(buildProvider);
                    continue;
                }
            }

            _assemblyBuilder.AddBuildProvider(buildProvider);
        }

        // If we didn't get an AssemblyBuilder, use a default
        if (_assemblyBuilder == null && languageFreeBuildProviders != null) {
            _assemblyBuilder = CompilerType.GetDefaultAssemblyBuilder(
                CompConfig, _referencedAssemblies, _configPath,
                _generatedFilesDir, OutputAssemblyName);
        }

        // Add all the language free providers (if any) to the AssemblyBuilder
        if (_assemblyBuilder != null && languageFreeBuildProviders != null) {
            foreach (BuildProvider languageFreeBuildProvider in languageFreeBuildProviders) {
                _assemblyBuilder.AddBuildProvider(languageFreeBuildProvider);
            }
        }
    }

    internal CompilerResults PerformBuild() {

        ProcessBuildProviders();
                
        // Build all the satellite assemblies
        if (_satelliteAssemblyBuilders != null) {
            int maxConcurrent = Math.Min(_satelliteAssemblyBuilders.Count, CompilationUtil.MaxConcurrentCompilations);
            try {
                Parallel.ForEach(_satelliteAssemblyBuilders.Values.Cast<AssemblyBuilder>(),
                    new ParallelOptions { MaxDegreeOfParallelism = maxConcurrent },
                    assemblyBuilder =>
                    {
                        assemblyBuilder.Compile();
                    });
            }
            catch (AggregateException ae) {
                ExceptionDispatchInfo.Capture(ae.GetBaseException()).Throw();
            }
        }

        // Build the main assembly
        if (_assemblyBuilder != null)
            return _assemblyBuilder.Compile();

        return null;
    }

    internal void GenerateSources(out Type codeDomProviderType,
        out CompilerParameters compilerParameters) {

        ProcessBuildProviders();

        // If we didn't get an AssemblyBuilder (happens when there was nothing to build),
        // get a default one.
        if (_assemblyBuilder == null) {
            _assemblyBuilder = CompilerType.GetDefaultAssemblyBuilder(
                CompConfig, _referencedAssemblies, _configPath, 
                _generatedFilesDir, null /*outputAssemblyName*/);
        }

        codeDomProviderType = _assemblyBuilder.CodeDomProviderType;
        compilerParameters = _assemblyBuilder.GetCompilerParameters();
    }
}


/*
 * This class handles the batch compilation of one directory.  It may
 * produce several assemblies out of them, based on dependencies and language
 * differences.  All the BuildProvider's are expected to share the same
 * configuration (i.e. they live in the same directory).
 */
internal class WebDirectoryBatchCompiler {

    private DateTime _utcStart;

    // The set of assemblies that we will link with
    private ICollection _referencedAssemblies;

    // The <compilation> config section for the set of build providers that we handle
    private CompilationSection _compConfig;

    // [VirtualPathString,InternalBuildProvider]
    private IDictionary _buildProviders = new Hashtable(
        StringComparer.OrdinalIgnoreCase);

    private VirtualDirectory _vdir;
    private ArrayList[] _nonDependentBuckets;

    private bool _ignoreProvidersWithErrors;

    // The set of parser errors detected during parsing.
    private ParserErrorCollection _parserErrors;

    // The first parse exceptions thrown during parsing.
    private HttpParseException _firstException;

    internal WebDirectoryBatchCompiler(VirtualDirectory vdir) {
        _vdir = vdir;

        _utcStart = DateTime.UtcNow;

        _compConfig = MTConfigUtil.GetCompilationConfig(_vdir.VirtualPath);

        _referencedAssemblies = BuildManager.GetReferencedAssemblies(_compConfig);
    }

    internal void SetIgnoreErrors() {
        _ignoreProvidersWithErrors = true;
    }

    internal void Process() {

        AddBuildProviders(true /*retryIfDeletionHappens*/);

        // If there are no BuildProvider's, we're done
        if (_buildProviders.Count == 0)
            return;

        BuildManager.ReportDirectoryCompilationProgress(_vdir.VirtualPathObject);

        GetBuildResultDependencies();
        ProcessDependencies();

        foreach (ICollection buildProviders in _nonDependentBuckets) {
            if (!CompileNonDependentBuildProviders(buildProviders))
                break;
        }

        // Report all parse exceptions
        if (_parserErrors != null && _parserErrors.Count > 0) {
            Debug.Assert(!_ignoreProvidersWithErrors);

            // Throw the first exception as inner exception along with the parse errors.
            HttpParseException newException = 
                new HttpParseException(_firstException.Message, _firstException, _firstException.VirtualPath,
                    _firstException.Source, _firstException.Line);

            // Add the rest of the parser errors to the exception.
            // The first one is already added.
            for (int i = 1; i < _parserErrors.Count; i++) {
                newException.ParserErrors.Add(_parserErrors[i]);
            }

            // rethrow the new exception
            throw newException;
        }
    }

    private void AddBuildProviders(bool retryIfDeletionHappens) {

        DiskBuildResultCache.ResetAssemblyDeleted();

        foreach (VirtualFile vfile in _vdir.Files) {

            // If it's already built and up to date, skip it
            BuildResult result = null;
            try {
                result = BuildManager.GetVPathBuildResultFromCache(vfile.VirtualPathObject);
            }
            catch {
                // Ignore the cached error in batch compilation mode, since we want to compile
                // as many files as possible.
                // But don't ignore it in CBM or precompile cases, since we always want to try
                // to compile everything that had failed before.
                if (!BuildManager.PerformingPrecompilation) {
                    // Skip it if an exception occurs (e.g. if a compile error was cached for it)
                    continue;
                }
            }

            if (result != null)
                continue;
            
            BuildProvider buildProvider = BuildManager.CreateBuildProvider(vfile.VirtualPathObject,
                _compConfig, _referencedAssemblies, false /*failIfUnknown*/);

            // Non-supported file type
            if (buildProvider == null)
                continue;

            // IgnoreFileBuildProvider's should never be created
            Debug.Assert(!(buildProvider is IgnoreFileBuildProvider));

            _buildProviders[vfile.VirtualPath] = buildProvider;
        }

        // If an assembly had to be deleted/renamed as a result of calling GetVPathBuildResultFromCache,
        // me way need to run the AddBuildProviders logic again.  The reason is that as a result of
        // deleting the assembly, we may have invalidated other BuildResult that we had earlier found
        // to be up to date (VSWhidbey 269297)
        if (DiskBuildResultCache.InUseAssemblyWasDeleted) {
            Debug.Assert(retryIfDeletionHappens);

            // Only retry if we're doing precompilation.  For standard batching, we can live
            // with the fact that not everything will be built after we're done (and we want to
            // be done as quickly as possible since the user is waiting).
            if (retryIfDeletionHappens && BuildManager.PerformingPrecompilation) {
                Debug.Trace("WebDirectoryBatchCompiler", "Rerunning AddBuildProviders for '" +
                    _vdir.VirtualPath + "' because an assembly was out of date.");

                // Pass false for retryIfDeletionHappens to make sure we don't get in an
                // infinite recursion.
                AddBuildProviders(false /*retryIfDeletionHappens*/);
            }
        }
    }

    private void CacheAssemblyResults(AssemblyBuilder assemblyBuilder, CompilerResults results) {

        foreach (BuildProvider buildProvider in assemblyBuilder.BuildProviders) {

            BuildResult result = buildProvider.GetBuildResult(results);

            // If the provider didn't produce anything, ignore it
            if (result == null)
                continue;

            // If CacheVPathBuildResult returns false, something was found to be invalidated
            // and we need to abort the caching (VSWhidbey 578372)
            if (!BuildManager.CacheVPathBuildResult(buildProvider.VirtualPathObject, result, _utcStart))
                break;

#if DBG
            if (results != null) {
                if (DelayLoadType.Enabled) {
                    Debug.Trace("BuildManager", buildProvider.VirtualPath + " Delay Load Assembly");
                } else {
                    Debug.Trace("BuildManager", buildProvider.VirtualPath + results.CompiledAssembly.EscapedCodeBase);
                }
            }
            else {
                Debug.Trace("BuildManager", buildProvider.VirtualPath + ": no assembly");
            }
#endif
        }
    }

    // Cache the various compile errors found during batching
    private void CacheCompileErrors(AssemblyBuilder assemblyBuilder, CompilerResults results) {

        BuildProvider previous = null;

        // Go through all the compile errors
        foreach (CompilerError error in results.Errors) {

            // Skip warnings
            if (error.IsWarning)
                continue;

            // Try to map the error back to a BuildProvider.  If we can't, skip the error.
            BuildProvider buildProvider = assemblyBuilder.GetBuildProviderFromLinePragma(error.FileName);
            if (buildProvider == null)
                continue;

            // Only cache the error for template controls.  Otherwise, for file types like
            // asmx/ashx, it's too likely that two of them define the same class.
            if (!(buildProvider is BaseTemplateBuildProvider))
                continue;

            // If the error is for the same page as the previous one, ignore it
            if (buildProvider == previous)
                continue;
            previous = buildProvider;

            // Create a new CompilerResults for this error
            CompilerResults newResults = new CompilerResults(null /*tempFiles*/);

            // Copy all the output to the new result.  Note that this will include all the
            // error lines, not just the ones for this BuildProvider.  But that's not a big deal,
            // and we can't easily filter the output here.
            foreach (string s in results.Output)
                newResults.Output.Add(s);

            // Copy various other fields to the new CompilerResults object
            newResults.PathToAssembly = results.PathToAssembly;
            newResults.NativeCompilerReturnValue = results.NativeCompilerReturnValue;

            // Add this error.  It will be the only one in the CompilerResults object.
            newResults.Errors.Add(error);

            // Create a new HttpCompileException & BuildResultCompileError to wrap this error
            HttpCompileException e = new HttpCompileException(newResults,
                assemblyBuilder.GetGeneratedSourceFromBuildProvider(buildProvider));
            BuildResult result = new BuildResultCompileError(buildProvider.VirtualPathObject, e);

            // Add the dependencies to the compile error build provider, so that
            // we will retry compilation when a dependency changes
            buildProvider.SetBuildResultDependencies(result);

            // Cache it
            BuildManager.CacheVPathBuildResult(buildProvider.VirtualPathObject, result, _utcStart);
        }

    }

    private void GetBuildResultDependencies() {
        foreach (BuildProvider buildProvider in _buildProviders.Values) {
            ICollection virtualPathDependencies = buildProvider.GetBuildResultVirtualPathDependencies();
            if (virtualPathDependencies == null)
                continue;

            foreach (string virtualPathDependency in virtualPathDependencies) {
                BuildProvider dependentBuildProvider = (BuildProvider) _buildProviders[virtualPathDependency];

                if (dependentBuildProvider != null)
                    buildProvider.AddBuildProviderDependency(dependentBuildProvider);
            }
        }
    }

    // Split the providers into non dependent buckets
    private void ProcessDependencies() {
        // First phase: compute levels in the dependency tree

        int totaldepth = 0;
        Hashtable depth = new Hashtable();
        Stack stack = new Stack();

        // compute depths
        foreach (BuildProvider buildProvider in _buildProviders.Values) {
            stack.Push(buildProvider);

            while (stack.Count > 0) {
                BuildProvider curnode = (BuildProvider)stack.Peek();

                bool recurse = false;
                int maxdepth = 0;

                if (curnode.BuildProviderDependencies != null) {
                    foreach (BuildProvider child in curnode.BuildProviderDependencies) {

                        if (depth.ContainsKey(child)) {
                            if (maxdepth <= (int)depth[child])
                                maxdepth = (int)depth[child] + 1;
                            else if ((int)depth[child] == -1)
                                throw new HttpException(SR.GetString(SR.File_Circular_Reference, child.VirtualPath));
                        }
                        else {
                            recurse = true;
                            stack.Push(child);
                        }
                    }
                }

                if (recurse)
                    depth[curnode] = -1; // being computed;
                else {
                    stack.Pop();
                    depth[curnode] = maxdepth;
                    if (totaldepth <= maxdepth)
                        totaldepth = maxdepth + 1;
                }
            }
        }

        // drop into buckets by depth
        _nonDependentBuckets = new ArrayList[totaldepth];

        for (IDictionaryEnumerator en = (IDictionaryEnumerator)depth.GetEnumerator(); en.MoveNext();) {
            int level = (int)en.Value;

            if (_nonDependentBuckets[level] == null)
                _nonDependentBuckets[level] = new ArrayList();

            _nonDependentBuckets[level].Add(en.Key);
        }

#if DBG
        int i = 0;
        foreach (ICollection buildProviders in _nonDependentBuckets) {
            Debug.Trace("BuildManager", String.Empty);
            Debug.Trace("BuildManager", "Bucket " + i + " contains " + buildProviders.Count + " files");

            foreach (BuildProvider buildProvider in buildProviders)
                Debug.Trace("BuildManager", buildProvider.VirtualPath);
            i++;
        }
#endif

    }

    private bool IsBuildProviderSkipable(BuildProvider buildProvider) {

        // If another build provider depends on it, we should not skip it
        if (buildProvider.IsDependedOn) return false;

        // No one depends on it (at least in this directory)

        // If it's a source file, skip it.  We need to do this for v1 compatibility,
        // since v1 VS projects contain many source files which have already been
        // precompiled into bin, and that should not be compiled dynamically
        if (buildProvider is SourceFileBuildProvider)
            return true;

        // For the same reason, skip resources
        if (buildProvider is ResXBuildProvider)
            return true;

        return false;
    }

    private bool CompileNonDependentBuildProviders(ICollection buildProviders) {

        // Key: CompilerType, Value: AssemblyBuilder
        IDictionary assemblyBuilders = new Hashtable();

        // List of InternalBuildProvider's that don't ask for a specific language
        ArrayList languageFreeBuildProviders = null;

        // AssemblyBuilder used for providers that don't need a specific language
        AssemblyBuilder defaultAssemblyBuilder = null;

        bool hasParserErrors = false;

        foreach (BuildProvider buildProvider in buildProviders) {

            if (IsBuildProviderSkipable(buildProvider))
                continue;

            // Instruct the internal build providers to continue processing for more parse errors.
            if (!BuildManager.ThrowOnFirstParseError) {
                InternalBuildProvider provider = buildProvider as InternalBuildProvider;
                if (provider != null) {
                    provider.ThrowOnFirstParseError = false;
                }
            }

            CompilerType compilerType = null;

            // Get the language
            try {
                compilerType = BuildProvider.GetCompilerTypeFromBuildProvider(
                    buildProvider);
            }
            catch (HttpParseException ex) {
                // Ignore the error if we are in that mode.
                if (_ignoreProvidersWithErrors) {
                    continue;
                }

                hasParserErrors = true;

                // Remember the first parse exception
                if (_firstException == null) {
                    _firstException = ex;
                }

                if (_parserErrors == null) {
                    _parserErrors = new ParserErrorCollection();
                }

                _parserErrors.AddRange(ex.ParserErrors);

                continue;
            }
            catch {
                // Ignore the error if we are in that mode.
                if (_ignoreProvidersWithErrors) {
                    continue;
                }

                throw;
            }

            AssemblyBuilder assemblyBuilder = defaultAssemblyBuilder;
            ICollection typeNames = buildProvider.GetGeneratedTypeNames();

            // Is it asking for a specific language?
            if (compilerType == null) {
                // If this provider doesn't need a specific language, and we haven't yet created
                // a default builder that is capable of building this, just keep track of it                
                if (defaultAssemblyBuilder == null || defaultAssemblyBuilder.IsBatchFull ||
                    defaultAssemblyBuilder.ContainsTypeNames(typeNames)) {
                    if (languageFreeBuildProviders == null) {
                        languageFreeBuildProviders = new ArrayList();
                    }

                    languageFreeBuildProviders.Add(buildProvider);
                    continue;
                }
            }
            else {
                // Check if we already have an assembly builder of the right type
                assemblyBuilder = (AssemblyBuilder)assemblyBuilders[compilerType];
            }

            // Starts a new assemblyBuilder if the old one already contains another buildprovider 
            // that uses the same type name
            if (assemblyBuilder == null || assemblyBuilder.IsBatchFull ||
                assemblyBuilder.ContainsTypeNames(typeNames)) {

                // If the assemblyBuilder is full, compile it.
                if (assemblyBuilder != null) {
                    CompileAssemblyBuilder(assemblyBuilder);
                }

                AssemblyBuilder newBuilder = compilerType.CreateAssemblyBuilder(
                    _compConfig, _referencedAssemblies);

                assemblyBuilders[compilerType] = newBuilder;

                // Remember it as the default if we don't already have one,
                // or if the default is already full, switch the default to the new one.
                if (defaultAssemblyBuilder == null ||
                    defaultAssemblyBuilder == assemblyBuilder) {

                    defaultAssemblyBuilder = newBuilder;
                }

                assemblyBuilder = newBuilder;
            }

            assemblyBuilder.AddTypeNames(typeNames);
            assemblyBuilder.AddBuildProvider(buildProvider);
        }

        // Don't try to compile providers, otherwise compile exceptions will be bubbled up,
        // and we lose the parse errors.
        if (hasParserErrors) {
            return false;
        }

        // Handle all the left over language free providers
        if (languageFreeBuildProviders != null) {

            // Indicates whether the default assembly builder is not a language specific builder.
            bool newDefaultAssemblyBuilder = (defaultAssemblyBuilder == null);

            // Add language independent providers to the default assembly builder.
            foreach (BuildProvider languageFreeBuildProvider in languageFreeBuildProviders) {

                ICollection typeNames = languageFreeBuildProvider.GetGeneratedTypeNames();

                // If we don't have a default language assembly builder, get one or
                // starts a new assemblyBuilder if the old one already contains another buildprovider 
                // that uses the same type name
                if (defaultAssemblyBuilder == null || defaultAssemblyBuilder.IsBatchFull ||
                    defaultAssemblyBuilder.ContainsTypeNames(typeNames)) {

                    // If the default assemblyBuilder is full, compile it.
                    if (defaultAssemblyBuilder != null) {
                        CompileAssemblyBuilder(defaultAssemblyBuilder);
                    }

                    defaultAssemblyBuilder = CompilerType.GetDefaultAssemblyBuilder(
                        _compConfig, _referencedAssemblies, _vdir.VirtualPathObject /*configPath*/, 
                        null /*outputAssemblyName*/);

                    // the default assembly builder needs to be compiled separately.
                    newDefaultAssemblyBuilder = true;
                }

                defaultAssemblyBuilder.AddTypeNames(typeNames);
                defaultAssemblyBuilder.AddBuildProvider(languageFreeBuildProvider);
            }

            // Only compile the default assembly builder if it's not part of language specific
            // assembly builder (which will be compiled separately)
            if (newDefaultAssemblyBuilder) {
                // Compile the default assembly builder.
                CompileAssemblyBuilder(defaultAssemblyBuilder);
            }
        }

        CompileAssemblyBuilderParallel(assemblyBuilders.Values);
        
        return true;
    }

    private void CompileAssemblyBuilderParallel(ICollection assemblyBuilders) {

        int maxConcurrent = Math.Min(assemblyBuilders.Count, CompilationUtil.MaxConcurrentCompilations);

        if (maxConcurrent < 2) {
            // Not using Parallel.ForEach to avoid performance penalty
            foreach (AssemblyBuilder assemblyBuilder in assemblyBuilders) {
                CompileAssemblyBuilder(assemblyBuilder);
            }
        }

        else {
            // devdiv bug 666936: ASP.NET compilation related deadlock in Antares scenario. 
            // The main (current) thread holds a global compilation lock. CacheAssemblyResults and CacheCompileErrors may 
            // also require the global compilation lock in case of removing old data and thus may lead to deadlock.
            // Fix: using dictionaries to collect the build results from parallel threads and do caching in the main thread.
            ConcurrentDictionary<AssemblyBuilder, CompilerResults> buildResults = new ConcurrentDictionary<AssemblyBuilder, CompilerResults>();
            ConcurrentDictionary<AssemblyBuilder, CompilerResults> buildErrors = new ConcurrentDictionary<AssemblyBuilder, CompilerResults>();
            
            try {
                Parallel.ForEach(assemblyBuilders.Cast<AssemblyBuilder>(),
                    new ParallelOptions { MaxDegreeOfParallelism = maxConcurrent },
                    builder =>
                    {
                        CompilerResults results;
                        try {
                            results = builder.Compile();
                        }
                        catch (HttpCompileException e) { 
                            buildErrors[builder] = e.Results;                            
                            throw;
                        }                        
                        buildResults[builder] = results;                        
                    });
            }
            catch (AggregateException e) {
                ExceptionDispatchInfo.Capture(e.GetBaseException()).Throw();
            }
            finally {
                // Before throwing the aggregated compilation exception, cache the build results first
                // This follows the execution order for the single thread case
                foreach (var pair in buildErrors) {
                    CacheCompileErrors(pair.Key, pair.Value);
                }
                foreach (var pair in buildResults) {
                    CacheAssemblyResults(pair.Key, pair.Value);
                }                
            }
        }
    }

    private void CompileAssemblyBuilder(AssemblyBuilder builder) {

        CompilerResults results;

        try {
            results = builder.Compile();
        }
        catch (HttpCompileException e) {
            CacheCompileErrors(builder, e.Results);
            throw;
        }

        CacheAssemblyResults(builder, results);
    }
}

}