System.out.println("Properties: " + permutation.prettyPrint());
}
AST ast = unifiedAst.getFreshAst();
JProgram jprogram = ast.getJProgram();
JsProgram jsProgram = ast.getJsProgram();
Map<StandardSymbolData, JsName> symbolTable = new TreeMap<StandardSymbolData, JsName>(
new SymbolData.ClassIdentComparator());
ResolveRebinds.exec(jprogram, permutation.getOrderedRebindAnswers());
// (4) Optimize the normalized Java AST for each permutation.
int optimizationLevel = options.getOptimizationLevel();
if (optimizationLevel == OptionOptimize.OPTIMIZE_LEVEL_DRAFT) {
draftOptimize(jprogram);
} else {
optimize(options, jprogram);
}
RemoveEmptySuperCalls.exec(jprogram);
// (5) "Normalize" the high-level Java tree into a lower-level tree more
// suited for JavaScript code generation. Don't go reordering these
// willy-nilly because there are some subtle interdependencies.
JsoDevirtualizer.exec(jprogram);
CatchBlockNormalizer.exec(jprogram);
PostOptimizationCompoundAssignmentNormalizer.exec(jprogram);
LongCastNormalizer.exec(jprogram);
LongEmulationNormalizer.exec(jprogram);
CastNormalizer.exec(jprogram, options.isCastCheckingDisabled());
ArrayNormalizer.exec(jprogram);
EqualityNormalizer.exec(jprogram);
// (6) Perform further post-normalization optimizations
// Prune everything
Pruner.exec(jprogram, false);
// (7) Generate a JavaScript code DOM from the Java type declarations
jprogram.typeOracle.recomputeAfterOptimizations();
JavaToJavaScriptMap jjsmap = GenerateJavaScriptAST.exec(jprogram,
jsProgram, options.getOutput(), symbolTable, propertyOracles);
// (8) Normalize the JS AST.
// Fix invalid constructs created during JS AST gen.
JsNormalizer.exec(jsProgram);
// Resolve all unresolved JsNameRefs.
JsSymbolResolver.exec(jsProgram);
// Move all function definitions to a top-level scope, to reduce weirdness
EvalFunctionsAtTopScope.exec(jsProgram, jjsmap);
// (9) Optimize the JS AST.
if (optimizationLevel > OptionOptimize.OPTIMIZE_LEVEL_DRAFT) {
optimizeJs(options, jsProgram);
/*
* Coalesce redundant labels in switch statements.
*/
JsDuplicateCaseFolder.exec(jsProgram);
}
/*
* Creates new variables, must run before code splitter and namer.
*/
JsStackEmulator.exec(jsProgram, propertyOracles);
/*
* Work around Safari 5 bug by rewriting a >> b as ~~a >> b.
*
* No shifts may be generated after this point.
*/
JsCoerceIntShift.exec(jsProgram, logger, propertyOracles);
// (10) Split up the program into fragments
SyntheticArtifact dependencies = null;
if (options.isRunAsyncEnabled()) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
CodeSplitter.exec(logger, jprogram, jsProgram, jjsmap,
chooseDependencyRecorder(options.isSoycEnabled(), baos));
if (baos.size() == 0 && options.isSoycEnabled()) {
recordNonSplitDependencies(jprogram, baos);
}
if (baos.size() > 0) {
dependencies = new SyntheticArtifact(SoycReportLinker.class,
"dependencies" + permutationId + ".xml.gz", baos.toByteArray());
}
}
// detect if browser is ie6 or not known
boolean isIE6orUnknown = false;
for (PropertyOracle oracle : propertyOracles) {
try {
SelectionProperty userAgentProperty = oracle.getSelectionProperty(
logger, "user.agent");
if ("ie6".equals(userAgentProperty.getCurrentValue())) {
isIE6orUnknown = true;
break;
}
} catch (BadPropertyValueException e) {
// user agent unknown; play it safe
isIE6orUnknown = true;
break;
}
}
// (10.5) Obfuscate
Map<JsName, String> obfuscateMap = Maps.create();
switch (options.getOutput()) {
case OBFUSCATED:
obfuscateMap = JsStringInterner.exec(jprogram, jsProgram, isIE6orUnknown);
JsObfuscateNamer.exec(jsProgram);
if (options.isAggressivelyOptimize()) {
if (JsStackEmulator.getStackMode(propertyOracles) == JsStackEmulator.StackMode.STRIP) {
boolean changed = false;
for (int i = 0; i < jsProgram.getFragmentCount(); i++) {
JsBlock fragment = jsProgram.getFragmentBlock(i);
changed = JsDuplicateFunctionRemover.exec(jsProgram, fragment)
|| changed;
}
if (changed) {
JsUnusedFunctionRemover.exec(jsProgram);
}
}
}
break;
case PRETTY:
// We don't intern strings in pretty mode to improve readability
JsPrettyNamer.exec(jsProgram);
break;
case DETAILED:
obfuscateMap = JsStringInterner.exec(jprogram, jsProgram, isIE6orUnknown);
JsVerboseNamer.exec(jsProgram);
break;
default:
throw new InternalCompilerException("Unknown output mode");
}
// (10.8) Handle cross-island references.
// No new JsNames or references to JSNames can be introduced after this
// point.
HandleCrossFragmentReferences.exec(logger, jsProgram, propertyOracles);
// (11) Perform any post-obfuscation normalizations.
// Work around an IE7 bug,
// http://code.google.com/p/google-web-toolkit/issues/detail?id=1440
// note, JsIEBlockTextTransformer now handles restructuring top level
// blocks, this class now handles non-top level blocks only.
boolean splitBlocks = isIE6orUnknown;
if (splitBlocks) {
JsIEBlockSizeVisitor.exec(jsProgram);
}
JsBreakUpLargeVarStatements.exec(jsProgram, propertyOracles);
// (12) Generate the final output text.
String[] js = new String[jsProgram.getFragmentCount()];
StatementRanges[] ranges = new StatementRanges[js.length];
SizeBreakdown[] sizeBreakdowns = options.isSoycEnabled()
|| options.isCompilerMetricsEnabled() ? new SizeBreakdown[js.length]
: null;
List<Map<Range, SourceInfo>> sourceInfoMaps = options.isSoycExtra()