Skip to content

Commit

Permalink
Implement --save_after_checks and --continue_saved_compilation.
Browse files Browse the repository at this point in the history
Some compiler options are not supported yet in this mode due to missing serialization of some of the compiler state:
- NTI.
- inline variables.
- coalesce variable names.
- disambiguate properties.
- dead assignment elimination

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=156216287
  • Loading branch information
rluble authored and brad4d committed May 18, 2017
1 parent 964c736 commit ccf57f4
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 32 deletions.
56 changes: 55 additions & 1 deletion src/com/google/javascript/jscomp/AbstractCommandLineRunner.java
Expand Up @@ -47,6 +47,7 @@
import java.io.BufferedWriter;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.Flushable;
import java.io.IOException;
Expand Down Expand Up @@ -116,6 +117,14 @@ public abstract class AbstractCommandLineRunner<A extends Compiler,
"JSC_OUTPUT_SAME_AS_INPUT_ERROR",
"Bad output file (already listed as input file): {0}");

static final DiagnosticType COULD_NOT_SERIALIZE_AST = DiagnosticType.error(
"JSC_COULD_NOT_SERIALIZE_AST",
"Could not serialize ast to: {0}");

static final DiagnosticType COULD_NOT_DESERIALIZE_AST = DiagnosticType.error(
"JSC_COULD_NOT_DESERIALIZE_AST",
"Could not deserialize ast from: {0}");

static final DiagnosticType NO_TREE_GENERATED_ERROR = DiagnosticType.error(
"JSC_NO_TREE_GENERATED_ERROR",
"Code contains errors. No tree was generated.");
Expand Down Expand Up @@ -1101,7 +1110,9 @@ protected int doRun() throws IOException {
compiler.printConfig(System.err);
}

// TODO(rluble): Add save and restore cases here.

String saveAfterChecksFilename = config.getSaveAfterChecksFileName();
String continueSavedCompilationFilename = config.getContinueSavedCompilationFileName();
if (config.skipNormalOutputs) {
// TODO(bradfordcsmith): Should we be ignoring possible init/initModules() errors here?
compiler.orderInputsWithLargeStack();
Expand All @@ -1111,6 +1122,10 @@ protected int doRun() throws IOException {
result = compiler.getResult();
} else if (options.getInstrumentForCoverageOnly()) {
result = instrumentForCoverage();
} else if (saveAfterChecksFilename != null) {
result = performStage1andSave(saveAfterChecksFilename);
} else if (continueSavedCompilationFilename != null) {
result = restoreAndPerformStage2(continueSavedCompilationFilename);
} else {
result = performFullCompilation();
}
Expand All @@ -1135,6 +1150,45 @@ protected int doRun() throws IOException {
return processResults(result, modules, options);
}

private Result performStage1andSave(String filename) {
Result result;
try (FileOutputStream serializedOutputStream = new FileOutputStream(filename)){
compiler.parseForCompilation();
if (!compiler.hasErrors()) {
compiler.stage1Passes();
compiler.completeCompilation();
compiler.saveState(serializedOutputStream);
}
} catch (IOException e) {
compiler.report(JSError.make(COULD_NOT_SERIALIZE_AST, filename));
} finally {
// Make sure we generate a report of errors and warnings even if the compiler throws an
// exception somewhere.
compiler.generateReport();
}
result = compiler.getResult();
return result;
}

private Result restoreAndPerformStage2(String filename) {
Result result;
try (FileInputStream serializedInputStream = new FileInputStream(filename)){
compiler.restoreState(serializedInputStream);
if (!compiler.hasErrors()) {
compiler.stage2Passes();
}
compiler.completeCompilation();
} catch (Exception e) {
compiler.report(JSError.make(COULD_NOT_DESERIALIZE_AST, filename));
} finally {
// Make sure we generate a report of errors and warnings even if the compiler throws an
// exception somewhere.
compiler.generateReport();
}
result = compiler.getResult();
return result;
}

private Result performFullCompilation() {
Result result;
try {
Expand Down
91 changes: 60 additions & 31 deletions src/com/google/javascript/jscomp/Compiler.java
Expand Up @@ -1715,11 +1715,7 @@ void readInputs() {
checkState(!hasErrors());
checkNotNull(externs);
checkNotNull(inputs);
if (options.getTracerMode().isOn()) {
tracker =
new PerformanceTracker(externsRoot, jsRoot, options.getTracerMode(), this.outStream);
addChangeHandler(tracker.getCodeChangeHandler());
}
maybeSetTracker();

Tracer tracer = newTracer(READING_PASS_NAME);
beforePass(READING_PASS_NAME);
Expand All @@ -1738,6 +1734,14 @@ void readInputs() {
}
}

public void maybeSetTracker() {
if (options.getTracerMode().isOn()) {
tracker =
new PerformanceTracker(externsRoot, jsRoot, options.getTracerMode(), this.outStream);
addChangeHandler(tracker.getCodeChangeHandler());
}
}

//------------------------------------------------------------------------
// Parsing
//------------------------------------------------------------------------
Expand Down Expand Up @@ -3301,49 +3305,64 @@ private void addFilesToSourceMap(Iterable<? extends SourceFile> files) {
* Serializable state of the compiler.
*/
private static class CompilerState implements Serializable {
CompilerOptions options;

Node externAndJsRoot;
Node externsRoot;
Node jsRoot;
Node externAndJsRoot;
List<CompilerInput> externs;
List<CompilerInput> inputs;
Map<InputId, CompilerInput> inputsById;
JSTypeRegistry typeRegistry;

CompilerState(
CompilerOptions options,
Node externsRoot,
Node jsRoot,
Node externAndJsRoot,
List<CompilerInput> externs,
List<CompilerInput> inputs,
Map<InputId, CompilerInput> inputsById,
JSTypeRegistry typeRegistry) {
this.options = options;
this.externsRoot = externsRoot;
this.jsRoot = jsRoot;
this.externAndJsRoot = externAndJsRoot;
this.typeRegistry = typeRegistry;
this.externs = externs;
this.inputs = inputs;
this.inputsById = inputsById;
MostRecentTypechecker mostRecentTypeChecker;
CompilerInput synthesizedExternsInput;
CompilerInput synthesizedExternsInputAtEnd;
Map<String, Node> injectedLibraries;
Node lastInjectedLibrary;
GlobalVarReferenceMap globalRefMap;
GlobalTypeInfo symbolTable;
private final boolean hasRegExpGlobalReferences;

CompilerState(Compiler compiler) {
this.externsRoot = checkNotNull(compiler.externsRoot);
this.jsRoot = checkNotNull(compiler.jsRoot);
this.externAndJsRoot = checkNotNull(compiler.externAndJsRoot);
this.typeRegistry = compiler.typeRegistry;
this.externs = compiler.externs;
this.inputs = checkNotNull(compiler.inputs);
this.inputsById = checkNotNull(compiler.inputsById);
this.mostRecentTypeChecker = compiler.mostRecentTypechecker;
this.synthesizedExternsInput = compiler.synthesizedExternsInput;
this.synthesizedExternsInputAtEnd = compiler.synthesizedExternsInputAtEnd;
this.injectedLibraries = compiler.injectedLibraries;
this.globalRefMap = compiler.globalRefMap;
this.lastInjectedLibrary = compiler.lastInjectedLibrary;
this.symbolTable = compiler.symbolTable;
this.hasRegExpGlobalReferences = compiler.hasRegExpGlobalReferences;
}
}

@GwtIncompatible("ObjectOutputStream")
public void saveState(OutputStream outputStream) throws IOException {
CompilerState compilerState = new CompilerState(
options, externsRoot, jsRoot, externAndJsRoot, externs, inputs, inputsById, typeRegistry);
try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream)) {
objectOutputStream.writeObject(compilerState);
runInCompilerThread(new Callable<Void>() {
@Override
public Void call() throws Exception {
objectOutputStream.writeObject(new CompilerState(Compiler.this));
return null;
}
});
}
}

@GwtIncompatible("ObjectInputStream")
public void restoreState(InputStream inputStream) throws Exception {
try (ObjectInputStream objectInputStream = new ObjectInputStream(inputStream)) {
CompilerState compilerState = (CompilerState) objectInputStream.readObject();
options = compilerState.options;
try (final ObjectInputStream objectInputStream = new ObjectInputStream(inputStream)) {
CompilerState compilerState = runInCompilerThread(new Callable<CompilerState>() {
@Override
public CompilerState call() throws Exception {
return (CompilerState) objectInputStream.readObject();
}
});
externs = compilerState.externs;
inputs = compilerState.inputs;
inputsById.clear();
Expand All @@ -3352,7 +3371,17 @@ public void restoreState(InputStream inputStream) throws Exception {
externAndJsRoot = compilerState.externAndJsRoot;
externsRoot = compilerState.externsRoot;
jsRoot = compilerState.jsRoot;
mostRecentTypechecker = compilerState.mostRecentTypeChecker;
synthesizedExternsInput = compilerState.synthesizedExternsInput;
synthesizedExternsInputAtEnd = compilerState.synthesizedExternsInputAtEnd;
injectedLibraries.clear();
injectedLibraries.putAll(compilerState.injectedLibraries);
lastInjectedLibrary = compilerState.lastInjectedLibrary;
globalRefMap = compilerState.globalRefMap;
symbolTable = compilerState.symbolTable;
hasRegExpGlobalReferences = compilerState.hasRegExpGlobalReferences;
}
initWarningsGuard(options.getWarningsGuard());
maybeSetTracker();
}
}
1 change: 1 addition & 0 deletions test/com/google/javascript/jscomp/CompilerTest.java
Expand Up @@ -972,6 +972,7 @@ public void testCheckSaveRestoreOptimize() throws Exception {
compiler.saveState(byteArrayOutputStream);

compiler = new Compiler(new TestErrorManager());
compiler.options = options;
ByteArrayInputStream byteArrayInputStream =
new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
compiler.restoreState(byteArrayInputStream);
Expand Down

0 comments on commit ccf57f4

Please sign in to comment.