blob: ea82650574906f068b90b3fb776d05513f770ea4 [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.
library compiler_isolate;
import 'dart:async';
import 'dart:html';
import 'dart:isolate';
import 'dart:convert' show JSON;
import 'compilation.dart' show PRIVATE_SCHEME;
import 'package:compiler/compiler.dart' as compiler;
import 'package:compiler/src/old_to_new_api.dart' show
LegacyCompilerDiagnostics, LegacyCompilerInput;
import 'package:dart2js_incremental/dart2js_incremental.dart' show
reuseCompiler, OutputProvider;
import 'package:compiler/src/compiler.dart' show
Compiler;
const bool THROW_ON_ERROR = false;
final cachedSources = new Map<Uri, Future<String>>();
Uri sdkLocation;
List options = [];
var communicateViaBlobs;
var cachedCompiler;
void notifyDartHtml(SendPort port) {
// Notify the controlling isolate (Try Dart UI) that the program imports
// dart:html. This is used to determine how to run the program: in an iframe
// or in a worker.
port.send('dart:html');
}
compile(source, SendPort replyTo) {
if (sdkLocation == null) {
// The first message received gives us the URI of this web app.
if (source.endsWith('/sdk.json')) {
var request = new HttpRequest();
request.open('GET', source, async: false);
request.send(null);
if (request.status != 200) {
throw 'SDK not found at $source';
}
sdkLocation = Uri.parse('sdk:/sdk/');
JSON.decode(request.responseText).forEach((file, content) {
cachedSources[Uri.parse(file)] = new Future<String>.value(content);
});
} else {
sdkLocation = Uri.parse(source);
}
replyTo.send(null);
return;
}
if (source is List) {
String messageType = (source.length > 0) ? source[0] : null;
var data = (source.length > 1) ? source[1] : null;
if (messageType == 'options') {
options = data as List;
} if (messageType == 'communicateViaBlobs') {
communicateViaBlobs = data as bool;
}
return;
}
int charactersRead = 0;
Future<String> inputProvider(Uri uri) {
Future<String> future;
if (uri.scheme == 'sdk') {
if (uri.path.endsWith('/lib/html/dart2js/html_dart2js.dart')) {
notifyDartHtml(replyTo);
}
future = cachedSources[uri];
} else if (uri.scheme == 'http' || uri.scheme == 'https') {
future =
cachedSources.putIfAbsent(uri, () => HttpRequest.getString('$uri'));
} else if ('$uri' == '$PRIVATE_SCHEME:/main.dart') {
future = new Future<String>.value(source);
} else if (uri.scheme == PRIVATE_SCHEME) {
future = HttpRequest.getString('project${uri.path}');
}
if (future == null) {
future = new Future<String>.error('$uri: Not found');
}
return future.then((String value) {
charactersRead += value.length;
return value;
}).catchError((Event event) {
var target = event.target;
if (target is HttpRequest) {
throw '$uri: ${target.statusText}';
} else {
throw event;
}
}, test: (error) => error is Event);
}
void handler(Uri uri, int begin, int end,
String message, compiler.Diagnostic kind) {
replyTo.send(['diagnostic', { 'uri': '$uri',
'begin': begin,
'end': end,
'message': message,
'kind': kind.name }]);
if (THROW_ON_ERROR && kind == compiler.Diagnostic.ERROR) {
throw new Exception('Throw on error');
}
}
Stopwatch compilationTimer = new Stopwatch()..start();
OutputProvider outputProvider = new OutputProvider();
reuseCompiler(
diagnosticHandler: new LegacyCompilerDiagnostics(handler),
inputProvider: new LegacyCompilerInput(inputProvider),
outputProvider: outputProvider,
options: options,
cachedCompiler: cachedCompiler,
libraryRoot: sdkLocation,
packageRoot: Uri.base.resolve('/packages/'),
packagesAreImmutable: true).then((Compiler newCompiler) {
cachedCompiler = newCompiler;
return cachedCompiler.run(Uri.parse('$PRIVATE_SCHEME:/main.dart'));
}).then((success) {
compilationTimer.stop();
print('Compilation took ${compilationTimer.elapsed}');
if (cachedCompiler.libraryLoader
.lookupLibrary(Uri.parse('dart:html')) != null) {
notifyDartHtml(replyTo);
}
String js = outputProvider['.js'];
if (js == null) {
if (!options.contains('--analyze-only')) replyTo.send('failed');
} else {
var url;
handler(null, 0, 0,
'Compiled ${source.length}/${charactersRead} characters Dart'
' -> ${js.length} characters.',
compiler.Diagnostic.VERBOSE_INFO);
if (communicateViaBlobs) {
try {
// At least Safari and Firefox do not support creating an
// object URL from a web worker. MDN claims that it will be
// supported in Firefox 21.
url = Url.createObjectUrl(new Blob([js], 'application/javascript'));
} catch (_) {
// Ignored.
}
} else {
url = null;
}
if (url != null) {
replyTo.send(['url', url]);
} else {
replyTo.send(['code', js]);
}
}
}).catchError((e, trace) {
replyTo.send(['crash', '$e, $trace']);
}).whenComplete(() {
replyTo.send('done');
});
}
void main(List<String> arguments, SendPort port) {
ReceivePort replyTo = new ReceivePort();
port.send(replyTo.sendPort);
replyTo.listen((message) {
try {
List list = message as List;
compile(list[0], list[1]);
} catch (exception, stack) {
port.send('$exception\n$stack');
}
});
}