blob: 4b530c8e03b37d121662a1260a90192a63dbaa11 [file] [log] [blame]
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of dart2js_incremental;
/// Do not call this method directly. It will be made private.
// TODO(ahe): Make this method private.
Future<CompilerImpl> reuseCompiler(
{CompilerDiagnostics diagnosticHandler,
CompilerInput inputProvider,
CompilerOutput outputProvider,
List<String> options: const [],
CompilerImpl cachedCompiler,
Uri libraryRoot,
Uri packageRoot,
Uri packageConfig,
bool packagesAreImmutable: false,
Map<String, dynamic> environment,
Future<bool> reuseLibrary(LibraryElement library)}) {
UserTag oldTag = new UserTag('_reuseCompiler').makeCurrent();
if (libraryRoot == null) {
throw 'Missing libraryRoot';
}
if (inputProvider == null) {
throw 'Missing inputProvider';
}
if (diagnosticHandler == null) {
throw 'Missing diagnosticHandler';
}
if (outputProvider == null) {
outputProvider = const NullCompilerOutput();
}
if (environment == null) {
environment = {};
}
CompilerImpl compiler = cachedCompiler;
JavaScriptBackend backend = compiler?.backend;
if (compiler == null ||
compiler.libraryRoot != libraryRoot ||
!compiler.options.hasIncrementalSupport ||
compiler.hasCrashed ||
backend.mirrorsAnalysis.resolutionHandler.hasEnqueuedReflectiveElements ||
compiler.deferredLoadTask.isProgramSplit) {
if (compiler != null && compiler.options.hasIncrementalSupport) {
print('***FLUSH***');
if (compiler.hasCrashed) {
print('Unable to reuse compiler due to crash.');
} else if (backend.mirrorsAnalysis.resolutionHandler
.hasEnqueuedReflectiveElements) {
print('Unable to reuse compiler due to dart:mirrors.');
} else if (compiler.deferredLoadTask.isProgramSplit) {
print('Unable to reuse compiler due to deferred loading.');
} else {
print('Unable to reuse compiler.');
}
}
oldTag.makeCurrent();
compiler = new CompilerImpl(
inputProvider,
outputProvider,
diagnosticHandler,
new CompilerOptions.parse(
libraryRoot: libraryRoot,
packageRoot: packageRoot,
packageConfig: packageConfig,
options: options,
environment: environment));
backend = compiler.backend;
Uri core = Uri.parse("dart:core");
return compiler.setupSdk().then((_) {
return compiler.libraryLoader.loadLibrary(core).then((_) {
// Likewise, always be prepared for runtimeType support.
// TODO(johnniwinther): Add global switch to force RTI.
compiler.resolutionWorldBuilder.hasRuntimeTypeSupport = true;
compiler.enqueuer.resolution.applyImpact(backend.registerRuntimeType());
return compiler;
});
});
} else {
compiler.tasks.forEach((t) => t.clearMeasurements());
compiler
..userOutputProvider = outputProvider
..provider = inputProvider
..handler = diagnosticHandler
..enqueuer.resolution.queueIsClosed = false
..enqueuer.resolution.hasEnqueuedReflectiveElements = false
..enqueuer.resolution.hasEnqueuedReflectiveStaticFields = false
..enqueuer.codegen.queueIsClosed = false
..enqueuer.codegen.hasEnqueuedReflectiveElements = false
..enqueuer.codegen.hasEnqueuedReflectiveStaticFields = false
..compilationFailed = false;
JavaScriptBackend backend = compiler.backend;
full.Emitter emitter = backend.emitter.emitter;
// TODO(ahe): Seems this cache only serves to tell
// [emitter.invalidateCaches] if it was invoked on a full compile (in
// which case nothing should be invalidated), or if it is an incremental
// compilation (in which case, holders/owners of newly compiled methods
// must be invalidated).
emitter.cachedElements.add(null);
compiler.enqueuer.codegen
..newlyEnqueuedElements.clear()
..newlySeenSelectors.clear();
emitter.nsmEmitter
..trivialNsmHandlers.clear();
backend.emitter.typeTestRegistry
..checkedClasses = null
..checkedFunctionTypes = null
..rtiNeededClasses.clear()
..cachedClassesUsingTypeVariableTests = null;
emitter.interceptorEmitter
..interceptorInvocationNames.clear();
backend.emitter.nativeEmitter
..hasNativeClasses = false
..nativeMethods.clear();
backend.emitter.readTypeVariables.clear();
emitter
..outputBuffers.clear()
..classesCollector = null
..mangledFieldNames.clear()
..mangledGlobalFieldNames.clear()
..recordedMangledNames.clear()
..clearCspPrecompiledNodes()
..elementDescriptors.clear();
backend
..preMirrorsMethodCount = 0;
if (reuseLibrary == null) {
reuseLibrary = (LibraryElement library) {
return new Future.value(
library.isPlatformLibrary ||
(packagesAreImmutable && library.isPackageLibrary));
};
}
return compiler.libraryLoader.resetAsync(reuseLibrary).then((_) {
oldTag.makeCurrent();
return compiler;
});
}
}
/// Helper class to collect sources.
class StringEventSink implements EventSink<String> {
List<String> data = <String>[];
final Function onClose;
StringEventSink(this.onClose);
void add(String event) {
if (data == null) throw 'StringEventSink is closed.';
data.add(event);
}
void addError(errorEvent, [StackTrace stackTrace]) {
throw 'addError($errorEvent, $stackTrace)';
}
void close() {
if (data != null) {
onClose(data.join());
data = null;
}
}
}
/// Output provider which collect output in [output].
class OutputProvider implements CompilerOutput {
final Map<String, String> output = new Map<String, String>();
EventSink<String> createEventSink(String name, String extension) {
return new StringEventSink((String data) {
output['$name.$extension'] = data;
});
}
String operator[] (String key) => output[key];
}