Fix deferred loading with multiple apps on same page.

Even though two apps don't have to load a file twice, they still both have to initialize it.

Still missing this support for the new emitter.

BUG=
R=floitsch@google.com

Review URL: https://codereview.chromium.org//837903002

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@42660 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
sigurdm@google.com 2015-01-07 14:05:51 +00:00
parent 34a556e5a9
commit 0df0c89ae6
8 changed files with 102 additions and 18 deletions

View file

@ -15,6 +15,7 @@ import 'package:_internal/compiler/js_lib/shared/embedded_names.dart' show
DEFERRED_LIBRARY_URIS,
DEFERRED_LIBRARY_HASHES,
INITIALIZE_LOADED_HUNK,
IS_HUNK_INITIALIZED,
IS_HUNK_LOADED;
import '../js_emitter.dart' show NativeGenerator;

View file

@ -161,6 +161,7 @@ class OldEmitter implements Emitter {
String get lazyInitializerName
=> '${namer.isolateName}.${lazyInitializerProperty}';
String get initName => 'init';
String get makeConstListProperty
=> namer.getMappedInstanceName('makeConstantList');
@ -1831,23 +1832,34 @@ function(originalDescriptor, name, holder, isStatic, globalFunctionsAccess) {
/// Emits support-code for deferred loading into [buffer].
void emitDeferredBoilerPlate(CodeBuffer buffer,
Map<OutputUnit, String> deferredLoadHashes) {
// Function for checking if a hunk is loaded given its hash.
buffer.write(jsAst.prettyPrint(
js('# = function(hunkHash) {'
' return !!$deferredInitializers[hunkHash];'
'}', generateEmbeddedGlobalAccess(embeddedNames.IS_HUNK_LOADED)),
jsAst.Statement functions = js.statement('''
{
// Function for checking if a hunk is loaded given its hash.
#isHunkLoaded = function(hunkHash) {
return !!$deferredInitializers[hunkHash];
};
#deferredInitialized = new Object(null);
// Function for checking if a hunk is initialized given its hash.
#isHunkInitialized = function(hunkHash) {
return #deferredInitialized[hunkHash];
};
// Function for initializing a loaded hunk, given its hash.
#initializeLoadedHunk = function(hunkHash) {
$deferredInitializers[hunkHash](
$globalsHolder, ${namer.currentIsolate});
#deferredInitialized[hunkHash] = true;
};
}
''', {"isHunkLoaded": generateEmbeddedGlobalAccess(
embeddedNames.IS_HUNK_LOADED),
"isHunkInitialized": generateEmbeddedGlobalAccess(
embeddedNames.IS_HUNK_INITIALIZED),
"initializeLoadedHunk": generateEmbeddedGlobalAccess(
embeddedNames.INITIALIZE_LOADED_HUNK),
"deferredInitialized": generateEmbeddedGlobalAccess(
embeddedNames.DEFERRED_INITIALIZED)});
buffer.write(jsAst.prettyPrint(functions,
compiler, monitor: compiler.dumpInfoTask));
buffer.write('$N');
// Function for initializing a loaded hunk, given its hash.
buffer.write(jsAst.prettyPrint(
js('# = function(hunkHash) {'
' $deferredInitializers[hunkHash]('
'$globalsHolder, ${namer.currentIsolate})'
'}',
generateEmbeddedGlobalAccess(
embeddedNames.INITIALIZE_LOADED_HUNK)),
compiler, monitor: compiler.dumpInfoTask));
buffer.write('$N');
// Write a javascript mapping from Deferred import load ids (derrived
// from the import prefix.) to a list of lists of uris of hunks to load,
// and a corresponding mapping to a list of hashes used by

View file

@ -15,6 +15,7 @@ import 'dart:_js_embedded_names' show
DEFERRED_LIBRARY_HASHES,
INITIALIZE_LOADED_HUNK,
IS_HUNK_LOADED,
IS_HUNK_INITIALIZED,
NATIVE_SUPERCLASS_TAG_NAME;
import 'dart:collection';
@ -3313,15 +3314,18 @@ Future<Null> loadDeferredLibrary(String loadId) {
// The indices into `uris` and `hashes` that we want to load.
List<int> indices = new List.generate(uris.length, (i) => i);
var isHunkLoaded = JS_EMBEDDED_GLOBAL('', IS_HUNK_LOADED);
var isHunkInitialized = JS_EMBEDDED_GLOBAL('', IS_HUNK_INITIALIZED);
// Filter away indices for hunks that have already been loaded.
List<int> indicesToLoad = indices
.where((int i) => !JS('bool','#(#)', isHunkLoaded, hashes[i]))
.toList();
// Load the needed hunks.
List<int> indicesToInitialize = indices
.where((int i) => !JS('bool','#(#)', isHunkInitialized, hashes[i]))
.toList(); // Load the needed hunks.
return Future.wait(indicesToLoad
.map((int i) => _loadHunk(uris[i]))).then((_) {
// Now all hunks have been loaded, we run the needed initializers.
for (int i in indicesToLoad) {
for (int i in indicesToInitialize) {
var initializer = JS_EMBEDDED_GLOBAL('', INITIALIZE_LOADED_HUNK);
JS('void', '#(#)', initializer, hashes[i]);
}

View file

@ -32,6 +32,8 @@ const DEFERRED_LIBRARY_URIS = 'deferredLibraryUris';
const DEFERRED_LIBRARY_HASHES = 'deferredLibraryHashes';
const INITIALIZE_LOADED_HUNK = 'initializeLoadedHunk';
const IS_HUNK_LOADED = 'isHunkLoaded';
const IS_HUNK_INITIALIZED = 'isHunkInitialized';
const DEFERRED_INITIALIZED = 'deferredInitialized';
const CLASS_ID_EXTRACTOR = 'classIdExtractor';
const CLASS_FIELDS_EXTRACTOR = 'classFieldsExtractor';
const INSTANCE_FROM_CLASS_ID = "instanceFromClassId";

View file

@ -0,0 +1,28 @@
// Copyright (c) 2015, 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.
import "deferred_multi_app_lib.dart" deferred as lib;
import "dart:async";
import "dart:html";
import "package:expect/expect.dart";
main() {
Element state = querySelector("#state");
if (state.text == "1") {
lib.loadLibrary().then((_) {
var a = lib.one();
Expect.equals("one", a);
window.postMessage(a, '*');
});
state.text = "2";
} else {
new Timer(new Duration(milliseconds: 100), () {
lib.loadLibrary().then((_) {
var a = lib.two();
Expect.equals("two", a);
window.postMessage(a, '*');
});
});
}
}

View file

@ -0,0 +1,23 @@
<!--
Copyright (c) 2015, 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.
Test that two instances of a script does not interfere when loading the same
deferred library.
START_HTML_DART_TEST
{
"scripts": ["deferred_multi_app.dart"],
"expectedMessages": ["one", "two"]
}
END_HTML_DART_TEST
-->
<html>
<body>
<div id="state">1</div>
<script>window.parent.dispatchEvent(new Event('detect_errors'));</script>
<script src="deferred_multi_app.dart" type="application/dart"></script>
<script src="deferred_multi_app.dart" type="application/dart"></script>
</body>
</html>

View file

@ -0,0 +1,11 @@
// Copyright (c) 2015, 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.
one() {
return "one";
}
two() {
return "two";
}

View file

@ -105,6 +105,9 @@ xhr_test: Pass, Fail # Issue 11884
[$runtime == drt || $runtime == dartium || $runtime == chrome || $runtime == chromeOnAndroid || $runtime == ContentShellOnAndroid ]
webgl_1_test: Pass, Fail # Issue 8219
[ ($compiler == none || $compiler == dart2dart) ]
deferred_multi_app_htmltest: Fail # Issue 16603
[ $compiler == none && ($runtime == drt || $runtime == dartium) && $system == windows]
websql_test: Skip # Issue 4941: stderr contains a backtrace.