Package flex2.compiler

Source Code of flex2.compiler.CompilerAPI$UnableToResolveNeededClass

/*
*
*  Licensed to the Apache Software Foundation (ASF) under one or more
*  contributor license agreements.  See the NOTICE file distributed with
*  this work for additional information regarding copyright ownership.
*  The ASF licenses this file to You under the Apache License, Version 2.0
*  (the "License"); you may not use this file except in compliance with
*  the License.  You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*
*/

package flex2.compiler;

import flash.fonts.FontManager;
import flash.localization.LocalizationManager;
import flash.localization.ResourceBundleLocalizer;
import flash.localization.XLRLocalizer;
import flash.swf.Movie;
import flash.swf.MovieEncoder;
import flash.swf.TagEncoder;
import flash.swf.TagEncoderReporter;
import flash.swf.tools.SizeReport;
import flash.util.FileUtils;

import flex2.compiler.config.ServicesDependenciesWrapper;

import flex2.compiler.as3.As3Compiler;
import flex2.compiler.as3.SignatureExtension;
import flex2.compiler.common.CompilerConfiguration;
import flex2.compiler.common.Configuration;
import flex2.compiler.config.ConfigurationException;
import flex2.compiler.common.FramesConfiguration;
import flex2.compiler.common.LocalFilePathResolver;
import flex2.compiler.common.PathResolver;
import flex2.compiler.common.SinglePathResolver;
import flex2.compiler.common.FramesConfiguration.FrameInfo;
import flex2.compiler.extensions.ExtensionManager;
import flex2.compiler.extensions.IPreCompileExtension;
import flex2.compiler.i18n.I18nUtils;
import flex2.compiler.io.FileUtil;
import flex2.compiler.io.InMemoryFile;
import flex2.compiler.io.LocalFile;
import flex2.compiler.io.ResourceFile;
import flex2.compiler.io.VirtualFile;
import flex2.compiler.mxml.lang.StandardDefs;
import flex2.compiler.swc.SwcScript;
import flex2.compiler.util.*;
import flex2.compiler.util.graph.Algorithms;
import flex2.compiler.util.graph.DependencyGraph;
import flex2.compiler.util.graph.Vertex;
import flex2.compiler.util.graph.Visitor;
import flex2.linker.ConsoleApplication;
import flex2.linker.LinkerConfiguration;
import flex2.linker.LinkerException;
import flex2.linker.SimpleMovie;
import flex2.tools.CompcPreLink;
import flex2.tools.oem.ProgressMeter;

import java.io.IOException;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.*;
import java.util.Map.Entry;

import macromedia.asc.parser.Tokens;
import macromedia.asc.semantics.ObjectValue;
import macromedia.asc.semantics.Slot;
import macromedia.asc.semantics.TypeValue;
import macromedia.asc.semantics.VariableSlot;
import macromedia.asc.util.Context;
import macromedia.asc.util.ContextStatics;
import macromedia.asc.util.Names;

/**
* This class orchestrates delegation to the subcompilers using
* batch1() when -conservative is true or batch2(), the default.  It
* also handles common tasks like validating CompilationUnit's before
* an incremental compilation, resolving dependences, loading a cache
* from a previous compilation, and storing a compilation cache.
*
* @see flex2.compiler.SubCompiler
* @see flex2.compiler.PersistentStore
* @see flex2.compiler.abc.AbcCompiler
* @see flex2.compiler.as3.As3Compiler
* @see flex2.compiler.css.CssCompiler
* @see flex2.compiler.fxg.FXGCompiler
* @see flex2.compiler.i18n.I18nCompiler
* @see flex2.compiler.mxml.MxmlCompiler
* @author Clement Wong
*/
public final class CompilerAPI
{
    private final static int INHERITANCE = 1;
    private final static int NAMESPACES = 2;
    private final static int TYPES = 3;
    private final static int EXPRESSIONS = 4;

    public static void useAS3()
    {
        // do this so there is no need to start java with -DAS3 and -DAVMPLUS...
        // this will likely not work in server environment.
        System.setProperty("AS3", "");
        System.setProperty("AVMPLUS", "");
    }

    public static void useConsoleLogger()
    {
        useConsoleLogger(true, true, true, true);
    }

    public static void useConsoleLogger(boolean isInfoEnabled, boolean isDebugEnabled, boolean isWarningEnabled, boolean isErrorEnabled)
    {
        ThreadLocalToolkit.setLogger(new ConsoleLogger(isInfoEnabled, isDebugEnabled, isWarningEnabled, isErrorEnabled));
    }

    public static Benchmark runBenchmark()
    {
        Benchmark b = ThreadLocalToolkit.getBenchmark();

        if (b == null)
        {
            try
            {
                String className = System.getProperty("flex2.compiler.benchmark");

                if (className != null)
                {
                    Class benchmarkClass = Class.forName(className, true, Thread.currentThread().getContextClassLoader());
                    b = (Benchmark) benchmarkClass.newInstance();
                }
            }
            catch (Exception e)
            {
                assert false : e.toString();
            }

            if (b == null)
            {
                b = new Benchmark();
            }

            ThreadLocalToolkit.setBenchmark(b);
            ThreadLocalToolkit.resetBenchmark();
        }

        return b;
    }

    public static void disableBenchmark()
    {
        ThreadLocalToolkit.setBenchmark(null);
    }

    public static void usePathResolver()
    {
        usePathResolver(null);
    }

    public static void usePathResolver(SinglePathResolver resolver)
    {
        PathResolver pathResolver = new PathResolver();
        if (resolver != null)
        {
            pathResolver.addSinglePathResolver(resolver);
        }
        pathResolver.addSinglePathResolver( LocalFilePathResolver.getSingleton() );
        pathResolver.addSinglePathResolver( URLPathResolver.getSingleton() );
        ThreadLocalToolkit.setPathResolver(pathResolver);
    }

    public static void removePathResolver()
    {
        ThreadLocalToolkit.setPathResolver(null);
        ThreadLocalToolkit.resetResolvedPaths();
    }

    public static void setupHeadless(Configuration configuration)
    {
        if (configuration.getCompilerConfiguration().headlessServer())
        {
            try
            {
                // needed for J#, which does not support setProperty method on System
                java.util.Properties systemProps = java.lang.System.getProperties();
                systemProps.put("java.awt.headless", "true");
                java.lang.System.setProperties(systemProps);
            }
            catch (SecurityException securityException)
            {
                // log warning for users who need to set property via command line due to policy settings
                ThreadLocalToolkit.log(new UnableToSetHeadless());
            }
        }
    }

    public static NameMappings getNameMappings(Configuration configuration)
    {
        NameMappings mappings = new NameMappings();
        Map<String, List<VirtualFile>> manifests = configuration.getCompilerConfiguration().getNamespacesConfiguration().getManifestMappings();
        if (manifests != null)
        {
            Iterator<Entry<String, List<VirtualFile>>> entryIterator = manifests.entrySet().iterator();
            while (entryIterator.hasNext())
            {
                Entry<String, List<VirtualFile>> entry = entryIterator.next();
                String ns = entry.getKey();
                List<VirtualFile> files = entry.getValue();
                Iterator<VirtualFile> filesIterator = files.iterator();
                while (filesIterator.hasNext())
                {
                    VirtualFile file = filesIterator.next();
                    ManifestParser.parse(ns, file, mappings);
                }
            }
        }
        return mappings;
    }

    private static final int preprocess                 = (1 << 1);
    private static final int parse1                     = (1 << 2);
    private static final int parse2                     = (1 << 3);
    private static final int analyze1                   = (1 << 4);
    private static final int analyze2                   = (1 << 5);
    private static final int analyze3                   = (1 << 6);
    private static final int analyze4                   = (1 << 7);
//    private static final int resolveInheritance         = (1 << 8);
//    private static final int sortInheritance            = (1 << 9);
    private static final int resolveType                = (1 << 10);
//    private static final int importType                 = (1 << 11);
//    private static final int resolveExpression          = (1 << 12);
    private static final int generate                   = (1 << 13);
    private static final int resolveImportStatements    = (1 << 14);
    private static final int adjustQNames               = (1 << 15);
    private static final int extraSources               = (1 << 16);

    /**
     * CompilerAPI.batch1() is used when -conservative is specified.
     *
     * It waits until*every* source has completed each compilation stage (e.g. analyze1())
     * before continuing (e.g. to analyze2())
     */
    private static void batch1(List<Source> sources, List<CompilationUnit> units,
                               DependencyGraph<CompilationUnit> igraph, DependencyGraph<Source> dgraph,
                               SymbolTable symbolTable, flex2.compiler.SubCompiler[] compilers, SourceList sourceList,
                               SourcePath sourcePath, ResourceContainer resources, CompilerSwcContext swcContext,
                               Configuration configuration)
    {
        int start = 0, end = sources.size();

        while (start < end)
        {
            if (!preprocess(sources, compilers, start, end, symbolTable.getSuppressWarningsIncremental()))
            {
                break;
            }

            if (tooManyErrors() || forcedToStop()) break;

            if (!parse1(sources, units, igraph, dgraph, compilers, symbolTable, start, end))
            {
                break;
            }

            if (tooManyErrors() || forcedToStop()) break;

            // C: context-free above this line...

            resolveInheritance(sources, igraph, dgraph, symbolTable, sourceList, sourcePath, resources, swcContext, start, end);
            addGeneratedSources(sources, igraph, dgraph, resources, symbolTable, configuration, start, end);

            start = end;
            end = sources.size();

            if (start < end)
            {
                continue;
            }

            if (!sortInheritance(sources, units, igraph))
            {
                break;
            }

            if (!parse2(sources, compilers, symbolTable))
            {
                break;
            }

            if (tooManyErrors() || forcedToStop()) break;

            if (!analyze(sources, compilers, symbolTable, 1))
            {
                break;
            }

            if (tooManyErrors() || forcedToStop()) break;

            resolveNamespace(sources, igraph, dgraph, symbolTable, sourceList, sourcePath, resources, swcContext, 0, end);
            addGeneratedSources(sources, igraph, dgraph, resources, symbolTable, configuration, 0, end);

            start = end;
            end = sources.size();

            if (start < end)
            {
                continue;
            }

            if (!analyze(sources, compilers, symbolTable, 2))
            {
                break;
            }

            if (tooManyErrors() || forcedToStop()) break;

            resolveType(sources, units, igraph, dgraph, symbolTable, sourceList, sourcePath, resources, swcContext);

            final CompilerConfiguration config = (configuration != null) ? configuration.getCompilerConfiguration() : null;
            if (config != null && config.strict())
            {
                resolveImportStatements(sources, units, sourcePath, swcContext);
            }

            // C: If --coach is turned on, do resolveExpression() here...
            if (config != null && (config.strict() || config.warnings()))
            {
                resolveExpression(sources, units, igraph, dgraph, symbolTable, sourceList,
                                  sourcePath, resources, swcContext, configuration);
            }

            start = end;
            end = sources.size();

            if (start < end)
            {
                continue;
            }

            if (!analyze(sources, compilers, symbolTable, 3))
            {
                break;
            }

            if (tooManyErrors() || forcedToStop()) break;

            if (!analyze(sources, compilers, symbolTable, 4))
            {
                break;
            }

            if (tooManyErrors() || forcedToStop()) break;

            if (!generate(sources, units, compilers, symbolTable))
            {
                break;
            }

            if (tooManyErrors() || forcedToStop()) break;

            markDone(sources, units);

            if (!postprocess(sources, units, compilers, symbolTable))
            {
                break;
            }

            if (tooManyErrors() || forcedToStop()) break;

            resolveExpression(sources, units, igraph, dgraph, symbolTable, sourceList, sourcePath, resources, swcContext, configuration);
            addGeneratedSources(sources, igraph, dgraph, resources, symbolTable, configuration, 0, end);

            start = end;
            end = sources.size();
        }

        adjustQNames(units, igraph, symbolTable);
    }

    /**
     * CompilerAPI.batch2() is the default algorithm (@see CompilerAPI.batch1()).
     *
     * It tries to release resources (such as the syntax tree) early by allowing sources
     * to reach generate() as soon as possible, once all their dependencies have been met.
     */
    private static void batch2(List<Source> sources, List<CompilationUnit> units,
                               DependencyGraph<CompilationUnit> igraph, DependencyGraph<Source> dgraph,
                               SymbolTable symbolTable, flex2.compiler.SubCompiler[] compilers, SourceList sourceList,
                               SourcePath sourcePath, ResourceContainer resources, CompilerSwcContext swcContext,
                               Configuration configuration)
    {
        Benchmark benchmark = ThreadLocalToolkit.getBenchmark();
        int benchmarkCompilingDetails = benchmark == null ? -1 : configuration.getBenchmarkCompilerDetails();

        if (benchmarkCompilingDetails > 4)
        {
            benchmark.benchmark2(
                    ThreadLocalToolkit.getLocalizationManager().getLocalizedTextString(new BatchTime("start", "")), true);
        }

        CompilerConfiguration config = (configuration != null) ? configuration.getCompilerConfiguration() : null;
        List<Source> targets = new ArrayList<Source>(sources.size());

        units.clear();
        for (int i = 0, size = sources.size(); i < size; i++)
        {
            Source s = sources.get(i);
            if (s != null && s.isCompiled())
            {
                units.add(s.getCompilationUnit());
            }
            else
            {
                units.add(null);
            }
        }

        if (benchmarkCompilingDetails > 4)
        {
            benchmark.benchmark2(
                    ThreadLocalToolkit.getLocalizationManager().getLocalizedTextString(new BatchTime("init units", "")));
        }

        while (nextSource(sources, igraph, dgraph, targets, symbolTable, configuration) > 0)
        {
            int postprocessCount = 0;

            // 1. targets.size() == sources.size()
            // 2. targets.get(i) == sources.get(i) or targets.get(i) == null
            for (int i = 0, size = targets.size(); i < size; i++)
            {
                Source s = targets.get(i);
                if (s == null) continue;

                int w = getCompilationUnitWorkflow(s);

                if ((w & preprocess) == 0)
                {
                    // C: it returns false if it errors. There is no need to catch that. It's okay to
                    //    keep going because findSources() takes into account of errors.
                    preprocess(sources, compilers, i, i + 1, symbolTable.getSuppressWarningsIncremental());

                    if (benchmarkCompilingDetails > 4)
                    {
                        benchmark.benchmark2(
                                ThreadLocalToolkit.getLocalizationManager()
                                .getLocalizedTextString(
                                        new BatchTime("preprocess", s.getNameForReporting())));
                    }
                }
                else if ((w & parse1) == 0)
                {
                    parse1(sources, units, igraph, dgraph, compilers, symbolTable, i, i + 1);
                    resolveInheritance(sources, igraph, dgraph, symbolTable, sourceList, sourcePath, resources, swcContext, i, i + 1);
                    addGeneratedSources(sources, igraph, dgraph, resources, symbolTable, configuration, i, i + 1);

                    if (benchmarkCompilingDetails > 4)
                    {
                        ThreadLocalToolkit.getBenchmark().benchmark2(
                                ThreadLocalToolkit.getLocalizationManager().
                                getLocalizedTextString(
                                        new BatchTime("parse1", s.getNameForReporting())));
                    }
                }
                else if ((w & parse2) == 0)
                {
                    parse2(sources, compilers, symbolTable, i, i + 1);
                    addGeneratedSources(sources, igraph, dgraph, resources, symbolTable, configuration, i, i + 1);

                    if (benchmarkCompilingDetails > 4)
                    {
                        ThreadLocalToolkit.getBenchmark().benchmark2(
                                ThreadLocalToolkit.getLocalizationManager().
                                getLocalizedTextString(
                                        new BatchTime("parse2", s.getNameForReporting())));
                    }
                }
                else if ((w & analyze1) == 0)
                {
                    // analyze1
                    analyze(sources, compilers, symbolTable, i, i + 1, 1);
                    resolveNamespace(sources, igraph, dgraph, symbolTable, sourceList, sourcePath, resources, swcContext, i, i + 1);
                    addGeneratedSources(sources, igraph, dgraph, resources, symbolTable, configuration, i, i + 1);

                    if (benchmarkCompilingDetails > 4)
                    {
                        ThreadLocalToolkit.getBenchmark().benchmark2(
                                ThreadLocalToolkit.getLocalizationManager().
                                getLocalizedTextString(
                                        new BatchTime("analyze1", s.getNameForReporting())));
                    }
                }
                else if ((w & analyze2) == 0)
                {
                    // analyze2
                    analyze(sources, compilers, symbolTable, i, i + 1, 2);
                    resolveType(sources, units, igraph, dgraph, symbolTable, sourceList, sourcePath, resources, swcContext, i, i + 1);

                    if (config.strict())
                    {
                        resolveImportStatements(sources, units, sourcePath, swcContext, i, i + 1);
                    }

                    // C: we don't need this batch1-based memory optimization.
                    // if (config.strict() || config.coach())
                    {
                        resolveExpression(sources, units, igraph, dgraph, symbolTable, sourceList, sourcePath, resources,
                                          swcContext, configuration, i, i + 1);
                    }

                    if (benchmarkCompilingDetails > 4)
                    {
                        ThreadLocalToolkit.getBenchmark().benchmark2(
                                ThreadLocalToolkit.getLocalizationManager().
                                getLocalizedTextString(
                                        new BatchTime("analyze2", s.getNameForReporting())));
                    }
                }
                else if ((w & analyze3) == 0)
                {
                    // analyze3
                    analyze(sources, compilers, symbolTable, i, i + 1, 3);

                    if (benchmarkCompilingDetails > 4)
                    {
                        ThreadLocalToolkit.getBenchmark().benchmark2(
                                ThreadLocalToolkit.getLocalizationManager().
                                getLocalizedTextString(
                                        new BatchTime("analyze3", s.getNameForReporting())));
                    }
                }
                else if ((w & analyze4) == 0)
                {
                    // analyze4
                    analyze(sources, compilers, symbolTable, i, i + 1, 4);

                    if (benchmarkCompilingDetails > 4)
                    {
                        ThreadLocalToolkit.getBenchmark().benchmark2(
                                ThreadLocalToolkit.getLocalizationManager().
                                getLocalizedTextString(
                                        new BatchTime("analyze4", s.getNameForReporting())));
                    }
                }
                else if ((w & generate) == 0)
                {
                    // generate
                    generate(sources, units, compilers, symbolTable, i, i + 1);
                    addGeneratedSources(sources, igraph, dgraph, resources, symbolTable, configuration, i, i + 1);
                    resolveExpression(sources, units, igraph, dgraph, symbolTable, sourceList, sourcePath, resources, swcContext, configuration, i, i + 1);
                    markDone(sources, units, i, i + 1);

                    if (benchmarkCompilingDetails > 4)
                    {
                        ThreadLocalToolkit.getBenchmark().benchmark2(
                                ThreadLocalToolkit.getLocalizationManager().
                                getLocalizedTextString(
                                        new BatchTime("generate", s.getNameForReporting())));
                    }
                }

                if (tooManyErrors() || forcedToStop()) break;

                if ((w & generate) != 0)
                {
                    // postprocess
                    postprocess(sources, units, compilers, symbolTable, i, i + 1);
                    resolveExpression(sources, units, igraph, dgraph, symbolTable, sourceList, sourcePath, resources, swcContext, configuration, i, i + 1);

                    postprocessCount++;

                    if (benchmarkCompilingDetails > 4)
                    {
                        ThreadLocalToolkit.getBenchmark().benchmark2(
                                ThreadLocalToolkit.getLocalizationManager().
                                getLocalizedTextString(
                                        new BatchTime("postprocess", s.getNameForReporting())));
                    }
                }

                if (tooManyErrors() || forcedToStop()) break;
            }

            // If all of them are doing postprocessing and they're not resolving and bringing in more source files,
            // we can call the compilation done and it should exit the loop.
            if ((postprocessCount == targets.size() && sources.size() == targets.size()) || tooManyErrors() || forcedToStop())
            {
                break;
            }
        }

        adjustQNames(units, igraph, symbolTable);
    }

    private static int nextSource(List<Source> sources, DependencyGraph<CompilationUnit> igraph, DependencyGraph<Source> dgraph,
                                  List<Source> targets, SymbolTable symbolTable, Configuration configuration)
    {
        int count = 0, isDone = 0;
        boolean strict = configuration.getCompilerConfiguration().strict();
        boolean warnings = configuration.getCompilerConfiguration().warnings();
        int factor = configuration.getCompilerConfiguration().factor();

        // The notDoneList is used to debug which files are not being completed on a pass
        // thru the source files. To turn on the debugging uncomment the uses of "notDoneList"
        // in this method.
//        HashMap notDoneList = new HashMap(sources.size());
        targets.clear();

        // if 'targets' is smaller than 'sources', fill it up.
        for (int i = targets.size(), size = sources.size(); i < size; i++)
        {
            targets.add(null);
        }

        // Map notOkay = new HashMap();
        Set<String> processed = new HashSet<String>();

        for (int i = sources.size() - 1; i >= 0; i--)
        {
            Source s = sources.get(i);
//            if (notDoneList.get(s.getName()) == null)
//            {
//                notDoneList.put(s.getName(), s);
//            }
            CompilationUnit u = s != null ? s.getCompilationUnit() : null;
            int w = getCompilationUnitWorkflow(s);

            if (w == 0 || (w & preprocess) == 0 || (w & parse1) == 0)
            {
                // anything before 'parse2' requires no dependencies
                boolean okay = s.getLogger() == null || s.getLogger().errorCount() == 0;

                if (okay)
                {
                    targets.set(i, s);
                    count++;
                }
                /*
                else
                {
                    notOkay.put(s, "1");
                }
                */
            }
            else if ((w & parse2) == 0)
            {
                boolean okay = ((s.getLogger() == null || s.getLogger().errorCount() == 0) &&
                                check(u, INHERITANCE, u.inheritance, symbolTable, parse2));

                if (okay)
                {
                    targets.set(i, s);
                    count++;
                }
            }
            else if ((w & analyze1) == 0)
            {
                boolean okay = (s.getLogger() == null || s.getLogger().errorCount() == 0);

                if (okay)
                {
                    targets.set(i, s);
                    count++;
                }
            }
            else if ((w & analyze2) == 0)
            {
                // analyze1 --> analyze2? focus on inheritance and namespaces
                //
                // 1. get their workflow values... must be greater than or equal to analyze2.
                // 2. CompilationUnit.typeinfo must be present.
                // 3. error count must be zero.

                boolean okay =  ((s.getLogger() == null || s.getLogger().errorCount() == 0) &&
                                 checkInheritance(u, u.inheritance, symbolTable, analyze2, processed) &&
                                 check(u, NAMESPACES, u.namespaces, symbolTable, analyze2));
                processed.clear();

                if (okay)
                {
                    targets.set(i, s);
                    count++;
                }
                /*
                else
                {
                    notOkay.put(s, "2");
                }
                */
            }
            else if ((w & analyze3) == 0)
            {
                // analyze2 --> analyze3? focus on types, expressions and namespaces
                //
                // 1. get their workflow values... must be greater than or equal to analyze3.
                // 2. CompilationUnit.typeinfo must be present.
                // 3. error count must be zero.

                boolean okay = ((s.getLogger() == null || s.getLogger().errorCount() == 0) &&
                                checkInheritance(u, u.inheritance, symbolTable, analyze3, processed) &&
                                check(u, TYPES, u.types, symbolTable, analyze2) &&
                                check(u, NAMESPACES, u.namespaces, symbolTable, analyze3) &&
                                ((!strict && !warnings) || check(u, EXPRESSIONS, u.expressions, symbolTable, analyze2)));
                processed.clear();

                if (okay)
                {
                    targets.set(i, s);
                    count++;
                }
                /*
                else
                {
                    notOkay.put(s, "3");
                }
                */
            }
            else if ((w & analyze4) == 0)
            {
                // analyze3 --> analyze4?
                //
                // 1. get their workflow values... must be greater than or equal to analyze4.
                // 3. error count must be zero.

                boolean okay = ((s.getLogger() == null || s.getLogger().errorCount() == 0) &&
                                checkInheritance(u, u.inheritance, symbolTable, analyze4, processed) &&
                                check(u, NAMESPACES, u.namespaces, symbolTable, analyze4) &&
                                checkDeep(u, TYPES, u.types, symbolTable, processed) &&
                                ((!strict && !warnings) || checkDeep(u, EXPRESSIONS, u.expressions, symbolTable, processed)));
                processed.clear();

                if (okay)
                {
                    targets.set(i, s);
                    count++;
                }
                /*
                else
                {
                    notOkay.put(s, "4");
                }
                */
            }
            else if ((w & generate) == 0)
            {
                // analyze4 --> generate
                //
                // 1. error count must be zero.

                if ((s.getLogger() == null) || (s.getLogger().errorCount() == 0))
                {
                    targets.set(i, s);
                    count++;
                }
                /*
                else
                {
                    notOkay.put(s, "5");
                }
                */
            }
            else
            {
                isDone = (s.getLogger() == null || s.getLogger().errorCount() == 0) ? isDone + 1 : isDone;
//                if ((s.getLogger() == null || s.getLogger().errorCount() == 0))
//                {
//                    notDoneList.remove(s.getName());
//                }
            }
        }

        if (count > 0)
        {
            boolean[] bits = new boolean[targets.size()];
            double maxBudget = 100, budget = 0;

            // Preferences
            //
            // 1. SubCompiler.generate()
            // 2. SubCompiler.analyze3()
            // 3. SubCompiler.analyze4()
            // 4. SubCompiler.analyze1()
            // 5. SubCompiler.preprocess()
            // 6. SubCompiler.analyze2() for .abc
            // 7. SubCompiler.parse2() for .abc
            // 8. SubCompiler.parse1() for .abc
            // 9. SubCompiler.analyze2() for .as and .mxml
            // 10. SubCompiler.parse2() for .as and .mxml
            // 11. SubCompiler.parse1() for .as and .mxml


            // 1. SubCompiler.generate()
            for (int i = targets.size() - 1; i >= 0 && budget < maxBudget; i--)
            {
                Source s = targets.get(i);
                if (s == null) continue;

                int w = getCompilationUnitWorkflow(s);
                if (w != 0 &&
                    (w & preprocess) != 0 &&
                    (w & parse1) != 0 &&
                    (w & parse2) != 0 &&
                    (w & analyze1) != 0 &&
                    (w & analyze2) != 0 &&
                    (w & analyze3) != 0 &&
                    (w & analyze4) != 0 &&
                    (w & generate) == 0)
                {
                    bits[i] = true;
                }
            }

            // 2. SubCompiler.analyze3()
            for (int i = targets.size() - 1; i >= 0 && budget < maxBudget; i--)
            {
                Source s = targets.get(i);
                if (s == null) continue;

                int w = getCompilationUnitWorkflow(s);
                if (w != 0 &&
                    (w & preprocess) != 0 &&
                    (w & parse1) != 0 &&
                    (w & parse2) != 0 &&
                    (w & analyze1) != 0 &&
                    (w & analyze2) != 0 &&
                    (w & analyze3) == 0)
                {
                    bits[i] = true;
                }
            }

            // 3. SubCompiler.analyze4()
            for (int i = targets.size() - 1; i >= 0 && budget < maxBudget; i--)
            {
                Source s = targets.get(i);
                if (s == null) continue;

                int w = getCompilationUnitWorkflow(s);
                if (w != 0 &&
                    (w & preprocess) != 0 &&
                    (w & parse1) != 0 &&
                    (w & parse2) != 0 &&
                    (w & analyze1) != 0 &&
                    (w & analyze2) != 0 &&
                    (w & analyze3) != 0 &&
                    (w & analyze4) == 0)
                {
                    bits[i] = true;
                }
            }

            // 4. SubCompiler.analyze1()
            for (int i = targets.size() - 1; i >= 0 && budget < maxBudget; i--)
            {
                Source s = targets.get(i);
                if (s == null) continue;

                int w = getCompilationUnitWorkflow(s);
                if (w != 0 &&
                    (w & preprocess) != 0 &&
                    (w & parse1) != 0 &&
                    (w & parse2) != 0 &&
                    (w & analyze1) == 0)
                {
                    bits[i] = true;
                }
            }

            // 5. SubCompiler.preprocess()
            for (int i = targets.size() - 1; i >= 0 && budget < maxBudget; i--)
            {
                Source s = targets.get(i);
                if (s == null) continue;

                int w = getCompilationUnitWorkflow(s);
                if (w == 0)
                {
                    bits[i] = true;
                }
            }

            // 6. SubCompiler.analyze2() for .abc
            for (int i = targets.size() - 1; i >= 0 && budget < maxBudget; i--)
            {
                Source s = targets.get(i);
                if (s == null) continue;

                int w = getCompilationUnitWorkflow(s);
                if (w != 0 &&
                    (w & preprocess) != 0 &&
                    (w & parse1) != 0 &&
                    (w & parse2) != 0 &&
                    (w & analyze1) != 0 &&
                    (w & analyze2) == 0)
                {
                    if (MimeMappings.ABC.equals(s.getMimeType()))
                    {
                        bits[i] = true;
                    }
                }
            }

            // 7. SubCompiler.parse2() for .abc
            for (int i = targets.size() - 1; i >= 0 && budget < maxBudget; i--)
            {
                Source s = targets.get(i);
                if (s == null) continue;

                int w = getCompilationUnitWorkflow(s);
                if (w != 0 &&
                    (w & preprocess) != 0 &&
                    (w & parse1) != 0 &&
                    (w & parse2) == 0)
                {
                    if (MimeMappings.ABC.equals(s.getMimeType()))
                    {
                        bits[i] = true;
                    }
                }
            }

            // 8. SubCompiler.parse1() for .abc
            for (int i = targets.size() - 1; i >= 0 && budget < maxBudget; i--)
            {
                Source s = targets.get(i);
                if (s == null) continue;

                int w = getCompilationUnitWorkflow(s);
                if (w != 0 &&
                    (w & preprocess) != 0 &&
                    (w & parse1) == 0)
                {
                    if (MimeMappings.ABC.equals(s.getMimeType()))
                    {
                        bits[i] = true;
                    }
                }
            }

            // 9. SubCompiler.analyze2() for .as and .mxml
            for (int i = targets.size() - 1; i >= 0 && budget < maxBudget; i--)
            {
                Source s = targets.get(i);
                if (s == null) continue;

                int w = getCompilationUnitWorkflow(s);
                if (w != 0 &&
                    (w & preprocess) != 0 &&
                    (w & parse1) != 0 &&
                    (w & parse2) != 0 &&
                    (w & analyze1) != 0 &&
                    (w & analyze2) == 0)
                {
                    if (!MimeMappings.ABC.equals(s.getMimeType()))
                    {
                        budget += calculateBudget(s, factor);
                        bits[i] = true;
                    }
                }
            }

            // 10. SubCompiler.parse2() for .as and .mxml
            for (int i = targets.size() - 1; i >= 0 && budget < maxBudget; i--)
            {
                Source s = targets.get(i);
                if (s == null) continue;

                int w = getCompilationUnitWorkflow(s);
                if (w != 0 &&
                    (w & preprocess) != 0 &&
                    (w & parse1) != 0 &&
                    (w & parse2) == 0)
                {
                    if (!MimeMappings.ABC.equals(s.getMimeType()))
                    {
                        budget += calculateBudget(s, factor);
                        bits[i] = true;
                    }
                }
            }

            // 11. SubCompiler.parse1() for .as and .mxml
            for (int i = targets.size() - 1; i >= 0 && budget < maxBudget; i--)
            {
                Source s = targets.get(i);
                if (s == null) continue;

                int w = getCompilationUnitWorkflow(s);
                if (w != 0 &&
                    (w & preprocess) != 0 &&
                    (w & parse1) == 0)
                {
                    if (!MimeMappings.ABC.equals(s.getMimeType()))
                    {
                        budget += calculateBudget(s, factor);
                        bits[i] = true;
                    }
                }
            }

            count = 0;
            for (int i = 0, size = bits.length; i < size; i++)
            {
                if (!bits[i])
                {
                    targets.set(i, null);
                }
                else
                {
                    count++;
                }
            }
        }
        else if (count == 0 && isDone == sources.size())
        {
            // successful... start postprocessing. batch2() won't call nextSource() again if postprocess()
            // stops generating new Sources...
            targets.clear();
            targets.addAll(sources);
            count = targets.size();
        }
        else if (count == 0 && isDone != sources.size())
        {
            // problem...
            //
            // 1. detect circular inheritance
            // 2. what else?
//            for (Iterator iter = notDoneList.entrySet().iterator(); iter.hasNext();)
//            {
//                Entry entry = (Entry)iter.next();
//                System.out.println("Did not finish compiling " + entry.getKey().toString());
//            }
            detectCycles(sources, igraph);
            assert ThreadLocalToolkit.errorCount() > 0 : "There is a problem in one of the compiler algorithms. Please use --conservative=true to compile. Also, please file a bug report.";
        }

        // C: sources.size() == targets.size() when this returns.
        return count;
    }

    private static double calculateBudget(Source s, int factor)
    {
        String mimeType = s.getMimeType();

        if (MimeMappings.MXML.equals(mimeType))
        {
            return s.size() * 4.5 / factor;
        }
        else if (MimeMappings.AS.equals(mimeType))
        {
            return s.size() / factor;
        }
        else
        {
            return 0;
        }
    }

    /**
     * Calculate a mask that tracks a class of types'
     * progress through the workflow.
     * @param type_class - the type class.
     * @pre type_class must be INHERITANCE, NAMESPACES, TYPES, or EXPRESSIONS.
     * @param workflow - the desired workflow state.
     * @pre workflow must be parse2, analyze2, analyze3, or analyze4.
     * @return a bit mask with a bit set to the type class/workflow pair's position in a CompilationUnit's checkBits flag.
     * @see check, which calls this method and sets flags in checkBits
     * @see checkDeep, which calls this method and sets flags in checkBits
     * @see unitsReset, which clears flags in checkBits when a CompilationUnit hasn't finished compiling.
     */
    private static int calculateCheckBitsMask(int type_class, int workflow)
    {
      //  Compute the base shift in the flag for
      //  this type class.  Each type class has
      //  four flag bits, and the shift is zero-based.
      assert(INHERITANCE == type_class || NAMESPACES == type_class || TYPES == type_class || EXPRESSIONS == type_class);
        int type_class_base_shift = (type_class - 1) * 4;
        //  The four available bit positions each track
        //  a specific workflow phase.
        int workflow_offset = 0;

        switch (workflow)
        {
            case parse2: workflow_offset = 0; break;
            case analyze2: workflow_offset = 1; break;
            case analyze3: workflow_offset = 2; break;
            case analyze4: workflow_offset = 3; break;
            default: assert false;
        }

        return 1 << (type_class_base_shift + workflow_offset);
    }

    private static boolean check(CompilationUnit unit, int typesId, Set<Name> types, SymbolTable symbolTable, int workflow)
    {
        int mask = calculateCheckBitsMask(typesId, workflow);

        if ((unit.checkBits & mask) > 0)
        {
            return true;
        }

        for (Iterator<Name> i = types.iterator(); i.hasNext();)
        {
            Name name = i.next();

            if (name instanceof QName)
            {
                QName qName = (QName) name;
                Source s = symbolTable.findSourceByQName(qName);
                CompilationUnit u = (s != null) ? s.getCompilationUnit() : null;

                // a compilation unit should not have itself as the dependency.
                // let's continue and let the compiler catch the problem later.
                if (unit == u)
                {
                    continue;
                }

                // workflow
                if (u == null || (u.getWorkflow() & workflow) == 0)
                {
                    return false;
                }

                // type info
                if (u == null || u.typeInfo == null)
                {
                    return false;
                }

                // error count
                if (s.getLogger() != null && s.getLogger().errorCount() > 0)
                {
                    return false;
                }
            }
        }

        unit.checkBits |= mask;
        return true;
    }

    // For CompilationUnit.inheritance
    private static boolean checkInheritance(CompilationUnit unit, Set<Name> types, SymbolTable symbolTable, int workflow, Set<String> processed)
    {
        // 1. inheritance

        // Don't short circuit if the CompilationUnit has already been
        // checked, because we still need to check the rest of the
        // inheritance tree.  This is due to possibility that there is
        // an mxml document, which has been reset, higher up the
        // chain.  We want to return false in that case, so we don't
        // let the CompilationUnit continue to the next phase until
        // the mxml document catches back up.

        processed.add(unit.getSource().getName());

        if (!check(unit, INHERITANCE, types, symbolTable, workflow))
        {
            return false;
        }

        for (Iterator<Name> i = types.iterator(); i.hasNext();)
        {
            Name name = i.next();

            if (name instanceof QName)
            {
                QName qName = (QName) name;
                Source s = symbolTable.findSourceByQName(qName);
                CompilationUnit u = (s != null) ? s.getCompilationUnit() : null;

                if (u == null)
                {
                    return false;
                }

                // a compilation unit should not have itself as the dependency.
                // let's continue and let the compiler catch the problem later.
                if (unit == u || processed.contains(s.getName()))
                {
                    continue;
                }

                if (!checkInheritance(u, u.inheritance, symbolTable, workflow, processed))
                {
                    return false;
                }
            }
        }

        return true;
    }

    // For CompilationUnit.types and CompilationUnit.expressions
    private static boolean checkDeep(CompilationUnit unit, int typesId, Set<Name> types, SymbolTable symbolTable, Set<String> processed)
    {
        // 3. types, 4. expressions
        int mask = calculateCheckBitsMask(typesId, analyze3);

        if ((unit.checkBits & mask) > 0)
        {
            return true;
        }

        processed.add(unit.getSource().getName());

        if (!check(unit, typesId, types, symbolTable, analyze3))
        {
            return false;
        }

        for (Iterator<Name> i = types.iterator(); i.hasNext();)
        {
            Name name = i.next();

            if (name instanceof QName)
            {
                QName qName = (QName) name;
                Source s = symbolTable.findSourceByQName(qName);
                CompilationUnit u = (s != null) ? s.getCompilationUnit() : null;

                if (u == null)
                {
                    return false;
                }

                // a compilation unit should not have itself as the dependency.
                // let's continue and let the compiler catch the problem later.
                if (unit == u || processed.contains(s.getName()))
                {
                    continue;
                }

                if (!checkDeep(u, INHERITANCE, u.inheritance, symbolTable, processed))
                {
                    return false;
                }

                if (!checkDeep(u, TYPES, u.types, symbolTable, processed))
                {
                    return false;
                }

                if (!checkDeep(u, EXPRESSIONS, u.expressions, symbolTable, processed))
                {
                    return false;
                }
            }
        }

        unit.checkBits |= mask;
        return true;
    }

    private static int getCompilationUnitWorkflow(Source s)
    {
        if (!s.isPreprocessed())
        {
            return 0;
        }
        else if (s.getCompilationUnit() == null || (s.getCompilationUnit().getWorkflow() & parse1) == 0)
        {
            return preprocess;
        }
        else
        {
            return s.getCompilationUnit().getWorkflow();
        }
    }

    private static void batch(List<Source> sources, List<CompilationUnit> units, DependencyGraph<CompilationUnit> igraph, DependencyGraph<Source> dgraph, SymbolTable symbolTable,
                              SubCompiler[] compilers, SourceList sourceList, SourcePath sourcePath, ResourceContainer resources,
                              CompilerSwcContext swcContext, Configuration configuration, boolean useFileSpec)
        throws CompilerException
    {
        do
        {
            units.clear();
            if (useFileSpec || configuration.getCompilerConfiguration().useConservativeAlgorithm())
            {
                batch1(sources, units, igraph, dgraph, symbolTable, compilers, sourceList, sourcePath, resources, swcContext, configuration);
            }
            else
            {
                batch2(sources, units, igraph, dgraph, symbolTable, compilers, sourceList, sourcePath, resources, swcContext, configuration);
            }
      symbolTable.perCompileData.reuse();

            if (swcContext.errorLocations().size() > 0)
            {
                for (Iterator it = swcContext.errorLocations().iterator(); it.hasNext();)
                {
                    ThreadLocalToolkit.log(new IncompatibleSWCArchive((String) it.next()));
                }
            }

            if (ThreadLocalToolkit.errorCount() > 0)
            {
                throw new CompilerException();
            }

            if (forcedToStop()) break;
        }
        while (unitsReset(units) > 0);
    }

    public static List<CompilationUnit>
                       compileSwc(FileSpec fileSpec,
                                  Collection<Source> classes,
                                  SourcePath sourcePath,
                                  ResourceContainer resources,
                                  ResourceBundlePath bundlePath,
                                  CompilerSwcContext swcContext,
                                  SymbolTable symbolTable,
                                  NameMappings nameMappings,
                                  Configuration configuration,
                                  SubCompiler[] compilers,
                                  PreLink preLink,
                                  Map licenseMap)
        throws CompilerException
    {
        return compile(fileSpec,
                       null,
                       classes,
                       sourcePath,
                       resources,
                       bundlePath,
                       swcContext,
                       symbolTable,
                       nameMappings,
                       configuration,
                       compilers,
                       preLink,
                       licenseMap,
                       new ArrayList<Source>());
    }

    public static List<CompilationUnit>
                       compile(FileSpec fileSpec,
                               SourceList sourceList,
                               SourcePath sourcePath,
                               ResourceContainer resources,
                               ResourceBundlePath bundlePath,
                               CompilerSwcContext swcContext,
                               SymbolTable symbolTable,
                               NameMappings nameMappings,
                               Configuration configuration,
                               SubCompiler[] compilers,
                               PreLink preLink,
                               Map licenseMap)
        throws CompilerException
    {
        return compile(fileSpec,
                       sourceList,
                       null,
                       sourcePath,
                       resources,
                       bundlePath,
                       swcContext,
                       symbolTable,
                       nameMappings,
                       configuration,
                       compilers,
                       preLink,
                       licenseMap,
                       new ArrayList<Source>());
    }

    // full compilation
    public static List<CompilationUnit>
                       compile(FileSpec fileSpec,
                               SourceList sourceList,
                               Collection<Source> classes,
                               SourcePath sourcePath,
                               ResourceContainer resources,
                               ResourceBundlePath bundlePath,
                               CompilerSwcContext swcContext,
                               NameMappings nameMappings,
                               Configuration configuration,
                               SubCompiler[] compilers,
                               PreLink preLink,
                               Map licenseMap,
                               List<Source> sources)
        throws CompilerException
    {
        return compile(fileSpec,
                       sourceList,
                       classes,
                       sourcePath,
                       resources,
                       bundlePath,
                       swcContext,
                       new SymbolTable(configuration),
                       nameMappings,
                       configuration,
                       compilers,
                       preLink,
                       licenseMap,
                       sources);
    }

    // incremental compilation
    public static List<CompilationUnit>
                       compile(FileSpec fileSpec,
                               SourceList sourceList,
                               Collection<Source> classes,
                               SourcePath sourcePath,
                               ResourceContainer resources,
                               ResourceBundlePath bundlePath,
                               CompilerSwcContext swcContext,
                               SymbolTable symbolTable,
                               NameMappings nameMappings,
                               Configuration configuration,
                               SubCompiler[] compilers,
                               PreLink preLink,
                               Map licenseMap,
                               List<Source> sources)
        throws CompilerException
    {
        Set<IPreCompileExtension> extensions =
            ExtensionManager.getPreCompileExtensions( configuration.getCompilerConfiguration().getExtensionsConfiguration().getExtensionMappings() );
        for ( IPreCompileExtension extension : extensions )
        {
            extension.run( fileSpec, sourceList, classes, sourcePath, resources, bundlePath, swcContext,
                           new SymbolTable(configuration), configuration, compilers, preLink, licenseMap,
                           sources );
        }
       
        if ( configuration.getCompilerConfiguration().getJavaProfilerClass() != null )
        {
            macromedia.asc.util.ProfileController.setProfiler(configuration.getCompilerConfiguration().getJavaProfilerClass());
            macromedia.asc.util.ProfileController.startAllocationRecording();
            macromedia.asc.util.ProfileController.startCPUProfiling(true); // sampling mode
        }
       
        // C: display any SourcePath-related warnings before starting to compile.
        if (sourcePath != null)
        {
            ThreadLocalToolkit.getPathResolver().addSinglePathResolver(sourcePath);
            sourcePath.displayWarnings();
        }

        ThreadLocalToolkit.setCompatibilityVersion(configuration.getCompatibilityVersion());

        StandardDefs standardDefs = StandardDefs.getStandardDefs(configuration.getFramework());
        ThreadLocalToolkit.setStandardDefs(standardDefs);

        LocalizationManager l10n = ThreadLocalToolkit.getLocalizationManager();

        if (configuration.getBenchmarkCompilerDetails() > 0 &&
                ThreadLocalToolkit.getBenchmark() != null)
        {
            ThreadLocalToolkit.getBenchmark().benchmark2(l10n.getLocalizedTextString(new CompileTime("Start")), true);
        }

        ProgressMeter meter = ThreadLocalToolkit.getProgressMeter();

        if (meter != null)
        {
            meter.start();
        }

        List<CompilationUnit> units = new ArrayList<CompilationUnit>();
        DependencyGraph<CompilationUnit> igraph = new DependencyGraph<CompilationUnit>();
        DependencyGraph<Source> dgraph = null; // new DependencyGraph();

        boolean useFileSpec = false;

        // based on the starting source file, retrieve a list of dependent files.
        if (fileSpec != null)
        {
            sources.addAll(fileSpec.retrieveSources());
            useFileSpec = sources.size() > 0;
        }

        if (sourceList != null)
        {
            sources.addAll(sourceList.retrieveSources());
        }

        // C: This is here for SWC compilation.
        if (classes != null)
        {
            for (Source source : classes)
            {
                // source might have already been added if it's in the SourceList.
                if (!sources.contains(source))
                {
                    sources.add(source);
                }
            }

            useFileSpec = useFileSpec || classes.size() > 0;
        }

        // add the sources to the dependency graphs as vertices.
        addVerticesToGraphs(sources, igraph, dgraph);

        if (configuration.getBenchmarkCompilerDetails() > 0 &&
                ThreadLocalToolkit.getBenchmark() != null)
        {
            ThreadLocalToolkit.getBenchmark().benchmark2(l10n.getLocalizedTextString(new CompileTime("addVerticesToGraphs")), true);
        }

        try
        {
            getCommonBuiltinClasses(sources, igraph, dgraph, symbolTable, sourceList, sourcePath, resources, swcContext);

            if (configuration.getBenchmarkCompilerDetails() > 0 &&
                    ThreadLocalToolkit.getBenchmark() != null)
            {
                ThreadLocalToolkit.getBenchmark().benchmark2(l10n.getLocalizedTextString(new CompileTime("GetCommonBuiltInClassesTime")), true);
            }

            //    build unit list
            batch(sources, units, igraph, dgraph, symbolTable, compilers, sourceList, sourcePath, resources, swcContext, configuration, useFileSpec);

            if (configuration.getBenchmarkCompilerDetails() > 0 &&
                    ThreadLocalToolkit.getBenchmark() != null)
            {
                ThreadLocalToolkit.getBenchmark().benchmark2(l10n.getLocalizedTextString(new CompileTime("batch")));

            }

            // enterprise messaging classes referenced by the messaging config file
            getMessagingClasses(sources, igraph, dgraph, symbolTable, sourceList, sourcePath, resources, swcContext, configuration);

            if (configuration.getBenchmarkCompilerDetails() > 0 &&
                    ThreadLocalToolkit.getBenchmark() != null)
            {
                ThreadLocalToolkit.getBenchmark().benchmark2(l10n.getLocalizedTextString(new CompileTime("getMessagingClasses")), true);
            }

            // unconditionally includes classes specified by --includes.
            getIncludeClasses(sources, igraph, dgraph, symbolTable, sourceList, sourcePath, resources, swcContext, configuration);

            if (configuration.getBenchmarkCompilerDetails() > 0 &&
                    ThreadLocalToolkit.getBenchmark() != null)
            {
                ThreadLocalToolkit.getBenchmark().benchmark2(l10n.getLocalizedTextString(new CompileTime("GetIncludeClassesTime")), true);
            }

            // backward compatibility
            getIncludeResources(sources, igraph, dgraph, bundlePath, symbolTable, swcContext, configuration);

            if (configuration.getBenchmarkCompilerDetails() > 0 &&
                    ThreadLocalToolkit.getBenchmark() != null)
            {
                ThreadLocalToolkit.getBenchmark().benchmark2(l10n.getLocalizedTextString(new CompileTime("GetIncludeResourcesTime")), true);
            }

            // getMessagingClasses, and getIncludeClasses may produce errors. check them...
            if (ThreadLocalToolkit.errorCount() > 0)
            {
                throw new CompilerException();
            }

            if (forcedToStop()) return units;

            // compile additional sources before running prelink so that all metadata-fed lists
            // contributing to codegen (i.e. mixins) are complete
            batch(sources, units, igraph, dgraph, symbolTable, compilers, sourceList, sourcePath, resources, swcContext, configuration, useFileSpec);

            if (configuration.getBenchmarkCompilerDetails() > 0 &&
                    ThreadLocalToolkit.getBenchmark() != null)
            {
                ThreadLocalToolkit.getBenchmark().benchmark2(l10n.getLocalizedTextString(new CompileTime("batch")), true);

            }

            if (forcedToStop()) return units;

            // PreLink

            int count = 0; // just in case something impossibly odd happens,
            if (preLink != null// don't wedge the compiler forever.
            {
                // run the prelink step (repeatedly until we've found all nested style dependencies...)
                boolean runPrelink = true;
                while (runPrelink && count++ < 1000)
                {
                    runPrelink = preLink.run(sources, units, fileSpec, sourceList, sourcePath, bundlePath, resources, symbolTable, swcContext, nameMappings, configuration);
                    if (!runPrelink)
                    {
                        // Add synthetic link-in units now that we've found all of our sources
                        preLink.postRun(sources, units, resources, symbolTable, swcContext, nameMappings, configuration);
                    }

                    if (configuration.getBenchmarkCompilerDetails() > 0 &&
                            ThreadLocalToolkit.getBenchmark() != null)
                    {
                        ThreadLocalToolkit.getBenchmark().benchmark2(l10n.getLocalizedTextString(new CompileTime("PreLinkTime")), true);
                    }

                    // prelink also may produce errors
                    if (ThreadLocalToolkit.errorCount() > 0)
                    {
                        throw new CompilerException();
                    }

                    // prelink introduces more sources, so we compile again
                    batch(sources, units, igraph, dgraph, symbolTable, compilers, sourceList, sourcePath, resources, swcContext, configuration, useFileSpec);

                    if (configuration.getBenchmarkCompilerDetails() > 0 &&
                            ThreadLocalToolkit.getBenchmark() != null)
                    {
                        ThreadLocalToolkit.getBenchmark().benchmark2(l10n.getLocalizedTextString(new CompileTime("batch")), true);
                    }

                    if (forcedToStop()) return units;
                }
            }

            // loader classes, licensing classes, extra classes

            count = 0; // just in case something impossibly odd happens,
            while (++count < 1000) // don't wedge the compiler forever.
            {
                int numSources = sources.size();
                getExtraSources(sources, igraph, dgraph, sourceList, sourcePath, resources, bundlePath, symbolTable, swcContext,
                                configuration, licenseMap);

                if (configuration.getBenchmarkCompilerDetails() > 0 &&
                        ThreadLocalToolkit.getBenchmark() != null)
                {
                    ThreadLocalToolkit.getBenchmark().benchmark2(l10n.getLocalizedTextString(new CompileTime("GetExtraSourcesTime")), true);
                }

                // getExtraSources may produce errors. check them...
                if (ThreadLocalToolkit.errorCount() > 0)
                {
                    throw new CompilerException();
                }

                // getExtraSources pulls in more classes, compile again
                batch(sources, units, igraph, dgraph, symbolTable, compilers, sourceList, sourcePath, resources, swcContext, configuration, useFileSpec);

                if (configuration.getBenchmarkCompilerDetails() > 0 &&
                        ThreadLocalToolkit.getBenchmark() != null)
                {
                    ThreadLocalToolkit.getBenchmark().benchmark2(l10n.getLocalizedTextString(new CompileTime("batch")), true);

                }

                if (sources.size() == numSources)
                {
                    break;
                }

                if (forcedToStop()) return units;
            }

            checkResourceBundles(sources, symbolTable);
            assert count < 1000;
        }
        finally
        {
            if (ThreadLocalToolkit.getBenchmark() != null)
            {
                ThreadLocalToolkit.getBenchmark().benchmark(l10n.getLocalizedTextString(new OutputTime(sources.size())));
            }

            // must close swc file handles...
            swcContext.close();
            symbolTable.cleanClassTable();
            symbolTable.adjustProgress();

            if (meter != null)
            {
                meter.end();
            }
        }

        return units;
    }

    private static final MultiName[] multiNames = new MultiName[]
    {
        new MultiName(SymbolTable.OBJECT),
        new MultiName(SymbolTable.CLASS),
        new MultiName(SymbolTable.FUNCTION),
        new MultiName(SymbolTable.BOOLEAN),
        new MultiName(SymbolTable.NUMBER),
        new MultiName(SymbolTable.STRING),
        new MultiName(SymbolTable.ARRAY),
        new MultiName(SymbolTable.INT),
        new MultiName(SymbolTable.UINT),
        new MultiName(SymbolTable.NAMESPACE),
        new MultiName(SymbolTable.REGEXP),
        new MultiName(SymbolTable.XML),
        new MultiName(SymbolTable.XML_LIST),
    };

    private static void getCommonBuiltinClasses(List<Source> sources, DependencyGraph<CompilationUnit> igraph, DependencyGraph<Source> dgraph,
                                                SymbolTable symbolTable, SourceList sourceList, SourcePath sourcePath,
                                                ResourceContainer resources, CompilerSwcContext swcContext)
    {
        for (int i = 0, size = multiNames.length; i < size; i++)
        {
            QName qName = resolveMultiName("builtin", multiNames[i], sources, sourceList, sourcePath, resources, swcContext, symbolTable);
            if (qName != null)
            {
                Source tailSource = symbolTable.findSourceByQName(qName);
                addVertexToGraphs(tailSource, tailSource.getCompilationUnit(), igraph, dgraph);
            }
        }
    }

    private static void getMessagingClasses(List<Source> sources, DependencyGraph<CompilationUnit> igraph, DependencyGraph<Source> dgraph,
                                            SymbolTable symbolTable, SourceList sourceList, SourcePath sourcePath,
                                            ResourceContainer resources, CompilerSwcContext swcContext,
                                            Configuration configuration)
    {
        // The enterprise messaging config file may refer to some classes. We want to load them up-front.
        ServicesDependenciesWrapper services = configuration.getCompilerConfiguration().getServicesDependencies();
        if (services != null)
        {
            for (Iterator i = services.getChannelClasses().iterator(); i.hasNext();)
            {
                String clientType = (String) i.next();

                if (clientType != null)
                {
                    QName qName = resolveMultiName("messaging", new MultiName(NameFormatter.toColon(clientType)), sources,
                                                   sourceList, sourcePath, resources, swcContext, symbolTable);

                    if (qName == null)
                    {
                        ThreadLocalToolkit.log(new ChannelDefinitionNotFound(clientType),
                                               configuration.getCompilerConfiguration().getServices().getNameForReporting());
                    }
                    else
                    {
                        Source s = symbolTable.findSourceByQName(qName);
                        addVertexToGraphs(s, s.getCompilationUnit(), igraph, dgraph);
                    }
                }
            }
        }
    }

    /**
     * reset non-internal units that have failed to produce bytecode.
     * NOTE: contract is that all units from non-internal sources will eventually produce either bytecode or an error,
     * after a finite number of resets.
     */
    private static int unitsReset(List<CompilationUnit> units)
    {
        int resetCount = 0;
        for (int i = 0, n = units.size(); i < n; i++)
        {
            CompilationUnit unit = units.get(i);
            Source source = unit.getSource();

            if (!source.isInternal() && !source.isCompiled())
            {
                unit.reset();
                resetCount++;
            }
            else if (!source.isInternal())
            {
                unit.checkBits = 0;
            }
        }
        return resetCount;
    }

    /**
     * Report cached SWC sources, which have been obsoleted by a newer
     * definition from another SWC.
     */
    private static void reportObsoletedSwcSources(CompilerSwcContext swcContext,
                                                  LocalizationManager l10n,
                                                  Logger logger)
    {
        for (Entry<Source, String> entry : swcContext.getObsoletedSources().entrySet())
        {
            Source obsoletedSource = entry.getKey();
            String obsoletedSourceName = obsoletedSource.getName();
            String newLocation = entry.getValue();
            String message = l10n.getLocalizedTextString(new SwcDefinitionObsoleted(newLocation));
            logger.needsCompilation(obsoletedSourceName, message);
        }
    }

    /**
     * Report cached SWC sources, which will be shadowed by a Source
     * in the source path, source list, or resource container.
     */
    private static void reportShadowedSwcSources(Set<Source> swcSources, SourceList sourceList,
                                                 SourcePath sourcePath, ResourceContainer resources,
                                                 LocalizationManager l10n, Logger logger,
                                                 Set<Source> sources)
    {
        for (Source source : swcSources)
        {
            CompilationUnit compilationUnit = source.getCompilationUnit();

            for (QName qName : compilationUnit.topLevelDefinitions)
            {
                Source newSource = null;

                if (sourceList != null)
                {
                    newSource = sourceList.findSource(qName.getNamespace(), qName.getLocalPart());
                }

                if ((newSource == null) && (sourcePath != null))
                {
                    try
                    {
                        newSource = sourcePath.findSource(qName.getNamespace(), qName.getLocalPart());
                    }
                    catch (CompilerException compilerException)
                    {
                        // handle this downstream.
                    }
                }

                if ((newSource == null) && (resources != null))
                {
                    newSource = resources.findSource(qName.getNamespace(), qName.getLocalPart());
                }

                if ((newSource != null) &&
                    (newSource != source) &&
                    (newSource.getLastModified() != source.getLastModified()))
                {
                    String message = l10n.getLocalizedTextString(new SwcDefinitionObsoleted(newSource.getName()));
                    logger.needsCompilation(source.getName(), message);
                    sources.remove(source);
                }
            }
        }
    }

    /**
     * For use by application compilations.
     */
    public static int validateCompilationUnits(FileSpec fileSpec, SourceList sourceList, SourcePath sourcePath,
                                               ResourceBundlePath bundlePath, ResourceContainer resources,
                                               CompilerSwcContext swcContext, ContextStatics perCompileData,
                                               Configuration configuration)
    {
        return validateCompilationUnits(fileSpec, sourceList, sourcePath, bundlePath, resources, swcContext,
                                        null, perCompileData, configuration);
    }

    /**
     * For use by library compilations.
     */
    public static int validateCompilationUnits(FileSpec fileSpec, SourceList sourceList, SourcePath sourcePath,
                                               ResourceBundlePath bundlePath, ResourceContainer resources,
                                               CompilerSwcContext swcContext, Map<String, Source> includedClasses,
                                               ContextStatics perCompileData, Configuration configuration)
    {
        final LocalizationManager l10n = ThreadLocalToolkit.getLocalizationManager();

        final boolean strict = configuration.getCompilerConfiguration().strict();

        final Map<String, Source>
                  updated                     = new HashMap<String, Source>(), // VirtualFile.getName() -> Source
                  updatedWithStableSignature  = new HashMap<String, Source>(), // VirtualFile.getName() -> Source
                  affected                    = new HashMap<String, Source>(); // VirtualFile.getName() -> Source

        final Map<QName, Source> deleted = new HashMap<QName, Source>();

        final Map<String, String> reasons = new HashMap<String, String>(); // VirtualFile.getName() -> String
        final Map<QName, Source> qNames = new HashMap<QName, Source>();

        final Set<String> includeUpdated      = new HashSet<String>(),         // VirtualFile.getName()
                  resourceDelegates           = new HashSet<String>(),         // VirtualFile.getNameForReporting()
                  namespaces                  = new HashSet<String>();

        final Map<QName, Map<String, Source>> dependents = new HashMap<QName, Map<String, Source>>();

        Set<Source> swcSources = swcContext.cachedSources();
        Context ascContext = null;

        if (perCompileData != null)
        {
            ascContext = new Context(perCompileData);
        }

        // put all the Source objects together
        final Set<Source> sources = new HashSet<Source>();
        {
            sources.addAll(swcSources);
            if (fileSpec != null)
                sources.addAll(fileSpec.sources());
            if (sourceList != null)
                sources.addAll(sourceList.sources().values());
            if (sourcePath != null)
                sources.addAll(sourcePath.sources().values());
            if (bundlePath != null)
                sources.addAll(bundlePath.sources().values());
            if (includedClasses != null)
                sources.addAll(includedClasses.values());
        }

        // build a dependency graph
        for (Source source : sources)
        {
            if (source.getName() == null)
            {
                continue;
            }

            CompilationUnit u = source.getCompilationUnit();

            if (u == null)
            {
                continue;
            }

            // collect the names of all the update file includes...
            for (Iterator j = source.getUpdatedFileIncludes(); j != null && j.hasNext();)
            {
                VirtualFile f = (VirtualFile) j.next();
                includeUpdated.add(f.getNameForReporting());
            }

            // register QName --> VirtualFile.getName()
            for (QName qName : u.topLevelDefinitions)
            {
                qNames.put(qName, source);
                dependents.put(qName, new HashMap<String, Source>());
            }
        }

        for (Source source : resources.sources().values())
        {
            if (source.getName() == null)
            {
                continue;
            }

            CompilationUnit u = source.getCompilationUnit();

            if (u == null)
            {
                continue;
            }

            // register QName --> VirtualFile.getName()
            for (QName qName : u.topLevelDefinitions)
            {
                qNames.put(qName, source);
            }
        }

        // setup inheritance-based dependencies...
        for (Source source : sources)
        {
            if (source == null) continue;

            CompilationUnit u = source.getCompilationUnit();
            if (u == null) continue;

            addDependents(source, u.inheritance, dependents);
            addDependents(source, u.namespaces, dependents);
            addDependents(source, u.types, dependents);
            addDependents(source, u.expressions, dependents);
        }

        Logger logger = ThreadLocalToolkit.getLogger();

        // if any of the Source objects in ResourceContainer is bad, obsolete the originating Source.
        for (Source source : resources.sources().values())
        {
            CompilationUnit u = source.getCompilationUnit();
            if (source.hasError() ||
                (u != null && !u.isDone() && !u.hasTypeInfo) ||
                source.isUpdated() ||
                (u != null && u.hasAssets() && u.getAssets().isUpdated()))
            {
                resourceDelegates.add(source.getNameForReporting());
                source.removeCompilationUnit();
            }
        }

        reportObsoletedSwcSources(swcContext, l10n, logger);
        reportShadowedSwcSources(swcSources, sourceList, sourcePath, resources, l10n, logger, sources);

        // identify obsolete CompilationUnit
        //   - NotFullyCompiled
        //   - SourceNoLongerExists
        //   - SourceFileUpdated
        //   - AssedUpdated
        for (Iterator<Source> iterator = sources.iterator(); iterator.hasNext();)
        {
            Source s = iterator.next();
            CompilationUnit u = s.getCompilationUnit();

            // Sources for internal classes like Object never reach the done state or have typeInfo.
            if (s.hasError() ||
                (!s.isInternal() && (u != null && !u.isDone() && !u.hasTypeInfo)) ||
                resourceDelegates.contains(s.getName()))
            {
                affected.put(s.getName(), s);
                reasons.put(s.getName(), l10n.getLocalizedTextString(new NotFullyCompiled()));
                iterator.remove();
            }
            else if (!s.exists())
            {
                updated.put(s.getName(), s);
                reasons.put(s.getName(), l10n.getLocalizedTextString(new SourceNoLongerExists()));

                if (u != null)
                {
                    for (QName qName : u.topLevelDefinitions)
                    {
                        namespaces.add(qName.toString());
                        deleted.put(qName, s);
                    }
                }

                iterator.remove();
            }
            else if (s.isUpdated())
            {
                // signature optimization:
                //     read the old signature from the incremental cache
                //     generate a new signature from the current source
                //     compare -- if stable, we don't have to recompile dependencies
                boolean signatureIsStable = false;
                if ((u != null) &&
                    (!configuration.getCompilerConfiguration().getDisableIncrementalOptimizations()) &&
                    // skip MXML sources:
                    //      MXML is too complicated to parse/codegen at this point in
                    //      order to generate and compare a new checksum
                    (!s.getMimeType().equals(MimeMappings.MXML)))
                {
                    final Long persistedCRC = u.getSignatureChecksum();
                    if (persistedCRC != null)
                    {
                        assert (s.getMimeType().equals(MimeMappings.ABC) ||
                                s.getMimeType().equals(MimeMappings.AS));

                        //TODO if we calculate a new checksum that does not match,
                        //     can we store this checksum and not recompute it later?
                        final Long currentCRC = computeSignatureChecksum(configuration, s);
                        signatureIsStable = (currentCRC != null) &&
                                            (persistedCRC.compareTo(currentCRC) == 0);

                        // if (SignatureExtension.debug)
                        // {
                        //     final String name = u.getSource().getName();
                        //     SignatureExtension.debug("*** FILE UPDATED: Signature "
                        //                                    + (signatureIsStable ? "IS" : "IS NOT")
                        //                                    + " stable ***");
                        //     SignatureExtension.debug("PERSISTED CRC32: " + persistedCRC + "\t--> " + name);
                        //     SignatureExtension.debug("CURRENT   CRC32: " + currentCRC   + "\t--> " + name);
                        // }
                    }
                }

                // if the class signature is stable (it has not changed since the last compile)
                // then we can invalidate and recompile the updated unit alone
                // otherwise we default to a chain reaction, invalidating _all_ dependent units
                if (signatureIsStable)
                {
                    updatedWithStableSignature.put(s.getName(), s);
                }
                else
                {
                    updated.put(s.getName(), s);
                }

                reasons.put(s.getName(), l10n.getLocalizedTextString(new SourceFileUpdated()));
                iterator.remove();
            }
            else if (u != null && u.hasAssets() && u.getAssets().isUpdated())
            {
                updated.put(s.getName(), s);
                reasons.put(s.getName(), l10n.getLocalizedTextString(new AssetUpdated()));
                iterator.remove();
            }
        }

        // permanently remove the deleted Source objects from SourcePath
        //
        // Note: this step is currently necessary because the location-updating loop that follows iterates over
        // 'sources', which has had deleted entries remove. So here we iterate directly over the deleted
        // entries. (Note also that 'reasons' already has an entry for this source.)
        //
        for (Source source : deleted.values())
        {
            if (source.isSourcePathOwner())
            {
                SourcePath sp = (SourcePath) source.getOwner();
                sp.removeSource(source);

                if (ascContext != null)
                {
                    CompilationUnit u = source.getCompilationUnit();

                    if (u != null)
                    {
                        for (QName defName : u.topLevelDefinitions)
                        {
                            ascContext.removeUserDefined(defName.toString());
                        }
                    }
                }
            }
        }

        // Examine each Source object in SourcePath or ResourceBundlePath...
        // if a Source object in SourcePath or ResourceBundlePath is no longer the
        // first choice according to findFile, it should be removed... i.e. look for ambiguous sources
        // - NotSourcePathFirstPreference
        for (Iterator<Source> iterator = sources.iterator(); iterator.hasNext();)
        {
            Source s = iterator.next();

            if (s.isSourcePathOwner() || s.isResourceBundlePathOwner())
            {
                SourcePathBase sp = (SourcePathBase) s.getOwner();
                if (!sp.checkPreference(s))
                {
                    affected.put(s.getName(), s);
                    reasons.put(s.getName(), l10n.getLocalizedTextString(new NotSourcePathFirstPreference()));
                    iterator.remove();
                }
            }
        }

        // invalidate the compilation unit if its dependencies are updated or not cached.
        // - DependencyUpdated
        // - DependencyNotCached
        // - InvalidImportStatement
        for (Iterator<Source> iterator = sources.iterator(); iterator.hasNext();)
        {
            Source s = iterator.next();
            CompilationUnit u = s.getCompilationUnit();
            if (u == null) continue;

            Set<Name> dependencies = new HashSet<Name>();
            dependencies.addAll(u.inheritance);
            dependencies.addAll(u.namespaces);
            dependencies.addAll(u.expressions);
            dependencies.addAll(u.types);

            // Every CompilationUnit has "Object" at the top of it's
            // inheritance chain.  As a result, in
            // As3Compiler.analyze2(), we call inheritSlots() on
            // Object's frame, which unfortunately includes lots of
            // other builtins, like String, Number, Namespace, etc.
            // By inheriting slots for these other builtins, they are
            // not reported as unresolved, so they are not recorded as
            // dependencies.  When switching between airglobal.swc and
            // playerglobal.swc in the same workspace, the builtins
            // change, so we need to check for that.  We use
            // "Namespace" to represent the set of builtins.  See
            // SDK-25206.
            dependencies.add(new QName("", "Namespace"));
            boolean valid = true;

            for (Name dependentName : dependencies)
            {
                QName qName = toQName(dependentName);

                if (qName != null)
                {
                    Source dependentSource = qNames.get(qName);

                    if (dependentSource != null)
                    {
                        CompilationUnit dependentCompilationUnit = dependentSource.getCompilationUnit();

                        if (u.hasTypeInfo && !dependentCompilationUnit.hasTypeInfo && !dependentSource.isInternal())
                        {
                            reasons.put(s.getName(), l10n.getLocalizedTextString(new DependencyNotCached(dependentName.toString())));
                            valid = false;
                        }
                        else
                        {
                            // If the dependency hasn't been updated with
                            // a stable signature, check that the two
                            // ObjectValues references the same Slot.  If
                            // they are not, then the referencing
                            // CompilationUnit needs to be recompiled.
                            if (!updatedWithStableSignature.containsKey(dependentSource.getName()) &&
                                (ascContext != null) &&
                                u.hasTypeInfo &&
                                dependentCompilationUnit.hasTypeInfo &&
                                referencesDifferentSlots(ascContext, u.typeInfo, qName, dependentCompilationUnit.typeInfo))
                            {
                                reasons.put(s.getName(), l10n.getLocalizedTextString(new DependencyUpdated(dependentName.toString())));
                                valid = false;
                            }
                        }
                    }
                    else if (u.hasTypeInfo)
                    {
                        reasons.put(s.getName(), l10n.getLocalizedTextString(new DependencyNotCached(dependentName.toString())));
                        valid = false;
                    }
                }

                if (!valid)
                {
                    affected.put(s.getName(), s);
                    iterator.remove();
                    break;
                }
            }

            if (!swcSources.contains(s))
            {
                // only check the following when strict is enabled.
                valid = valid && strict;

                for (Iterator k = u.importPackageStatements.iterator(); valid && k.hasNext();)
                {
                    String packageName = (String) k.next();

                    if (!hasPackage(sourcePath, swcContext, packageName))
                    {
                        affected.put(s.getName(), s);
                        reasons.put(s.getName(), l10n.getLocalizedTextString(new InvalidImportStatement(packageName)));
                        iterator.remove();
                        namespaces.add(packageName);
                        valid = false;
                        break;
                    }
                }

                for (Iterator k = u.importDefinitionStatements.iterator(); valid && k.hasNext();)
                {
                    QName defName = (QName) k.next();

                    if (!hasDefinition(sourcePath, swcContext, defName))
                    {
                        affected.put(s.getName(), s);
                        reasons.put(s.getName(), l10n.getLocalizedTextString(new InvalidImportStatement(defName.toString())));
                        iterator.remove();
                        namespaces.add(defName.toString());
                        valid = false;
                        break;
                    }
                }
            }
        }

        // - DependentFileModified
        if (strict)
        {
            Map<String, Source> updatedAndAffected = new HashMap<String, Source>(updated);
            updatedAndAffected.putAll(affected);

            for (Source source : updatedAndAffected.values())
            {
                dependentFileModified(source, dependents, updated, affected, reasons, sources);
            }
        }

        for (Iterator<String> i = includeUpdated.iterator(); i.hasNext();)
        {
            ThreadLocalToolkit.getLogger().includedFileUpdated(i.next());
        }

        int affectedCount = affected.size();
        logReasonAndRemoveCompilationUnit(affected, reasons, includeUpdated, swcContext);
        logReasonAndRemoveCompilationUnit(updated, reasons, includeUpdated, swcContext);


        // If a source was updated with a stable signature, then we need to seed ASCs userDefined
        // with the definitions from that source.  This is because we will recompile only the source with the stable
        // signature, and none of it's dependents.  Those dependencies will point at the old TypeValues,
        // but new TypeValues will be created when we recompile the source because they weren't in userDefined.  By putting
        // the old TypeValues in userDefined, when the Source is recompiled it will reuse that same TypeValue
        // instance, instead of creating a new one.
        // We do not have to do this for the updated or affected maps, because anything in those will force
        // their dependencies to be recompiled.
        seedUserDefined(updatedWithStableSignature.values(), ascContext, perCompileData);

        logReasonAndRemoveCompilationUnit(updatedWithStableSignature, reasons, includeUpdated, swcContext);

    // if a compilation unit becomes obsolete, its satellite compilation units in ResourceContainer
    // must go away too.
    for (Source s : resources.sources().values())
    {
      if (s != null)
      {
        String name = s.getNameForReporting();
        if (affected.containsKey(name) || updated.containsKey(name))
        {
          s.removeCompilationUnit();
        }
      }
    }

        affected.clear();

        // validate multinames
        // - MultiNameMeaningChanged
        for (Iterator<Source> iterator = sources.iterator(); iterator.hasNext();)
        {
            Source s = iterator.next();
            CompilationUnit u = s.getCompilationUnit();
            if (u == null) continue;

            for (Entry<MultiName, QName> entry : u.inheritanceHistory.entrySet())
            {
                MultiName multiName = entry.getKey();
                QName qName = entry.getValue();

                try
                {
                    if (!validateMultiName(multiName, qName, sourcePath))
                    {
                        affected.put(s.getName(), s);
                        reasons.put(s.getName(), l10n.getLocalizedTextString(new MultiNameMeaningChanged(multiName, qName)));
                        iterator.remove();
                    }
                }
                catch (CompilerException ex)
                {
                    affected.put(s.getName(), s);
                    reasons.put(s.getName(), ex.getMessage());
                    iterator.remove();
                }
            }
        }

        affectedCount += affected.size();

        // remove CompilationUnits from affected Map
        logReasonAndRemoveCompilationUnit(affected, reasons, includeUpdated, swcContext);

    // if a compilation unit becomes obsolete, its satellite compilation units in ResourceContainer
    // must go away too.
    for (Source s : resources.sources().values())
    {
      if (s != null)
      {
        String name = s.getNameForReporting();
        if (affected.containsKey(name))
        {
          s.removeCompilationUnit();
        }
      }
    }

        // refresh the state of ResourceContainer
        resources.refresh();

        // finally, remove the deleted namespaces from SymbolTable...
        if (perCompileData != null)
        {
            for (String ns : namespaces)
            {
                perCompileData.removeNamespace(ns);
            }
        }

        final int updateCount = updated.size() + updatedWithStableSignature.size();
        if (updateCount + affectedCount > 0)
        {
            ThreadLocalToolkit.log(new FilesChangedAffected(updateCount, affectedCount));
        }

        // Any sources left are valid and if they have type info, we
        // need to seed ASC's userDefined with them, so we don't end
        // up with multiple TypeValue copies floating around.  The
        // global SWC cache requires this to be run.
        seedUserDefined(sources, ascContext, perCompileData);

        if (configuration.getBenchmarkCompilerDetails() > 0 &&
            ThreadLocalToolkit.getBenchmark() != null)
        {
            ThreadLocalToolkit.getBenchmark().benchmark2("validateCompilationUnits");
        }

        int count = updateCount + affectedCount;

        return count;
    }

    private static void addDependents(Source source, Set<Name> dependencies,
                                      Map<QName, Map<String, Source>> dependents)
    {
        for (Name name : dependencies)
        {
            QName qName = toQName(name);

            if (qName != null)
            {
                Map<String, Source> sourceMap = dependents.get(qName);

                if (sourceMap != null)
                {
                    sourceMap.put(source.getName(), source);
                }
            }
        }
    }

    private static QName toQName(Name name)
    {
        QName result = null;

        if (name instanceof QName)
        {
            result = (QName) name;
        }
        else if (name instanceof MultiName)
        {
            MultiName multiName = (MultiName) name;
           
            if (multiName.getNumQNames() == 1)
            {
                result = multiName.getQName(0);
            }
        }

        return result;
    }

    private static void dependentFileModified(Source affectedSource,
                                              Map<QName, Map<String, Source>> dependents,
                                              Map<String, Source> updated,
                                              Map<String, Source> affected,
                                              Map<String, String> reasons,
                                              Set<Source> sources)
    {
        LocalizationManager l10n = ThreadLocalToolkit.getLocalizationManager();
        CompilationUnit compilationUnit = affectedSource.getCompilationUnit();

        if (compilationUnit != null)
        {
            for (QName qName : compilationUnit.topLevelDefinitions)
            {
                if (dependents.containsKey(qName))
                {
                    for (Entry<String, Source> dependentEntry : dependents.get(qName).entrySet())
                    {
                        if (!updated.containsKey(dependentEntry.getKey()) &&
                            !affected.containsKey(dependentEntry.getKey()))
                        {
                            affected.put(dependentEntry.getKey(), dependentEntry.getValue());
                            reasons.put(dependentEntry.getKey(),
                                        l10n.getLocalizedTextString(new DependentFileModified(affectedSource.getName())));

                            sources.remove(dependentEntry.getValue());
                            dependentFileModified(dependentEntry.getValue(), dependents, updated, affected, reasons, sources);
                        }
                    }
                }
            }
        }
    }

    /**
     * Helper for validateCompilationUnits(). Removes the CompilationUnit for sources in map,
     * and logs the reasons.
     */
    private static void logReasonAndRemoveCompilationUnit(final Map<String, Source> map,
                                                          final Map<String, String> reasons,
                                                          final Set<String> includeUpdated,
                                                          CompilerSwcContext compilerSwcContext)
    {
        Logger logger = ThreadLocalToolkit.getLogger();

        for (Entry<String, Source> entry : map.entrySet())
        {
            String name = entry.getKey();
            Source s = entry.getValue();

            for (Iterator j = s.getFileIncludes(); j.hasNext();)
            {
                VirtualFile f = (VirtualFile) j.next();
                if (!includeUpdated.contains(f.getNameForReporting()))
                {
                    ThreadLocalToolkit.getLogger().includedFileAffected(f.getNameForReporting());
                }
            }

            CompilationUnit compilationUnit = s.getCompilationUnit();

            if (compilationUnit != null)
            {
                for (QName topLevelDefinition : compilationUnit.topLevelDefinitions)
                {
                    SwcScript swcScript = compilerSwcContext.getCachedScript(topLevelDefinition);

                    // Make sure the SwcScript's cached CompilationUnit isn't reused.
                    if (swcScript != null)
                    {
                        CompilationUnit swcScriptCompilationUnit = swcScript.getCompilationUnit();

                        if (swcScriptCompilationUnit != null)
                        {
                            // SwcContext's getSource() has the side effect of
                            // copying cached type information into a new
                            // Source object, so we need to clean that up too.
                            swcScriptCompilationUnit.getSource().removeCompilationUnit();
                            swcScript.setCompilationUnit(null);
                        }
                    }
                }
            }

            // It might be tempting to only call
            // removeCompilationUnit() if the compilationUnit is not
            // null, but it does more than just remove the
            // compilationUnit.
            s.removeCompilationUnit();

            logger.needsCompilation(s.getName(), reasons.get(s.getName()));
        }
    }

    /**
     * Returns true if the Slot referenced by the two ObjectValue's isn't the same.
     */
    private static boolean referencesDifferentSlots(Context ascContext, ObjectValue referencingTypeInfo,
                                                    QName qName, ObjectValue referencedTypeInfo)
    {
        boolean result = false;
        int kind = Tokens.GET_TOKEN;
        String localPart = qName.getLocalPart().intern();
        ObjectValue namespace = ascContext.getNamespace(qName.getNamespace().intern());
       
        if (referencingTypeInfo.hasName(ascContext, kind, localPart, namespace) &&
            referencedTypeInfo.hasName(ascContext, kind, localPart, namespace))
        {
            int referencingIndex = referencingTypeInfo.getSlotIndex(ascContext, kind, localPart, namespace);
            int referencedIndex = referencedTypeInfo.getSlotIndex(ascContext, kind, localPart, namespace);

            if (referencingIndex != referencedIndex)
            {
                Slot referencingSlot = referencingTypeInfo.getSlot(ascContext, referencingIndex);
                Slot referencedSlot = referencedTypeInfo.getSlot(ascContext, referencedIndex);

                // Types are stored in VariableSlot's as opposed to MethodSlot's.
                if ((referencingSlot instanceof VariableSlot) &&
                    (referencedSlot instanceof VariableSlot) &&
                    (referencingSlot.getValue() != referencedSlot.getValue()))
                {
                    result = true;
                }
            }
        }


        return result;
    }

    /**
     * This method is used to populate ASC's userDefined Map with the typeInfo from a set of sources.
     */
    private static void seedUserDefined(Collection<Source> sources, Context ascContext, ContextStatics perCompileData)
    {
        for (Source s : sources)
        {
            CompilationUnit u = s.getCompilationUnit();

            if ((u != null) && u.hasTypeInfo)
            {
        ObjectValue frame = u.typeInfo;
               
                for (QName topLevelDefinition : u.topLevelDefinitions)
                {
                    String name = topLevelDefinition.getLocalPart().intern();
                    ObjectValue namespace = ascContext.getNamespace(topLevelDefinition.getNamespace().intern());

                    if (frame.hasName(ascContext, Tokens.GET_TOKEN, name, namespace))
                    {
                        int slotId = frame.getSlotIndex(ascContext, Tokens.GET_TOKEN, name, namespace);
                        Slot slot = frame.getSlot(ascContext, slotId);

                        if (slot != null)
                        {
                            int implicitId = frame.getImplicitIndex(ascContext, slotId, Tokens.EMPTY_TOKEN);

                            if ((slotId != implicitId) && (slot instanceof VariableSlot))
                            {
                                Slot implicitSlot = frame.getSlot(ascContext, implicitId);
                                TypeValue typeValue = implicitSlot.getType().getTypeValue();
                                assert topLevelDefinition.toString().equals(typeValue.name.toString()) :
                                "topLevelDefinition = " + topLevelDefinition + ", typeValue = " + typeValue.name.toString();
                                perCompileData.userDefined.put(typeValue.name.toString(), typeValue);
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * Runs the parser over a Source and returns the SignatureChecksum. The Source is copied.
     */
    private static Long computeSignatureChecksum(Configuration configuration, final Source source)
    {
        assert (configuration != null);

        //TODO It would be nice to cache this; it cannot (?) be static, however,
        //     as the Configuration changes. Solution would be a static Map or some fancy logic?
        // temporary compiler to get a syntax tree, for signature generation
        final As3Compiler asc = new As3Compiler(configuration.getCompilerConfiguration());
        asc.addCompilerExtension(SignatureExtension.getInstance());

        // create a new CompilationUnit if no error occur
        // then grab the signature if no signature error occur
        CompilationUnit u = null;

        // this is needed by Source.Resolver.resolve().
        ThreadLocalToolkit.setCompatibilityVersion(configuration.getCompatibilityVersion());

        // this swallows any parse errors -- they will get thrown when the file is
        // officially reparsed for compilation
        final Logger original = ThreadLocalToolkit.getLogger();
        ThreadLocalToolkit.setLogger(new LocalLogger(null));
        {
            final Source tmpSource = asc.preprocess(
                           Source.newSource(source.getBackingFile(),      source.getFileTime(),
                                            source.getPathRoot(),         source.getRelativePath(),
                                            source.getShortName(),        source.getOwner(),
                                            source.isInternal(),          source.isRoot(),
                                            source.isDebuggable(),        source.getFileIncludesSet(),
                                            source.getFileIncludeTimes(), source.getLogger()));

            // HACK: Forcefully disable any chance of signatures getting emitted to
            //       the filesystem -- since this code should be as fast as possible.
            //       Don't worry though, it WILL happen later during re-compilation.
            final String tmp = SignatureExtension.signatureDirectory;
            SignatureExtension.signatureDirectory = null;
            {
                u = asc.parse1(tmpSource, new SymbolTable(configuration));
            }
            SignatureExtension.signatureDirectory = tmp;
        }
        ThreadLocalToolkit.setLogger(original);

        return ((u != null) ? u.getSignatureChecksum() : null);
    }


    private static boolean validateMultiName(MultiName multiName, QName qName, SourcePath sourcePath)
        throws CompilerException
    {
        for (int i = 0, length = multiName.namespaceURI.length; i < length; i++)
        {
            String ns = multiName.namespaceURI[i];
            String name = multiName.localPart;

            // C: findSource() may do a Source.copy()... we don't need Source.copy() in this case.
            Source s = (sourcePath != null) ? sourcePath.findSource(ns, name) : null;
            CompilationUnit u = (s != null) ? s.getCompilationUnit() : null;

            if (u != null)
            {
                ns = u.topLevelDefinitions.first().getNamespace();
            }

            if (s != null && !(qName.getNamespace().equals(ns) && qName.getLocalPart().equals(name)))
            {
                return false;
            }
        }

        return true;
    }

    private static void addVerticesToGraphs(List<Source> sources, DependencyGraph<CompilationUnit> igraph, DependencyGraph<Source> dgraph)
    {
        for (int i = 0, size = sources.size(); i < size; i++)
        {
            Source s = sources.get(i);
            if (s != null)
            {
                addVertexToGraphs(s, s.getCompilationUnit(), igraph, dgraph);
            }
        }
    }

    private static void addVertexToGraphs(Source s, CompilationUnit u, DependencyGraph<CompilationUnit> igraph, DependencyGraph<Source> dgraph)
    {
        String name = s.getName();

        if (u != null || igraph.get(name) == null)
        {
            igraph.put(name, u);
        }

        if (!igraph.containsVertex(name))
        {
            igraph.addVertex(new Vertex<String,CompilationUnit>(name));
        }

        if (dgraph != null)
        {
            dgraph.put(name, s);
            if (!dgraph.containsVertex(name))
            {
                dgraph.addVertex(new Vertex<String,Source>(name));
            }
        }
    }

    private static boolean preprocess(List<Source> sources, flex2.compiler.SubCompiler[] compilers,
                                      int start, int end, boolean suppressWarnings)
    {
        boolean result = true;

        for (int i = start; i < end; i++)
        {
            Source s = sources.get(i);
            if (s.isPreprocessed())
            {
                continue;
            }

            if ((s = preprocess(s, compilers, suppressWarnings)) == null)
            {
                result = false;
            }
            else
            {
                sources.set(i, s);
            }

            if (tooManyErrors())
            {
                ThreadLocalToolkit.log(new TooManyErrors());
                break;
            }

            if (forcedToStop())
            {
                ThreadLocalToolkit.log(new ForcedToStop());
                break;
            }
        }

        return result;
    }

    /**
     * use this to display warnings from the compilation unit list when nothing needs to be recompiled.
     */
    public static void displayWarnings(List units)
    {
        for (int i = 0, size = units == null ? 0 : units.size(); i < size; i++)
        {
            CompilationUnit u = (CompilationUnit) units.get(i);
            Source s = (u != null) ? u.getSource() : null;

            if (s != null && s.getLogger() != null && s.getLogger().warningCount() > 0 && !s.getLogger().isConnected())
            {
                s.getLogger().displayWarnings(ThreadLocalToolkit.getLogger());
            }
        }
    }

    static Source preprocess(Source s, flex2.compiler.SubCompiler[] compilers, boolean suppressWarnings)
    {
        if (!s.isCompiled())
        {
            // C: A fresh or healthy Source should not have a Logger.
            if (s.getLogger() != null && s.getLogger().warningCount() > 0 && !s.getLogger().isConnected() && !suppressWarnings)
            {
                s.getLogger().displayWarnings(ThreadLocalToolkit.getLogger());
            }

            flex2.compiler.SubCompiler c = getCompiler(s, compilers);
            if (c != null)
            {
                Logger original = ThreadLocalToolkit.getLogger();
                // assert !(original instanceof LocalLogger);

                LocalLogger local = new LocalLogger(original, s);
                local.setLocalizationManager(ThreadLocalToolkit.getLocalizationManager());
                s.setLogger(local);
                ThreadLocalToolkit.setLogger(local);

                s = c.preprocess(s);

                ThreadLocalToolkit.setLogger(original);

                if (local.errorCount() > 0)
                {
                    if (s != null)
                    {
                        s.disconnectLogger();
                    }

                    s = null;
                }
                else
                {
                    s.setPreprocessed();
                }
            }
            else
            {
                s = null;
            }
        }

        return s;
    }

    private static boolean parse1(List<Source> sources, List<CompilationUnit> units, DependencyGraph<CompilationUnit> igraph, DependencyGraph<Source> dgraph,
                                 flex2.compiler.SubCompiler[] compilers, SymbolTable symbolTable,
                                 int start, int end)
    {
        boolean result = true;

        for (int i = start; i < end; i++)
        {
            Source s = sources.get(i);
            CompilationUnit u;

            if ((u = parse1(s, compilers, symbolTable)) == null)
            {
                result = false;
                s.disconnectLogger();
            }

            for (int j = units.size(); j < i + 1; j++)
            {
                units.add(null);
            }

            units.set(i, u);

            addVertexToGraphs(s, u, igraph, dgraph);

            calculateProgress(sources, symbolTable);

            if (tooManyErrors())
            {
                ThreadLocalToolkit.log(new TooManyErrors());
                break;
            }

            if (forcedToStop())
            {
                ThreadLocalToolkit.log(new ForcedToStop());
                break;
            }
        }

        return result;
    }

    private static CompilationUnit parse1(Source s, flex2.compiler.SubCompiler[] compilers, SymbolTable symbolTable)
    {
        if (s.isCompiled())
        {
            return s.getCompilationUnit();
        }

        CompilationUnit u = null;
        flex2.compiler.SubCompiler c = getCompiler(s, compilers);
        if (c != null)
        {
            Logger original = ThreadLocalToolkit.getLogger(), local = s.getLogger();
            ThreadLocalToolkit.setLogger(local);

            u = c.parse1(s, symbolTable);

            // reset the logger to the original one...
            ThreadLocalToolkit.setLogger(original);

            if (local.errorCount() == 0)
            {
                symbolTable.registerQNames(u.topLevelDefinitions, u.getSource());

                u.setState(CompilationUnit.SyntaxTree);
                u.setWorkflow(preprocess);
                u.setWorkflow(parse1);
            }
        }

        return u;
    }

    private static boolean parse2(List<Source> sources, flex2.compiler.SubCompiler[] compilers,
                                  SymbolTable symbolTable, int start, int end)
    {
        boolean result = true;

        for (int i = start; i < end; i++)
        {
            Source source = sources.get(i);
            CompilationUnit u = source.getCompilationUnit();

            if ((u.getWorkflow() & parse2) != 0)
            {
                continue;
            }

            if (!parse2(u, compilers, symbolTable))
            {
                result = false;
                u.getSource().disconnectLogger();
            }

            calculateProgress(sources, symbolTable);

            if (tooManyErrors())
            {
                ThreadLocalToolkit.log(new TooManyErrors());
                break;
            }

            if (forcedToStop())
            {
                ThreadLocalToolkit.log(new ForcedToStop());
                break;
            }
        }

        return result;
    }

    private static boolean parse2(List<Source> sources, flex2.compiler.SubCompiler[] compilers, SymbolTable symbolTable)
    {
        return parse2(sources, compilers, symbolTable, 0, sources.size());
    }

    private static boolean parse2(CompilationUnit u, flex2.compiler.SubCompiler[] compilers, SymbolTable symbolTable)
    {
        Source s = u.getSource();

        if (!s.isCompiled())
        {
            flex2.compiler.SubCompiler c = getCompiler(s, compilers);
            if (c != null)
            {
                // C: may use CompilationUnit to reference the local logger so as to minimize
                //    the number of creations...
                Logger original = ThreadLocalToolkit.getLogger(), local = s.getLogger();
                ThreadLocalToolkit.setLogger(local);

                c.parse2(u, symbolTable);
                u.setWorkflow(parse2);
                ThreadLocalToolkit.setLogger(original);

                if (local.errorCount() > 0)
                {
                    return false;
                }
            }
            else
            {
                return false;
            }
        }

        return true;
    }

    private static boolean analyze(List<Source> sources, flex2.compiler.SubCompiler[] compilers,
                                   SymbolTable symbolTable, int phase)
    {
        return analyze(sources, compilers, symbolTable, 0, sources.size(), phase);
    }

    private static boolean analyze(List<Source> sources, flex2.compiler.SubCompiler[] compilers,
                                   SymbolTable symbolTable, int start, int end, int phase)
    {
        boolean result = true;

        for (int i = start; i < end; i++)
        {
            Source source = sources.get(i);
            CompilationUnit u = source.getCompilationUnit();

            if ((phase == 1 && (u.getWorkflow() & analyze1) != 0) ||
                (phase == 2 && (u.getWorkflow() & analyze2) != 0) ||
                (phase == 3 && (u.getWorkflow() & analyze3) != 0) ||
                (phase == 4 && (u.getWorkflow() & analyze4) != 0))
            {
                continue;
            }

            if (!analyze(u, compilers, symbolTable, phase))
            {
                result = false;
                u.getSource().disconnectLogger();
            }

            calculateProgress(sources, symbolTable);

            // C: make sure that Source and CompilationUnit always point to each other.
            assert u.getSource().getCompilationUnit() == u;

            if (tooManyErrors())
            {
                ThreadLocalToolkit.log(new TooManyErrors());
                break;
            }

            if (forcedToStop())
            {
                ThreadLocalToolkit.log(new ForcedToStop());
                break;
            }
        }

        return result;
    }

    private static boolean analyze(CompilationUnit u, flex2.compiler.SubCompiler[] compilers, SymbolTable symbolTable,
                                   int phase)
    {
        Source s = u.getSource();

        if (!s.isCompiled())
        {
            flex2.compiler.SubCompiler c = getCompiler(s, compilers);

            if (c != null)
            {
                // C: may use CompilationUnit to reference the local logger so as to minimize
                //    the number of creations...
                Logger original = ThreadLocalToolkit.getLogger(), local = s.getLogger();
                ThreadLocalToolkit.setLogger(local);

                if (phase == 1)
                {
                    c.analyze1(u, symbolTable);

                    if (local.errorCount() == 0)
                    {
                        // C: check u.topLevelDefinitions...
                        if (s.isSourcePathOwner() || s.isSourceListOwner())
                        {
                            int size = u.topLevelDefinitions.size();
                            if (size > 1)
                            {
                                ThreadLocalToolkit.log(new MoreThanOneDefinition(u.topLevelDefinitions), s);
                            }
                            else if (size < 1)
                            {
                                ThreadLocalToolkit.log(new MustHaveOneDefinition(), s);
                            }
                            else if (s.isSourcePathOwner())
                            {
                                SourcePath owner = (SourcePath) s.getOwner();

                                String[] packages = owner.checkPackageNameDirectoryName(s);
                                if (packages != null)
                                {
                                    ThreadLocalToolkit.log(new WrongPackageName(packages[0], packages[1]), s);
                                }

                                String[] classes = owner.checkClassNameFileName(s);
                                if (classes != null)
                                {
                                    ThreadLocalToolkit.log(new WrongDefinitionName(classes[0], classes[1]), s);
                                }
                            }
                            else if (s.isSourceListOwner())
                            {
                                SourceList owner = (SourceList) s.getOwner();

                                String[] packages = owner.checkPackageNameDirectoryName(s);
                                if (packages != null)
                                {
                                    ThreadLocalToolkit.log(new WrongPackageName(packages[0], packages[1]), s);
                                }

                                String[] classes = owner.checkClassNameFileName(s);
                                if (classes != null)
                                {
                                    ThreadLocalToolkit.log(new WrongDefinitionName(classes[0], classes[1]), s);
                                }
                            }
                        }

                        // symbolTable.registerQNames(u.topLevelDefinitions, u.getSource());
                    }

                    u.setWorkflow(analyze1);
                }
                else if (phase == 2)
                {
                    c.analyze2(u, symbolTable);
                    u.setWorkflow(analyze2);
                }
                else if (phase == 3)
                {
                    c.analyze3(u, symbolTable);
                    u.setWorkflow(analyze3);
                }
                else // phase == 4
                {
                    c.analyze4(u, symbolTable);
                    u.setWorkflow(analyze4);
                }

                ThreadLocalToolkit.setLogger(original);

                if (local.errorCount() > 0)
                {
                    return false;
                }
            }
            else
            {
                return false;
            }
        }

        return true;
    }

    private static void resolveInheritance(List<Source> sources, DependencyGraph<CompilationUnit> igraph, DependencyGraph<Source> dgraph,
                                           SymbolTable symbolTable, SourceList sourceList, SourcePath sourcePath,
                                           ResourceContainer resources, CompilerSwcContext swcContext, int start, int end)
    {
        Set<QName> qNames = new HashSet<QName>();

        for (int i = start; i < end; i++)
        {
            Source source = sources.get(i);
            CompilationUnit u = source.getCompilationUnit();

            if (u == null || u.inheritance.size() == 0)
            {
                continue;
            }

            qNames.clear();

            String head = source.getName();
            String name = source.getNameForReporting();

            for (Iterator<Name> iterator = u.inheritance.iterator(); iterator.hasNext();)
            {
                Name unresolved = iterator.next();

                if (unresolved instanceof MultiName)
                {
                    MultiName mName = (MultiName) unresolved;
                    QName qName = resolveMultiName(name, mName, sources, sourceList, sourcePath, resources, swcContext, symbolTable);

                    if (qName != null)
                    {
                        Source tailSource = symbolTable.findSourceByQName(qName);
                        String tail = tailSource.getName();
                        addVertexToGraphs(tailSource, tailSource.getCompilationUnit(), igraph, dgraph);
                        addEdgeToGraphs(igraph, dgraph, head, tail);
                        qNames.add(qName);
                        u.inheritanceHistory.put(mName, qName);
                        iterator.remove();
                    }
                }
            }

            if (qNames.size() > 0)
            {
                u.inheritance.addAll(qNames);
            }
        }
    }

    private static void resolveNamespace(List<Source> sources, DependencyGraph<CompilationUnit> igraph, DependencyGraph<Source> dgraph,
                                         SymbolTable symbolTable, SourceList sourceList, SourcePath sourcePath,
                                         ResourceContainer resources, CompilerSwcContext swcContext, int start, int end)
    {
        Set<QName> qNames = new HashSet<QName>();

        for (int i = start; i < end; i++)
        {
            Source source = sources.get(i);
            CompilationUnit u = source.getCompilationUnit();

            if (u.namespaces.size() == 0)
            {
                continue;
            }

            qNames.clear();

            String head = source.getName();
            String name = u.getSource().getNameForReporting();

            for (Iterator<Name> iterator = u.namespaces.iterator(); iterator.hasNext();)
            {
                Name unresolved = iterator.next();

                if (unresolved instanceof MultiName)
                {
                    MultiName mName = (MultiName) unresolved;
                    QName qName = resolveMultiName(name, mName, sources, sourceList, sourcePath, resources, swcContext, symbolTable);

                    if (qName != null)
                    {
                        Source tailSource = symbolTable.findSourceByQName(qName);
                        String tail = tailSource.getName();
                        addVertexToGraphs(tailSource, tailSource.getCompilationUnit(), igraph, dgraph);
                        addEdgeToGraphs(null, dgraph, head, tail);
                        qNames.add(qName);
                        u.namespaceHistory.put(mName, qName);
                        iterator.remove();
                    }
                }
            }

            if (qNames.size() > 0)
            {
                u.namespaces.addAll(qNames);
            }
        }
    }

    // this will be set by asdoc. if true source from disk will be preferred over source from swc
    private static boolean skipTimestampCheck = false;
   
    private static int findDefinition(List<Source> sources, SourceList sourceList, SourcePathBase sourcePath,
                                      ResourceContainer resources, CompilerSwcContext swcContext,
                                      String namespaceURI, String localPart)
        throws CompilerException
    {
        Source s = (sourceList != null) ? sourceList.findSource(namespaceURI, localPart) : null;

        if (s == null)
        {
            s = (sourcePath != null) ? sourcePath.findSource(namespaceURI, localPart) : null;
        }

        if (s == null)
        {
            s = (resources != null) ? resources.findSource(namespaceURI, localPart) : null;
        }

        Source swcSource = (swcContext != null) ? swcContext.getSource(namespaceURI, localPart) : null;

        // No sense recompiling the same source file again.
        if ((swcSource != null) &&
            ((s == null) ||
             ((s.getLastModified() == swcSource.getLastModified() && !skipTimestampCheck) &&
              ((s.getCompilationUnit() == null) ||
               (!s.getCompilationUnit().hasTypeInfo)))))
        {
            s = swcSource;
        }

        if (s != null)
        {
            int where = sources.indexOf(s);
            if (where == -1)
            {
                sources.add(s);
                return sources.size() - 1;
            }
            else
            {
                return where;
            }
        }
        else
        {
            return -1;
        }
    }

    private static int findResourceBundle(List<Source> sources, SourceList sourceList, SourcePathBase sourcePath, CompilerSwcContext swcContext,
                                          String[] locales, String namespaceURI, String localPart)
        throws CompilerException
    {
        Source s1, s2, s3;
        VirtualFile o1, o2, o3;
        ResourceFile rf1, rf2, rf3;

        s1 = (sourceList != null) ? sourceList.findSource(namespaceURI, localPart) : null;
        o1 = (s1 != null) ? s1.getBackingFile() : null;

        // already compiled. return...
        if (o1 instanceof InMemoryFile)
        {
            return findResourceBundleHelper(sources, s1);
        }

        rf1 = (ResourceFile) o1;

        if (rf1 != null && rf1.complete())
        {
            return findResourceBundleHelper(sources, s1);
        }
        else
        {
            // rf1 == null || !rf1.complete(), must get rf2...
            s2 = (sourcePath != null) ? sourcePath.findSource(namespaceURI, localPart) : null;
            o2 = (s2 != null) ? s2.getBackingFile() : null;

            // already compiled. return...
            if (rf1 == null && o2 instanceof InMemoryFile)
            {
                return findResourceBundleHelper(sources, s2);
            }
            else if (o2 instanceof InMemoryFile)
            {
                o2 = null;
            }

            rf2 = (ResourceFile) o2;

            if (rf1 != null)
            {
                rf1.merge(rf2);
            }
            else
            {
                rf1 = rf2;
                s1 = s2;
            }
        }

        if (rf1 != null && rf1.complete())
        {
            return findResourceBundleHelper(sources, s1);
        }
        else
        {
            // rf1 == null || !rf1.complete(), must get rf3...
            s3 = (swcContext != null) ? swcContext.getResourceBundle(locales, namespaceURI, localPart) : null;
            o3 = (s3 != null) ? s3.getBackingFile() : null;

            // already compiled. return...
            if (rf1 == null && o3 instanceof InMemoryFile)
            {
                return findResourceBundleHelper(sources, s3);
            }
            else if (o3 instanceof InMemoryFile)
            {
                o3 = null;
            }

            rf3 = (ResourceFile) o3;

            if (rf1 != null)
            {
                rf1.merge(rf3);
            }
            else
            {
                rf1 = rf3;
                s1 = s3;
            }
        }

        return findResourceBundleHelper(sources, s1);
    }

    private static int findResourceBundleHelper(List<Source> sources, Source s)
    {
        if (s != null)
        {
            int where = sources.indexOf(s);
            if (where == -1)
            {
                sources.add(s);
                return sources.size() - 1;
            }
            else
            {
                return where;
            }
        }
        else
        {
            return -1;
        }
    }

    private static boolean hasPackage(SourcePath sourcePath, CompilerSwcContext swcContext, String packageName)
    {
        // C: This should check with "sources" before SourcePath and CompilerSwcContext... or check with
        //    FileSpec and SourceList, not "sources"... will fix it asap...
        boolean hasPackage = (sourcePath != null) && sourcePath.hasPackage(packageName);

        if (!hasPackage && swcContext != null)
        {
            hasPackage = swcContext.hasPackage(packageName);
        }

        return hasPackage;
    }

    private static boolean hasDefinition(SourcePath sourcePath, CompilerSwcContext swcContext, QName defName)
    {
        boolean hasDefinition = (sourcePath != null) && sourcePath.hasDefinition(defName);

        if (!hasDefinition && swcContext != null)
        {
            hasDefinition = swcContext.hasDefinition(defName);
        }

        return hasDefinition;
    }

    private static boolean sortInheritance(List<Source> sources, final List<CompilationUnit> units, final DependencyGraph<CompilationUnit> graph)
    {
        assert sources.size() == units.size();
        boolean success = true;
        final List<CompilationUnit> tsort = new ArrayList<CompilationUnit>(units.size());

        Algorithms.topologicalSort(graph, new Visitor<Vertex<String,CompilationUnit>>()
        {
            public void visit(Vertex<String,CompilationUnit> v)
            {
                String name = v.getWeight();
                CompilationUnit u = graph.get(name);
                assert u != null : name;
                tsort.add(u);
            }
        });

        if (units.size() > tsort.size())
        {
            for (int i = 0, size = units.size(); i < size; i++)
            {
                CompilationUnit u = units.get(i);
                if (!tsort.contains(u))
                {
                    ThreadLocalToolkit.log(new CircularInheritance(), u.getSource());
                    success = false;
                }
            }
            assert !success;
        }
        else
        {
            sources.clear();
            units.clear();
            for (int i = 0, size = tsort.size(); i < size; i++)
            {
                CompilationUnit u = tsort.get(i);
                sources.add(u.getSource());
                units.add(u);
            }
        }

        return success;
    }

    private static boolean detectCycles(List<Source> sources, final DependencyGraph<CompilationUnit> graph)
    {
        final Map<String, Source> tsort = new HashMap<String, Source>(sources.size());

        for (int i = 0, size = sources.size(); i < size; i++)
        {
            Source s = sources.get(i);
            tsort.put(s.getName(), s);
        }

        Algorithms.topologicalSort(graph, new Visitor<Vertex<String,CompilationUnit>>()
        {
            public void visit(Vertex<String,CompilationUnit> v)
            {
                String name = v.getWeight();
                tsort.remove(name);
            }
        });

        if (tsort.size() > 0)
        {
            for (Iterator<String> i = tsort.keySet().iterator(); i.hasNext();)
            {
                String name = i.next();
                Source s = tsort.get(name);
                if (!s.hasError())
                {
                    ThreadLocalToolkit.log(new CircularInheritance(), name);
                }
            }

            return true;
        }
        else
        {
            return false;
        }
    }

    private static void addGeneratedSources(List<Source> sources, DependencyGraph<CompilationUnit> igraph, DependencyGraph<Source> dgraph,
                                            ResourceContainer resources, SymbolTable symbolTable,
                                            Configuration configuration, int start, int end)
    {
        for (int i = start; i < end; i++)
        {
            Source source = sources.get(i);
            CompilationUnit u = source.getCompilationUnit();
            if (u != null)
            {
                Map<QName, Source> generatedSources = u.getGeneratedSources();
                if (generatedSources != null)
                {
                    for (Entry<QName, Source> entry : generatedSources.entrySet())
                    {
                        QName qName = entry.getKey();
                        MultiName mN = new MultiName(qName.getNamespace(), qName.getLocalPart());
                        Source gSource = entry.getValue();
                        String gName = gSource.getName();

                        if (!igraph.containsVertex(gName))
                        {
                            gSource = resources.addResource(gSource);
                            addVertexToGraphs(gSource, gSource.getCompilationUnit(), igraph, dgraph);
                            sources.add(gSource);

                            // C: This is similar to CompilerAPI.resolveMultiName(). The resolveMultiName() method does more
                            //    than adding Source objects to "sources".
                            symbolTable.registerMultiName(mN, qName);
                            symbolTable.registerQName(qName, gSource);
                        }

                        // C: If we manually add to CompilationUnit.expressions, we must add MultiName instances,
                        //    otherwise, incremental compilation will lose the dependency because the multiname
                        //    qname mapping isn't in expressionHistory.
                        u.expressions.add(mN);
                    }

                    u.clearGeneratedSources();
                }

                @SuppressWarnings("unchecked")
                Map<String, VirtualFile> cssArchiveFiles = (Map<String, VirtualFile>) u.getContext().getAttribute(CompilerContext.CSS_ARCHIVE_FILES);
                if (cssArchiveFiles != null && cssArchiveFiles.size() > 0)
                {
                    configuration.addCSSArchiveFiles(cssArchiveFiles);
                }

                @SuppressWarnings("unchecked")
                Map<String, VirtualFile> l10nArchiveFiles = (Map<String, VirtualFile>) u.getContext().getAttribute(CompilerContext.L10N_ARCHIVE_FILES);
                if (l10nArchiveFiles != null && l10nArchiveFiles.size() > 0)
                {
                    configuration.addL10nArchiveFiles(l10nArchiveFiles);
                }
            }
        }
    }

    private static void resolveType(List<Source> sources, List<CompilationUnit> units, DependencyGraph<CompilationUnit> igraph, DependencyGraph<Source> dgraph, SymbolTable symbolTable,
                                    SourceList sourceList, SourcePath sourcePath, ResourceContainer resources, CompilerSwcContext swcContext)
    {
        resolveType(sources, units, igraph, dgraph, symbolTable, sourceList, sourcePath, resources, swcContext, 0, units.size());
    }

    private static void resolveType(List<Source> sources, List<CompilationUnit> units, DependencyGraph<CompilationUnit> igraph, DependencyGraph<Source> dgraph,
                                    SymbolTable symbolTable, SourceList sourceList, SourcePath sourcePath,
                                    ResourceContainer resources, CompilerSwcContext swcContext, int start, int end)
    {
        Set<QName> qNames = new HashSet<QName>();

        for (int i = start; i < end; i++)
        {
            Source s = sources.get(i);
            CompilationUnit u = (s != null) ? s.getCompilationUnit() : units.get(i);

            if ((u.getWorkflow() & resolveType) != 0 || u.types.size() == 0)
            {
                continue;
            }

            qNames.clear();

            String head = u.getSource().getName();
            String name = u.getSource().getNameForReporting();

            for (Iterator<Name> iterator = u.types.iterator(); iterator.hasNext();)
            {
                Name unresolved = iterator.next();

                if (unresolved instanceof MultiName)
                {
                    MultiName mName = (MultiName) unresolved;
                    QName qName = resolveMultiName(name, mName, sources, sourceList, sourcePath, resources, swcContext, symbolTable);

                    if (qName != null)
                    {
                        Source tailSource = symbolTable.findSourceByQName(qName);
                        String tail = tailSource.getName();
                        addVertexToGraphs(tailSource, tailSource.getCompilationUnit(), igraph, dgraph);
                        addEdgeToGraphs(null, dgraph, head, tail);
                        qNames.add(qName);
                        u.typeHistory.put(mName, qName);
                        iterator.remove();
                    }
                }
            }

            if (qNames.size() > 0)
            {
                u.types.addAll(qNames);
            }
        }

        for (int i = start; i < end; i++)
        {
            Source s = sources.get(i);
            CompilationUnit u = (s != null) ? s.getCompilationUnit() : units.get(i);

            if ((u.getWorkflow() & resolveType) != 0)
            {
                continue;
            }
            else
            {
                u.setWorkflow(resolveType);
                if (u.namespaces.size() == 0)
                {
                    continue;
                }
            }

            qNames.clear();

            String head = u.getSource().getName();
            String name = u.getSource().getNameForReporting();

            for (Iterator<Name> iterator = u.namespaces.iterator(); iterator.hasNext();)
            {
                Name unresolved = iterator.next();

                if (unresolved instanceof MultiName)
                {
                    MultiName mName = (MultiName) unresolved;
                    QName qName = resolveMultiName(name, mName, sources, sourceList, sourcePath, resources, swcContext, symbolTable);

                    if (qName != null)
                    {
                        Source tailSource = symbolTable.findSourceByQName(qName);
                        String tail = tailSource.getName();
                        addVertexToGraphs(tailSource, tailSource.getCompilationUnit(), igraph, dgraph);
                        addEdgeToGraphs(null, dgraph, head, tail);
                        qNames.add(qName);
                        u.namespaceHistory.put(mName, qName);
                        iterator.remove();
                    }
                }
            }

            if (qNames.size() > 0)
            {
                u.namespaces.addAll(qNames);
            }
        }
    }

    private static void resolveImportStatements(List<Source> sources, List<CompilationUnit> units,
                                                SourcePath sourcePath,
                                                CompilerSwcContext swcContext)
    {
        resolveImportStatements(sources, units, sourcePath, swcContext, 0, units.size());
    }

    private static void resolveImportStatements(List<Source> sources, List<CompilationUnit> units,
                                                SourcePath sourcePath,
                                                CompilerSwcContext swcContext,
                                                int start, int end)
    {
        for (int i = start; i < end; i++)
        {
            Source s = sources.get(i);
            CompilationUnit u = (s != null) ? s.getCompilationUnit() : units.get(i);

            if ((u.getWorkflow() & resolveImportStatements) != 0)
            {
                continue;
            }
            else
            {
                u.setWorkflow(resolveImportStatements);
            }

            for (Iterator k = u.importPackageStatements.iterator(); k.hasNext();)
            {
                String packageName = (String) k.next();

                if (!hasPackage(sourcePath, swcContext, packageName))
                {
                    k.remove();
                }
            }

            for (Iterator k = u.importDefinitionStatements.iterator(); k.hasNext();)
            {
                QName defName = (QName) k.next();

                if (!hasDefinition(sourcePath, swcContext, defName))
                {
                    k.remove();
                }
            }
        }
    }

    private static void resolveExpression(List<Source> sources, List<CompilationUnit> units, DependencyGraph<CompilationUnit> igraph, DependencyGraph<Source> dgraph, SymbolTable symbolTable,
                                          SourceList sourceList, SourcePath sourcePath, ResourceContainer resources,
                                          CompilerSwcContext swcContext, Configuration configuration)
    {
        resolveExpression(sources, units, igraph, dgraph, symbolTable, sourceList, sourcePath, resources, swcContext,
                          configuration, 0, units.size());
    }

    private static void resolveExpression(List<Source> sources, List<CompilationUnit> units, DependencyGraph<CompilationUnit> igraph, DependencyGraph<Source> dgraph, SymbolTable symbolTable,
                                          SourceList sourceList, SourcePath sourcePath, ResourceContainer resources,
                                          CompilerSwcContext swcContext, Configuration configuration,
                                          int start, int end)
    {
        Set<QName> qNames = new HashSet<QName>();

        for (int i = start; i < end; i++)
        {
            Source s = sources.get(i);
            CompilationUnit u = (s != null) ? s.getCompilationUnit() : units.get(i);

            if (u.expressions.size() == 0)
            {
                continue;
            }

            qNames.clear();

            String head = u.getSource().getName();
            String name = u.getSource().getNameForReporting();

            for (Iterator<Name> iterator = u.expressions.iterator(); iterator.hasNext();)
            {
                Name unresolved = iterator.next();

                if (unresolved instanceof MultiName)
                {
                    MultiName mName = (MultiName) unresolved;
                    QName qName = resolveMultiName(name, mName, sources, sourceList, sourcePath, resources, swcContext, symbolTable);

                    if (qName != null)
                    {
                        Source tailSource = symbolTable.findSourceByQName(qName);
                        String tail = tailSource.getName();
                        addVertexToGraphs(tailSource, tailSource.getCompilationUnit(), igraph, dgraph);
                        addEdgeToGraphs(null, dgraph, head, tail);
                        qNames.add(qName);
                        u.expressionHistory.put(mName, qName);
                    }
                    else
                    {
                        // ASC doesn't seem to care about unresolved expression deps too much.
                        // This list seems to have a lot of false positives (i.e. generated local methods?)
                        // so the warning is contingent on an advanced config var.
                        if (configuration.getCompilerConfiguration().showDependencyWarnings())
                        {
                            ThreadLocalToolkit.log(new UnableToResolveDependency(mName.getLocalPart()), u.getSource());
                        }
                    }

                    // Due to the false positives, we have to remove
                    // the MultiName, even if it wasn't resolved
                    // successfully.  Otherwise, the false positive
                    // will lead to unnecessary global SWC cache
                    // invalidations in validationCompilationUnits().
                    iterator.remove();
                }
            }

            if (qNames.size() > 0)
            {
                u.expressions.addAll(qNames);
            }
        }
    }

    // e.g. head = mx.core.Application (subclass), tail = mx.containers.Container (superclass), 'head' needs 'tail'
    private static void addEdgeToGraphs(DependencyGraph<CompilationUnit> igraph, DependencyGraph<Source> dgraph, String head, String tail)
    {
        if (igraph != null)
        {
            if (!head.equals(tail) && !igraph.dependencyExists(head, tail))
            {
                igraph.addDependency(head, tail);
            }
        }

        if (dgraph != null)
        {
            if (!head.equals(tail) && !dgraph.dependencyExists(head, tail))
            {
                dgraph.addDependency(head, tail);
            }
        }
    }

    private static void adjustQNames(List<CompilationUnit> units, DependencyGraph<CompilationUnit> igraph, SymbolTable symbolTable)
    {
        // C: A temporary fix for the issue when the true QName of the top level definition in a source file
        //    from the classpath is not known until the source file is parsed...
        for (int i = 0, size = units.size(); i < size; i++)
        {
            CompilationUnit u = units.get(i);

            if (u != null && u.isDone() && (u.getWorkflow() & adjustQNames) == 0)
            {
                for (Name name : u.inheritance)
                {
                    if (name instanceof QName)
                    {
                        QName qName = (QName) name;
                        adjustQName(qName, igraph, symbolTable);
                    }
                }

                for (Name name : u.namespaces)
                {
                    if (name instanceof QName)
                    {
                        QName qName = (QName) name;
                        adjustQName(qName, igraph, symbolTable);
                    }
                }

                for (Name name : u.types)
                {
                    if (name instanceof QName)
                    {
                        QName qName = (QName) name;
                        adjustQName(qName, igraph, symbolTable);
                    }
                }

                for (Name name : u.expressions)
                {
                    if (name instanceof QName)
                    {
                        QName qName = (QName) name;
                        adjustQName(qName, igraph, symbolTable);
                    }
                }

                u.setWorkflow(adjustQNames);
            }
        }
    }

    private static void adjustQName(QName qName, DependencyGraph<CompilationUnit> igraph, SymbolTable symbolTable)
    {
        Source s = symbolTable.findSourceByQName(qName);
        CompilationUnit u = igraph.get(s == null ? null : s.getName());
        if (u != null && (u.getSource().isSourcePathOwner() || u.getSource().isSourceListOwner()) &&
            u.topLevelDefinitions.size() == 1)
        {
            QName def = u.topLevelDefinitions.last();
            if (qName.getLocalPart().equals(def.getLocalPart()) && !qName.getNamespace().equals(def.getNamespace()))
            {
                qName.setNamespace( def.getNamespace() );
            }
        }
    }

    // C: making this method public is only temporary...
    public static QName resolveMultiName(MultiName multiName, List<Source> sources, SourceList sourceList, SourcePath sourcePath,
                                         ResourceContainer resources, CompilerSwcContext swcContext, SymbolTable symbolTable)
    {
        return resolveMultiName(null, multiName, sources, sourceList, sourcePath, resources, swcContext, symbolTable);
    }

    private static QName resolveMultiName(String nameForReporting, MultiName multiName, List<Source> sources, SourceList sourceList,
                                          SourcePath sourcePath, ResourceContainer resources, CompilerSwcContext swcContext,
                                          SymbolTable symbolTable)
    {
        QName qName = symbolTable.isMultiNameResolved(multiName), qName2 = null;
        Source source = null, source2 = null;
        boolean hasAmbiguity = false;

        if (qName != null)
        {
            return qName;
        }

        String[] namespaceURI = multiName.getNamespace();
        String localPart = multiName.getLocalPart();

        for (int j = 0, length = namespaceURI.length; j < length; j++)
        {
            Source s = symbolTable.findSourceByQName(namespaceURI[j], localPart);
            int where = -1;

            if (s == null)
            {
                try
                {
                    where = findDefinition(sources, sourceList, sourcePath, resources, swcContext, namespaceURI[j], localPart);
                }
                catch (CompilerException ex)
                {
                    ThreadLocalToolkit.logError(ex.getMessage());
                }

                if (where != -1)
                {
                    s = sources.get(where);
                }
            }

            if (s != null)
            {
                if (qName == null)
                {
                    qName = new QName(namespaceURI[j], localPart);
                    source = s;

                    // C: comment out the break statement to enforce ambiguity checks...
                    // break;
                }
                else if (!qName.equals(namespaceURI[j], localPart))
                {
                    hasAmbiguity = true;
                    qName2 = new QName(namespaceURI[j], localPart);
                    source2 = s;
                    break;
                }
            }
        }

        if (hasAmbiguity)
        {
            CompilerMessage msg = new AmbiguousMultiname(qName, source.getName(), qName2, source2.getName());

            // C: The MultiName representation does not carry a line number. It looks like it'll improve
            //    error reporting if the AS compiler also tells this method where it found the reference.
            if (nameForReporting != null)
            {
                ThreadLocalToolkit.log(msg, nameForReporting);
            }
            else
            {
                ThreadLocalToolkit.log(msg);
            }

            return null;
        }
        else if (source != null)
        {
            symbolTable.registerMultiName(multiName, qName);
            symbolTable.registerQName(qName, source);
        }

        return qName;
    }

    public static QName[] resolveResourceBundleName(String rbName, List<Source> sources, SourceList sourceList,
                                                    SourcePathBase sourcePath, ResourceContainer resources, CompilerSwcContext swcContext,
                                                    SymbolTable symbolTable, String[] locales)
    {
        QName[] qNames = symbolTable.isResourceBundleResolved(rbName);
        if (qNames != null)
        {
            return qNames;
        }

        Source source = symbolTable.findSourceByResourceBundleName(rbName);
        if (source == null)
        {
            int where = -1;
            QName bundleName = new QName(rbName);
            String namespaceURI = bundleName.getNamespace();
            String localPart = bundleName.getLocalPart();

            try
            {
                where = findResourceBundle(sources, sourceList, sourcePath, swcContext, locales, namespaceURI, localPart);
            }
            catch (CompilerException ex)
            {
                ThreadLocalToolkit.logError(ex.getMessage());
            }

            if (where != -1)
            {
                source = sources.get(where);
                qNames = new QName[locales == null ? 0 : locales.length];

                for (int i = 0, length = qNames.length; i < length; i++)
                {
                    qNames[i] = new QName(namespaceURI, locales[i] + "$" + localPart + I18nUtils.CLASS_SUFFIX);
                }
            }
        }

        symbolTable.register(rbName, qNames, source);

        return qNames;
    }

    private static boolean generate(List<Source> sources, List<CompilationUnit> units, flex2.compiler.SubCompiler[] compilers, SymbolTable symbolTable)
    {
        return generate(sources, units, compilers, symbolTable, 0, units.size());
    }

    private static boolean generate(List<Source> sources, List<CompilationUnit> units, flex2.compiler.SubCompiler[] compilers, SymbolTable symbolTable,
                                    int start, int end)
    {
        boolean result = true;

        for (int i = start; i < end; i++)
        {
            Source s = sources.get(i);
            CompilationUnit u = (s != null) ? s.getCompilationUnit() : units.get(i);

            if ((u.getWorkflow() & generate) != 0)
            {
                continue;
            }
            else
            {
                u.setWorkflow(generate);
            }

            if (!u.isBytecodeAvailable() && !generate(u, compilers, symbolTable))
            {
                result = false;
                u.getSource().disconnectLogger();
            }

            calculateProgress(sources, symbolTable);

            if (tooManyErrors())
            {
                ThreadLocalToolkit.log(new TooManyErrors());
                break;
            }

            if (forcedToStop())
            {
                ThreadLocalToolkit.log(new ForcedToStop());
                break;
            }
        }

        return result;
    }

    private static boolean generate(CompilationUnit u, flex2.compiler.SubCompiler[] compilers, SymbolTable symbolTable)
    {
        Source s = u.getSource();
        if (!s.isCompiled())
        {
            flex2.compiler.SubCompiler c = getCompiler(s, compilers);
            if (c != null)
            {
                // C: may use CompilationUnit to reference the local logger so as to minimize
                //    the number of creations...
                Logger original = ThreadLocalToolkit.getLogger(), local = s.getLogger();
                ThreadLocalToolkit.setLogger(local);

                c.generate(u, symbolTable);
                if (u.bytes.size() > 0)
                {
                    u.setState(CompilationUnit.abc);
                }

                ThreadLocalToolkit.setLogger(original);

                if (local.errorCount() > 0)
                {
                    return false;
                }
            }
            else
            {
                return false;
            }
        }

        return true;
    }

    private static boolean postprocess(List<Source> sources, List<CompilationUnit> units, flex2.compiler.SubCompiler[] compilers, SymbolTable symbolTable)
    {
        return postprocess(sources, units, compilers, symbolTable, 0, units.size());
    }

    private static boolean postprocess(List<Source> sources, List<CompilationUnit> units, flex2.compiler.SubCompiler[] compilers, SymbolTable symbolTable,
                                       int start, int end)
    {
        boolean result = true;

        for (int i = start; i < end; i++)
        {
            Source s = sources.get(i);
            CompilationUnit u = (s != null) ? s.getCompilationUnit() : units.get(i);

            if (!postprocess(u, compilers, symbolTable))
            {
                result = false;
                u.getSource().disconnectLogger();
            }

            if (tooManyErrors())
            {
                ThreadLocalToolkit.log(new TooManyErrors());
                break;
            }

            if (forcedToStop())
            {
                ThreadLocalToolkit.log(new ForcedToStop());
                break;
            }
        }

        return result;
    }

    private static boolean postprocess(CompilationUnit u, flex2.compiler.SubCompiler[] compilers, SymbolTable symbolTable)
    {
        Source s = u.getSource();
        if (!s.isCompiled())
        {
            flex2.compiler.SubCompiler c = getCompiler(s, compilers);
            if (c != null)
            {
                Logger original = ThreadLocalToolkit.getLogger(), local = s.getLogger();
                ThreadLocalToolkit.setLogger(local);

                c.postprocess(u, symbolTable);

                ThreadLocalToolkit.setLogger(original);

                if (local.errorCount() > 0)
                {
                    return false;
                }
            }
            else
            {
                return false;
            }
        }

        return true;
    }

    private static void getIncludeClasses(List<Source> sources, DependencyGraph<CompilationUnit> igraph, DependencyGraph<Source> dgraph, SymbolTable symbolTable,
                                          SourceList sourceList, SourcePath sourcePath, ResourceContainer resources,
                                          CompilerSwcContext swcContext, Configuration configuration)
    {
        Set<String> includes = new LinkedHashSet<String>();
        includes.addAll( configuration.getIncludes() );
        for (Iterator<FrameInfo> it = configuration.getFrameList().iterator(); it.hasNext();)
        {
            FramesConfiguration.FrameInfo f = it.next();
            includes.addAll( f.frameClasses );
        }
        for (Iterator<String> it = includes.iterator(); it.hasNext();)
        {
            String className = it.next();
            MultiName mName = new MultiName(className);
            QName qName = resolveMultiName("configuration", mName, sources, sourceList, sourcePath, resources, swcContext, symbolTable);

            if (qName != null)
            {
                Source tailSource = symbolTable.findSourceByQName(qName);
                addVertexToGraphs(tailSource, tailSource.getCompilationUnit(), igraph, dgraph);
            }
            else
            {
                ThreadLocalToolkit.log(new UnableToResolveClass("include", className));
            }
        }
    }

    private static void getIncludeResources(List<Source> sources, DependencyGraph<CompilationUnit> igraph, DependencyGraph<Source> dgraph, ResourceBundlePath bundlePath,
                                            SymbolTable symbolTable, CompilerSwcContext swcContext, Configuration configuration)
    {
        Map resourceIncludes = swcContext.getResourceIncludes();
        String[] locales = configuration.getCompilerConfiguration().getLocales();

        for (Iterator it = resourceIncludes.keySet().iterator(); it.hasNext();)
        {
            String rbName = NameFormatter.toColon((String) it.next());
            QName[] qNames = resolveResourceBundleName(rbName, sources, null, bundlePath,
                                                       null, swcContext, symbolTable, locales);
            if (qNames != null)
            {
                Source source = symbolTable.findSourceByResourceBundleName(rbName);
                addVertexToGraphs(source, source.getCompilationUnit(), igraph, dgraph);

                for (int i = 0; i < qNames.length; i++)
                {
                    configuration.getIncludes().add(qNames[i].toString());
                }
            }
        }
    }

    private static void getExtraSources(List<Source> sources, DependencyGraph<CompilationUnit> igraph, DependencyGraph<Source> dgraph,
                                        SourceList sourceList, SourcePath sourcePath, ResourceContainer resources,
                                        ResourceBundlePath bundlePath, SymbolTable symbolTable, CompilerSwcContext swcContext,
                                        Configuration configuration, Map licenseMap)
    {
        getExtraSources(sources, igraph, dgraph, sourceList, sourcePath, resources, bundlePath, symbolTable, swcContext, 0,
                        sources.size(), configuration, licenseMap);
    }

    private static void getExtraSources(List<Source> sources, DependencyGraph<CompilationUnit> igraph, DependencyGraph<Source> dgraph,
                                        SourceList sourceList, SourcePath sourcePath, ResourceContainer resources,
                                        ResourceBundlePath bundlePath, SymbolTable symbolTable,
                                        CompilerSwcContext swcContext, int start, int end, Configuration configuration,
                                        Map licenseMap)
    {
        for (int i = start; i < end; i++)
        {
            Source s = sources.get(i);
            CompilationUnit u = (s != null) ? s.getCompilationUnit() : null;

            if (u != null)
            {
                getExtraSources(u, sources, igraph, dgraph, sourceList, sourcePath, resources, bundlePath, symbolTable, swcContext,
                                configuration, licenseMap);
            }
        }
    }

    private static void getExtraSources(CompilationUnit u, List<Source> sources, DependencyGraph<CompilationUnit> igraph, DependencyGraph<Source> dgraph,
                                        SourceList sourceList, SourcePath sourcePath, ResourceContainer resources,
                                        ResourceBundlePath bundlePath, SymbolTable symbolTable, CompilerSwcContext swcContext,
                                        Configuration configuration, Map licenseMap)
    {
        if ((u.getWorkflow() & extraSources) != 0) return;

        if (u.loaderClass != null)
        {
            String className = u.loaderClass;
            MultiName mName = new MultiName(className);
            QName qName = resolveMultiName(u.getSource().getNameForReporting(), mName, sources, sourceList, sourcePath,
                                           resources, swcContext, symbolTable);

            if (qName != null)
            {
                Source tailSource = symbolTable.findSourceByQName(qName);
                addVertexToGraphs(tailSource, tailSource.getCompilationUnit(), igraph, dgraph);
            }
            else
            {
                ThreadLocalToolkit.log(new UnableToResolveClass("factoryClass", className));
            }
        }

        configuration.getResourceBundles().addAll(u.resourceBundleHistory);
        boolean processResourceBundles = configuration.getCompilerConfiguration().useResourceBundleMetadata() && u.resourceBundleHistory.size() > 0;

        if (processResourceBundles)
        {
            String[] locales = configuration.getCompilerConfiguration().getLocales();

            for (Iterator it = u.resourceBundleHistory.iterator(); it.hasNext();)
            {
                String rbName = NameFormatter.toColon((String) it.next());
                Source source = null;
                QName[] qNames = resolveResourceBundleName(rbName, sources, null, bundlePath,
                                                           null, swcContext, symbolTable, locales);
                if (qNames != null)
                {
                    source = symbolTable.findSourceByResourceBundleName(rbName);
                    addVertexToGraphs(source, source.getCompilationUnit(), igraph, dgraph);
                    continue;
                }

                MultiName mName = new MultiName(rbName);
                QName qName = resolveMultiName(u.getSource().getNameForReporting(), mName, sources, null, sourcePath,
                                               null, null, symbolTable);
                if (qName != null)
                {
                    source = symbolTable.findSourceByQName(qName);
                    addVertexToGraphs(source, source.getCompilationUnit(), igraph, dgraph);

                    symbolTable.register(rbName, qNames, source);
                    continue;
                }

                mName = new MultiName(rbName + I18nUtils.CLASS_SUFFIX);
                qName = resolveMultiName(u.getSource().getNameForReporting(), mName, sources, null, null,
                                         null, swcContext, symbolTable);
                if (qName != null)
                {
                    source = symbolTable.findSourceByQName(qName);
                    addVertexToGraphs(source, source.getCompilationUnit(), igraph, dgraph);

                    symbolTable.register(rbName, qNames, source);
                }
                else if (locales.length == 1)
                {
                    ThreadLocalToolkit.log(new UnableToResolveResourceBundleForLocale(rbName, locales[0]));
                }
                else if (locales.length > 1)
                {
                    ThreadLocalToolkit.log(new UnableToResolveResourceBundle(rbName));
                }
            }
        }

        // ToDo: For Apache Flex remove this section since there is no longer a license.
        if ((u.licensedClassReqs != null) && (u.licensedClassReqs.size() > 0))
        {
            for (Iterator it = u.licensedClassReqs.entrySet().iterator(); it.hasNext();)
            {
                Map.Entry e = (Map.Entry) it.next();
                String id = (String) e.getKey();
                String handler = (String) e.getValue();

                if (!hasValidLicense(licenseMap, id))
                {
                    MultiName mName = new MultiName(handler);
                    QName qName = resolveMultiName(u.getSource().getNameForReporting(), mName, sources, sourceList,
                                                   sourcePath, resources, swcContext, symbolTable);
                    configuration.getIncludes().add(handler);
                    configuration.getExterns().remove(handler);   // don't let them try to extern it

                    if (qName != null)
                    {
                        // if the license is missing, we still may be able to be in
                        // a "demo" mode under control of the license handler
                        Source tailSource = symbolTable.findSourceByQName(qName);
                        addVertexToGraphs(tailSource, tailSource.getCompilationUnit(), igraph, dgraph);
                    }
                    else
                    {
                        // no license, no handler, no SWF
                        ThreadLocalToolkit.log(new UnableToResolveClass("RequiresLicense handler", handler));
                    }
                }
                else
                {
                    // if there is a license and the license handler is unconditionally added, remove it.
                    configuration.getIncludes().remove(handler);
                    configuration.getExterns().add(handler);
                }
            }
        }

        if ((u.extraClasses != null) && (u.extraClasses.size() > 0))
        {
            for (Iterator it = u.extraClasses.iterator(); it.hasNext();)
            {
                String className = (String) it.next();
                MultiName mName = new MultiName(className);
                QName qName = resolveMultiName(u.getSource().getNameForReporting(), mName, sources, sourceList,
                                               sourcePath, resources, swcContext, symbolTable);

                if (qName != null)
                {
                    Source tailSource = symbolTable.findSourceByQName(qName);
                    addVertexToGraphs(tailSource, tailSource.getCompilationUnit(), igraph, dgraph);
                }
                else
                {
                    ThreadLocalToolkit.log(new UnableToResolveNeededClass(className));
                }
            }
        }

        u.setWorkflow(extraSources);
    }

    private static void checkResourceBundles(List<Source> sources, SymbolTable symbolTable)
            throws CompilerException
    {
        for (Iterator<Source> iterator = sources.iterator(); iterator.hasNext();)
        {
            Source s = iterator.next();
            CompilationUnit u = (s != null) ? s.getCompilationUnit() : null;
            if (u != null && u.resourceBundleHistory.size() > 0)
            {
                for (Iterator it = u.resourceBundleHistory.iterator(); it.hasNext();)
                {
                    String rbName = (String) it.next();
                    Source rbSource = symbolTable.findSourceByResourceBundleName(rbName);
                    if (rbSource != null)
                    {
                        CompilationUnit rbUnit = rbSource.getCompilationUnit();
                        for (int j = 0, size = rbUnit == null ? 0 : rbUnit.topLevelDefinitions.size(); j < size; j++)
                        {
                            u.resourceBundles.add(rbUnit.topLevelDefinitions.get(j).toString());
                        }
                    }
                }
            }
        }

        if (ThreadLocalToolkit.errorCount() > 0)
        {
            throw new CompilerException();
        }
    }

    private static boolean hasValidLicense(Map licenseMap, String id)
    {     
      // For Apache Flex there is no license.
      return true;
    }

    private static void markDone(List<Source> sources, List<CompilationUnit> units)
    {
        markDone(sources, units, 0, units.size());
    }

    private static void markDone(List<Source> sources, List<CompilationUnit> units, int start, int end)
    {
        for (int i = start; i < end; i++)
        {
            Source s = sources.get(i);
            CompilationUnit u = (s != null) ? s.getCompilationUnit() : units.get(i);
            // C: There are requirements a CompilationUnit must meet before this marks the unit as Done.
            //    1. is the bytecode available?
            //    2. how about assets??
            if (u.getSource().isCompiled())
            {
                u.setState(CompilationUnit.Done);
            }
        }
    }

    private static flex2.compiler.SubCompiler getCompiler(Source source, flex2.compiler.SubCompiler[] compilers)
    {
        for (int i = 0, length = source == null || compilers == null ? 0 : compilers.length; i < length; i++)
        {
            if (compilers[i].isSupported(source.getMimeType()))
            {
                return compilers[i];
            }
        }
        return null;
    }

    /**
     * builds a list of VirtualFiles from list of path strings.
     */
    public static List<VirtualFile> getVirtualFileList(List<? extends Object> files)
        throws ConfigurationException
    {
        return new ArrayList<VirtualFile>(fileSetFromPaths(files, false, null, null));
    }

    /**
     * builds a list of VirtualFiles from list of path strings. Directories are scanned recursively, using mimeTypes
     * (if not null) as a filter.
     */
    public static List<VirtualFile> getVirtualFileList(Collection<? extends Object> paths, Set mimeTypes)
        throws ConfigurationException
    {
        return new ArrayList<VirtualFile>(fileSetFromPaths(paths, true, mimeTypes, null));
    }

    /**
     * list[0] --> List for FileSpec
     * list[1] --> List for SourceList
     */
    public static List<VirtualFile>[] getVirtualFileList(Collection<? extends Object> paths, Collection<VirtualFile> stylesheets, Set mimeTypes, List<File> directories)
        throws ConfigurationException
    {
        return getVirtualFileList(paths, stylesheets, mimeTypes, directories, null);
    }

    public static List<VirtualFile>[] getVirtualFileList(Collection<? extends Object> paths, Collection<VirtualFile> stylesheets, Set mimeTypes, List<File> directories,
            Collection<? extends Object> excludedPaths) throws ConfigurationException
  {
        //TODO this function should really be cleaned up to use Array.newInstance and
        //     List<List<VirtualFile>> instead of an array, so that we can get compile-time type-checks
        @SuppressWarnings("unchecked")
        List<VirtualFile>[] array = new List[2];

        array[0] = new ArrayList<VirtualFile>();
        array[1] = new ArrayList<VirtualFile>();

        if(excludedPaths != null) {
            LinkedList tempExcludedPaths = new LinkedList();
            Iterator iterator = excludedPaths.iterator();
            while (iterator.hasNext())
            {
                String path = (String)iterator.next();
                VirtualFile file = getVirtualFile(path);
                tempExcludedPaths.add(file);
            }

            excludedPaths = tempExcludedPaths;
        }

    List<VirtualFile> list = new ArrayList<VirtualFile>(fileSetFromPaths(paths, true, mimeTypes, null, excludedPaths));
    for (int i = 0, len = list == null ? 0 : list.size(); i < len; i++)
    {
      VirtualFile f = list.get(i);
      array[(SourceList.calculatePathRoot(f, directories) == null) ? 0 : 1].add(f);
    }
    for (Iterator<VirtualFile> j = stylesheets.iterator(); j.hasNext(); )
    {
      VirtualFile f = j.next();
      array[(SourceList.calculatePathRoot(f, directories) == null) ? 0 : 1].add(f);
    }

        return array;
    }

    public static List<VirtualFile>[] getVirtualFileList(Set<VirtualFile> fileSet, List<File> directories)
    {
        //TODO this function should really be cleaned up to use Array.newInstance and
        //     List<List<VirtualFile>> instead of an array, so that we can get compile-time type-checks
        @SuppressWarnings("unchecked")
        List<VirtualFile>[] array = new List[2];
        array[0] = new ArrayList<VirtualFile>();
        array[1] = new ArrayList<VirtualFile>();

        for (VirtualFile f : fileSet)
        {
            array[(SourceList.calculatePathRoot(f, directories) == null) ? 0 : 1].add(f);
        }

        return array;
    }

  private static Set<VirtualFile> fileSetFromPaths(Collection<? extends Object> paths, boolean recurse, Set mimeTypes, Set<VirtualFile> fileSet)
    throws ConfigurationException
    {
      return fileSetFromPaths(paths, recurse, mimeTypes, fileSet, null);
    }

  /**
   * Build a set of virtual files by scanning a mix of file and directory paths.
   * @param paths a list of path strings.
   * @param recurse if true, directories are recursively scanned. If not, they're just added to the returned set
   * @param mimeTypes if non-null, this filters the files found in scanned directories (but not top-level, i.e.
   * explicitly given files)
   * @param fileSet if non-null, files are added to this set and a reference ts returned. If null, a new Set is created.
   * @param excludedPaths This is only set via asdoc, its for -exclude-sources option.
   */
  private static Set<VirtualFile> fileSetFromPaths(Collection<? extends Object> paths, boolean recurse, Set mimeTypes, Set<VirtualFile> fileSet, Collection<? extends Object> excludedPaths)
    throws ConfigurationException
  {
    boolean topLevel;
    if (topLevel = (fileSet == null))
    {
      fileSet = new HashSet<VirtualFile>(paths.size());
    }
    for (Iterator<? extends Object> iter = paths.iterator(); iter.hasNext(); )
    {
      Object next = iter.next();
      VirtualFile file;
      if (next instanceof VirtualFile)
      {
        file = (VirtualFile) next;
      }
      else
      {
        String path = (next instanceof File) ? ((File)next).getAbsolutePath() : (String)next;

        file = getVirtualFile(path);

                if(excludedPaths != null && excludedPaths.contains(file)) {
                    excludedPaths.remove(file);
                    file = null;
                }
      }

      if (file != null)
      {
        if (recurse && file.isDirectory())
        {
          File dir = FileUtil.openFile(file.getName());
          if (dir == null)
          {
            throw new ConfigurationException.IOError(file.getName());
          }
                    fileSetFromPaths(Arrays.asList(dir.listFiles()), true, mimeTypes, fileSet, excludedPaths);
                }
                else if (topLevel || mimeTypes == null || mimeTypes.contains(file.getMimeType()))
                {
                    fileSet.add(file);
                }
            }
        }
        return fileSet;
    }

    public static VirtualFile getVirtualFile(String path) throws ConfigurationException
    {
        return getVirtualFile(path, true);
    }

    /**
     * Create virtual file for given file and throw configuration exception if not possible
     */
    public static VirtualFile getVirtualFile(String path, boolean reportError) throws ConfigurationException
    {
        VirtualFile result;
        File file = FileUtil.openFile(path);

        if (file != null && FileUtils.exists(file))
        {
            result = new LocalFile(FileUtil.getCanonicalFile(file));
        }
        else
        {
            PathResolver resolver = ThreadLocalToolkit.getPathResolver();
            result = resolver.resolve(path);

            if (result == null && reportError)
            {
                throw new ConfigurationException.IOError(path);
            }
        }

        return result;
    }

    /**
     * Encode movie; produce binary output
     *
     * @param movie
     * @throws java.io.IOException
     */
    public static void encode(Configuration configuration, Movie movie, OutputStream out) throws IOException
    {
        // TODO PERFORMANCE:
        // We create a TagEncoder, writes everything to the TagEncoder, and then copy the
        // result to the intended output stream. There is no reason for the copy. TagEncoder
        // contains a "protected SwfEncoder writer", and SwfEncoder extends RandomAccessBuffer,
        // which extends ByteArrayOutputStream -- this writer would need to be replaced with
        // some other object that can accept an OutputStream in its constructor. The point is
        // to eliminate the extra buffers, and just always write directly to the intended target.
        // - mikemo
        final boolean useCompression = configuration.getCompilerConfiguration().useCompression();
        TagEncoder encoder = configuration.generateSizeReport() ? new TagEncoderReporter() : new TagEncoder();
        new MovieEncoder(encoder).export(movie, useCompression);
        encoder.writeTo(out);
        generateSizeReport(configuration, movie, encoder);

        if (ThreadLocalToolkit.getBenchmark() != null)
        {
            LocalizationManager l10n = ThreadLocalToolkit.getLocalizationManager();
            if (l10n != null)
            ThreadLocalToolkit.getBenchmark().benchmark(l10n.getLocalizedTextString(new SWFEncoding()));
        }
    }

    public static void encode(ConsoleApplication app, OutputStream out) throws IOException
    {
        List abcList = app.getABCs();
        for (int i = 0, size = abcList.size(); i < size; i++)
        {
            out.write((byte[]) abcList.get(i));
        }

        if (ThreadLocalToolkit.getBenchmark() != null)
        {
            LocalizationManager l10n = ThreadLocalToolkit.getLocalizationManager();
            if (l10n != null)
            ThreadLocalToolkit.getBenchmark().benchmark(l10n.getLocalizedTextString(new SWFEncoding()));
        }
    }

    private static void generateSizeReport(Configuration config, Movie movie, TagEncoder encoder)
    {
        if (config.generateSizeReport() && movie instanceof SimpleMovie &&
            encoder instanceof TagEncoderReporter)
        {
            String report = ((TagEncoderReporter)encoder).getSizeReport();
            ((SimpleMovie)movie).setSizeReport(report);
            String fileName = config.getSizeReportFileName();
           
            if (fileName != null)
            {
              try
              {
                  FileUtil.writeFile(fileName, report);
              }
              catch (Exception ex)
              {
                  ThreadLocalToolkit.log( new UnableToWriteSizeReport( fileName ) );
              }
            }
        }
    }
   
    /**
     * @see flex2.compiler.PersistenceStore
     */
    public static void persistCompilationUnits(Configuration configuration,
            FileSpec fileSpec, SourceList sourceList, SourcePath sourcePath,
            ResourceContainer resources, ResourceBundlePath bundlePath,
            int checksum, String description, RandomAccessFile f)
        throws IOException
    {
        persistCompilationUnits(configuration, fileSpec, sourceList, sourcePath, resources, bundlePath, null, null,
                                checksum, checksum, checksum, checksum, null, null,
                                description, f);
    }

    /**
     * @see flex2.compiler.PersistenceStore
     */
    public static void persistCompilationUnits(Configuration configuration,
            FileSpec fileSpec, SourceList sourceList, SourcePath sourcePath,
            ResourceContainer resources, ResourceBundlePath bundlePath,
            List sources, List units, int checksums[],
            Map<QName, Long> swcDefSignatureChecksums,
            Map<String, Long> swcFileChecksums,
            Map<String, Long> archiveFileChecksums,
            String description, RandomAccessFile f) throws IOException
    {
        persistCompilationUnits(configuration, fileSpec, sourceList, sourcePath, resources, bundlePath,
                sources, units,
                checksums[0], checksums[1], checksums[2], checksums[3],
                swcDefSignatureChecksums, swcFileChecksums,
                archiveFileChecksums, description, f);
    }

    /**
     * @see flex2.compiler.PersistenceStore
     */
    public static void persistCompilationUnits(Configuration configuration, FileSpec fileSpec, SourceList sourceList, SourcePath sourcePath,
            ResourceContainer resources, ResourceBundlePath bundlePath,
            List sources, List units,
            int checksum, int cmd_checksum, int linker_checksum, int swc_checksum,
            Map<QName, Long> swcDefSignatureChecksums,
            Map<String, Long> swcFileChecksums,
            String description, RandomAccessFile f)
        throws IOException
   {
        persistCompilationUnits(configuration, fileSpec, sourceList, sourcePath,
                resources, bundlePath,
                sources, units,
                checksum, cmd_checksum, linker_checksum, swc_checksum,
                swcDefSignatureChecksums, swcFileChecksums, null,
                description, f);
   }

    /**
     * @see flex2.compiler.PersistenceStore
     */
    public static void persistCompilationUnits(Configuration configuration, FileSpec fileSpec, SourceList sourceList, SourcePath sourcePath,
                                               ResourceContainer resources, ResourceBundlePath bundlePath,
                                               List sources, List units,
                                               int checksum, int cmd_checksum, int linker_checksum, int swc_checksum,
                                               Map<QName, Long> swcDefSignatureChecksums,
                                               Map<String, Long> swcFileChecksums,
                                               Map<String, Long> archiveFileChecksums,
                                               String description, RandomAccessFile f)
        throws IOException
    {
        PersistenceStore store = new PersistenceStore(configuration, f);
        int count = -1;
        try
        {
            count = store.write(fileSpec, sourceList, sourcePath, resources, bundlePath, sources, units,
                                checksum, cmd_checksum, linker_checksum, swc_checksum,
                                swcDefSignatureChecksums, swcFileChecksums, archiveFileChecksums, description);
        }
        finally
        {
            if (count != -1 && ThreadLocalToolkit.getBenchmark() != null)
            {
                LocalizationManager l10n = ThreadLocalToolkit.getLocalizationManager();
                if (l10n == null)
                {
                    // set up for localizing messages
                    l10n = new LocalizationManager();
                    l10n.addLocalizer( new XLRLocalizer() );
                    l10n.addLocalizer( new ResourceBundleLocalizer() );
                    ThreadLocalToolkit.setLocalizationManager(l10n);
                }
                if (ThreadLocalToolkit.getLogger() == null)
                {
                    // this is called by flex builder running outside the OEM api.
                    flex2.compiler.CompilerAPI.useConsoleLogger();
                }
                ThreadLocalToolkit.getBenchmark().benchmark(l10n.getLocalizedTextString(new PersistingCompilationUnits(count)));
            }
        }
    }

    /**
     * Used by flex2.tools.oem.Library.
     */
    public static void loadCompilationUnits(Configuration configuration, FileSpec fileSpec, SourceList sourceList, SourcePath sourcePath,
                ResourceContainer resources, ResourceBundlePath bundlePath,
                List sources, List<CompilationUnit> units,
                int[] checksums, Map<QName, Long> swcDefSignatureChecksums, Map<String, Long> swcFileChecksums,
                RandomAccessFile f, String cacheName) throws IOException
    {
        loadCompilationUnits(configuration, fileSpec, sourceList, sourcePath,
                             resources, bundlePath, sources, units, checksums,
                             swcDefSignatureChecksums, swcFileChecksums, null, f, cacheName, null);
    }

    /**
     * Appears to be unused.
     */
    public static void loadCompilationUnits(Configuration configuration, FileSpec fileSpec, SourceList sourceList, SourcePath sourcePath,
                                            ResourceContainer resources, ResourceBundlePath bundlePath,
                                            int checksum, RandomAccessFile f, String cacheName)
        throws IOException
    {
        loadCompilationUnits(configuration, fileSpec, sourceList, sourcePath, resources, bundlePath, null, null,
                             new int[] {checksum, checksum, checksum, checksum}, null, null, null, f, cacheName, null);
    }

    /**
     * Used by flex2.tools.oem.Application.
     */
    public static void loadCompilationUnits(Configuration configuration, FileSpec fileSpec, SourceList sourceList, SourcePath sourcePath,
                                            ResourceContainer resources, ResourceBundlePath bundlePath,
                                            List sources, List units,
                                            int[] checksums, Map<QName, Long> swcDefSignatureChecksums, Map swcFileChecksums,
                                            RandomAccessFile f, String cacheName, FontManager fontManager)
        throws IOException
    {
        loadCompilationUnits(configuration, fileSpec, sourceList, sourcePath, resources, bundlePath, sources, units,
                             checksums, swcDefSignatureChecksums, swcFileChecksums, null, f, cacheName, null);
    }

    /**
     * Used by flex2.tools.Mxmlc and flex2.tools.Compc.
     */
    public static void loadCompilationUnits(Configuration configuration, FileSpec fileSpec, SourceList sourceList, SourcePath sourcePath,
                                            ResourceContainer resources, ResourceBundlePath bundlePath,
                                            List sources, List units,
                                            int[] checksums,
                                            Map<QName, Long> swcDefSignatureChecksums, Map swcFileChecksums,
                                            Map<String, Long> archiveFileChecksums,
                                            RandomAccessFile f, String cacheName, FontManager fontManager)
        throws IOException
    {
        LocalizationManager l10n = ThreadLocalToolkit.getLocalizationManager();
        PersistenceStore store = new PersistenceStore(configuration, f, fontManager);
        int count = -1;
        try
        {
            if ((count = store.read(fileSpec, sourceList, sourcePath, resources, bundlePath, sources, units,
                                    checksums, swcDefSignatureChecksums, swcFileChecksums, archiveFileChecksums)) < 0)
            {
                throw new IOException(l10n.getLocalizedTextString(new FailedToMatchCacheFile(cacheName)));
            }
        }
        finally
        {
            if (count >= 0 && ThreadLocalToolkit.getBenchmark() != null)
            {
                ThreadLocalToolkit.getBenchmark().benchmark(l10n.getLocalizedTextString(new LoadingCompilationUnits(count)));
            }
        }
    }

    private static boolean tooManyErrors()
    {
        return ThreadLocalToolkit.errorCount() > 100;
    }

    public static boolean forcedToStop()
    {
        CompilerControl cc = ThreadLocalToolkit.getCompilerControl();
        return (cc != null && cc.getStatus() == CompilerControl.STOP);
    }

    private static void calculateProgress(List<Source> sources, SymbolTable symbolTable)
    {
        symbolTable.tick++;
        int total = sources.size() * 12;
        double p = (double) symbolTable.tick / (double) total;
        int percent = (int) (p * 100);

        if (percent > 100)
        {
            percent = 100;
        }

        if (percent > symbolTable.currentPercentage)
        {
            symbolTable.currentPercentage = percent;
            ProgressMeter meter = ThreadLocalToolkit.getProgressMeter();

            if (meter != null)
            {
                meter.percentDone(percent);
            }
        }
    }

    /**
     * Useful when debugging batch issues.
     */
    @SuppressWarnings("unused")
    private static String workflowToString(int workflow)
    {
        String result;

        if ((workflow & extraSources) >= 1)
        {
            result = "extraSources";
        }
        else if ((workflow & adjustQNames) >= 1)
        {
            result = "adjustQNames";
        }
        else if ((workflow & resolveImportStatements) >= 1)
        {
            result = "resolveImportStatements";
        }
        else if ((workflow & generate) >= 1)
        {
            result = "generate";
        }
        else if ((workflow & resolveType) >= 1)
        {
            result = "resolveType";
        }
        else if ((workflow & analyze4) >= 1)
        {
            result = "analyze4";
        }
        else if ((workflow & analyze3) >= 1)
        {
            result = "analyze3";
        }
        else if ((workflow & analyze2) >= 1)
        {
            result = "analyze2";
        }
        else if ((workflow & analyze1) >= 1)
        {
            result = "analyze1";
        }
        else if ((workflow & parse2) >= 1)
        {
            result = "parse2";
        }
        else if ((workflow & parse1) >= 1)
        {
            result = "parse1";
        }
        else if ((workflow & preprocess) >= 1)
        {
            result = "preprocess";
        }
        else
        {
            result = "before preprocessed";
        }

        return result;
    }

    // error messages

    public static class UnableToSetHeadless extends CompilerMessage.CompilerWarning
    {
        private static final long serialVersionUID = 3008724815757107600L;

        public UnableToSetHeadless()
        {
            super();
        }
    }

    public static class IncompatibleSWCArchive extends CompilerMessage.CompilerError
    {
        private static final long serialVersionUID = 1741319866432830221L;

        public IncompatibleSWCArchive(String swc)
        {
            super();
            this.swc = swc;
        }

        public final String swc;
    }

    public static class OutputTime extends CompilerMessage.CompilerInfo
    {
        private static final long serialVersionUID = -6051351911183837367L;

        public OutputTime(int size)
        {
            super();
            this.size = size;
        }

        public final int size;
    }

    public static class NotFullyCompiled extends CompilerMessage.CompilerInfo
    {
        private static final long serialVersionUID = 4136933749063866830L;

        public NotFullyCompiled()
        {
            super();
        }
    }

    public static class SourceNoLongerExists extends CompilerMessage.CompilerInfo
    {
        private static final long serialVersionUID = -2704778045668485048L;

        public SourceNoLongerExists()
        {
            super();
        }
    }

    public static class SourceFileUpdated extends CompilerMessage.CompilerInfo
    {
        private static final long serialVersionUID = -5950312800861211191L;

        public SourceFileUpdated()
        {
            super();
        }
    }

    public static class AssetUpdated extends CompilerMessage.CompilerInfo
    {
        private static final long serialVersionUID = 4010801229607993419L;

        public AssetUpdated()
        {
            super();
        }
    }

    public static class SwcDefinitionObsoleted extends CompilerMessage.CompilerInfo
    {
        public final String newLocation;

        public SwcDefinitionObsoleted(String newLocation)
        {
            super();
            this.newLocation = newLocation;
        }
    }

    public static class DependencyNotCached extends CompilerMessage.CompilerInfo
    {
        public final String dependency;

        public DependencyNotCached(String dependency)
        {
            super();
            this.dependency = dependency;
        }
    }

    public static class NotSourcePathFirstPreference extends CompilerMessage.CompilerInfo
    {
        private static final long serialVersionUID = -9215808965455458278L;

        public NotSourcePathFirstPreference()
        {
            super();
        }
    }

    public static class DependentFileNoLongerExists extends CompilerMessage.CompilerInfo
    {
        private static final long serialVersionUID = 4566054497729698471L;

        public DependentFileNoLongerExists(String location)
        {
            super();
            this.location = location;
        }

        public final String location;
    }

    public static class InvalidImportStatement extends CompilerMessage.CompilerInfo
    {
        private static final long serialVersionUID = -6431103025897195931L;

        public InvalidImportStatement(String defName)
        {
            super();
            this.defName = defName;
        }

        public final String defName;
    }

    public static class DependentFileModified extends CompilerMessage.CompilerInfo
    {
        private static final long serialVersionUID = -3397344779921936416L;

        public DependentFileModified(String location)
        {
            super();
            this.location = location;
        }

        public final String location;
    }

    public static class MultiNameMeaningChanged extends CompilerMessage.CompilerInfo
    {
        private static final long serialVersionUID = -2003160838933415991L;
        public MultiNameMeaningChanged(MultiName multiName, QName qName)
        {
            super();
            this.multiName = multiName;
            this.qName = qName;
        }

        public final MultiName multiName;
        public final QName qName;
    }

    public static class FilesChangedAffected extends CompilerMessage.CompilerInfo
    {
        private static final long serialVersionUID = 567632711113318088L;

        public FilesChangedAffected(int updateCount, int count)
        {
            super();
            this.updateCount = updateCount;
            this.count = count;
        }

        public final int updateCount, count;
    }

    public static class MoreThanOneDefinition extends CompilerMessage.CompilerError
    {
        private static final long serialVersionUID = 4656607717787554720L;

        public MoreThanOneDefinition(List topLevelDefinitions)
        {
            super();
            this.topLevelDefinitions = topLevelDefinitions;
        }

        public final List topLevelDefinitions;
    }

    public static class MustHaveOneDefinition extends CompilerMessage.CompilerError
    {
        private static final long serialVersionUID = -3136994771425079174L;

        public MustHaveOneDefinition()
        {
            super();
        }
    }

    public static class WrongPackageName extends CompilerMessage.CompilerError
    {
        private static final long serialVersionUID = -2915859996892576941L;

        public WrongPackageName(String pathPackage, String defPackage)
        {
            super();
            this.pathPackage = pathPackage;
            this.defPackage = defPackage;
        }

        public final String pathPackage, defPackage;
    }

    public static class WrongDefinitionName extends CompilerMessage.CompilerError
    {
        private static final long serialVersionUID = -6793666173106638874L;

        public WrongDefinitionName(String pathName, String defName)
        {
            super();
            this.pathName = pathName;
            this.defName = defName;
        }

        public final String pathName, defName;
    }

    public static class CircularInheritance extends CompilerMessage.CompilerError
    {
        private static final long serialVersionUID = 2395431275577572954L;

        public CircularInheritance()
        {
            super();
        }
    }

    public static class DependencyUpdated extends CompilerMessage.CompilerWarning
    {
        public final String dependency;

        public DependencyUpdated(String dependency)
        {
            super();
            this.dependency = dependency;
        }
    }

    public static class UnableToResolveDependency extends CompilerMessage.CompilerWarning
    {
        private static final long serialVersionUID = -5981015158191974877L;

        public UnableToResolveDependency(String localPart)
        {
            super();
            this.localPart = localPart;
        }

        public final String localPart;
    }

    public static class AmbiguousMultiname extends CompilerMessage.CompilerError
    {
        private static final long serialVersionUID = -3521126109099117806L;
        public AmbiguousMultiname(QName qName1, String source1, QName qName2, String source2)
        {
            super();
            this.qName1 = qName1;
            this.source1 = source1;
            this.qName2 = qName2;
            this.source2 = source2;
        }

        public final QName qName1, qName2;
        public final String source1, source2;
    }

    public static class SWFEncoding extends CompilerMessage.CompilerInfo
    {
        private static final long serialVersionUID = 5936641849426685640L;

        public SWFEncoding()
        {
            super();
        }
    }

    public static class PersistingCompilationUnits extends CompilerMessage.CompilerInfo
    {
        private static final long serialVersionUID = 3560732877476940286L;

        public PersistingCompilationUnits(int count)
        {
            super();
            this.count = count;
        }

        public final int count;
    }

    public static class FailedToMatchCacheFile extends CompilerMessage.CompilerInfo
    {
        private static final long serialVersionUID = 555051683127823122L;

        public FailedToMatchCacheFile(String cacheName)
        {
            super();
            this.cacheName = cacheName;
        }

        public final String cacheName;
    }

    public static class LoadingCompilationUnits extends CompilerMessage.CompilerInfo
    {
        private static final long serialVersionUID = 6116416220246580099L;

        public LoadingCompilationUnits(int count)
        {
            super();
            this.count = count;
        }

        public final int count;
    }

    public static class ChannelDefinitionNotFound extends CompilerMessage.CompilerError
    {
        private static final long serialVersionUID = 5848003710927048218L;

        public ChannelDefinitionNotFound(String clientType)
        {
            super();
            this.clientType = clientType;
        }

        public final String clientType;
    }

    public static class TooManyErrors extends CompilerMessage.CompilerInfo
    {
        private static final long serialVersionUID = 3209927829940607725L;

        public TooManyErrors()
        {
            super();
        }
    }

    public static class ForcedToStop extends CompilerMessage.CompilerInfo
    {
        private static final long serialVersionUID = -8162250327019786018L;

        public ForcedToStop()
        {
            super();
        }
    }

    public static class UnableToWriteSizeReport extends CompilerMessage.CompilerError
    {
        private static final long serialVersionUID = 9098665499898450430L;
        public UnableToWriteSizeReport(String fileName)
        {
            super();
            this.fileName = fileName;
        }
        public final String fileName;
    }
   
    public static class UnableToResolveClass extends CompilerMessage.CompilerError
    {
        private static final long serialVersionUID = 9098665492278450430L;
        public UnableToResolveClass(String type, String className)
        {
            super();
            this.type = type;
            this.className = className;
        }

        public final String type;
        public final String className;
    }

    public static class UnableToResolveNeededClass extends CompilerMessage.CompilerError
    {
        private static final long serialVersionUID = 7916145250681811567L;

        public UnableToResolveNeededClass(String className)
        {
            super();
            this.className = className;
        }

        public final String className;
    }

    public static class UnableToResolveResourceBundle extends CompilerMessage.CompilerError
    {
        private static final long serialVersionUID = 8772827635337487217L;

        public UnableToResolveResourceBundle(String bundleName)
        {
            super();
            this.bundleName = bundleName;
        }

        public final String bundleName;
    }

    public static class UnableToResolveResourceBundleForLocale extends CompilerMessage.CompilerError
    {
        private static final long serialVersionUID = -8272953403512518246L;
        public UnableToResolveResourceBundleForLocale(String bundleName, String locale)
        {
            super();
            this.bundleName = bundleName;
            this.locale = locale;
        }

        public final String bundleName;
        public final String locale;
    }

    public static class BatchTime extends CompilerMessage.CompilerInfo
    {
        private static final long serialVersionUID = -1020248542254534482L;
        public BatchTime(String phase, String sourceName)
        {
            super();
            this.phase = phase;
            this.sourceName = sourceName;
        }

        public final String phase;
        public final String sourceName;
    }

    public static class CompileTime extends CompilerMessage.CompilerInfo
    {
        private static final long serialVersionUID = -4940316315109571708L;

        public CompileTime(String phase)
        {
            super();
            this.phase = phase;
        }

        public final String phase;
    }

  static String constructClassName(String namespaceURI, String localPart)
  {
    return (namespaceURI.length() == 0) ? localPart : new StringBuilder(namespaceURI.length() + localPart.length() + 1).append(namespaceURI).append(":").append(localPart).toString();
  }

    public static void setSkipTimestampCheck(boolean skipTimestampCheck)
    {
        CompilerAPI.skipTimestampCheck = skipTimestampCheck;
    }
}
TOP

Related Classes of flex2.compiler.CompilerAPI$UnableToResolveNeededClass

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.