mirror of
https://github.com/dart-lang/sdk
synced 2024-09-04 16:03:44 +00:00
Factor deferred loading data
'Normalize' the data used for loading deferred libraries. Replace URIs and SHA1 hashes with indexes so that the URIs and hashes occur once. Bug: https://github.com/dart-lang/sdk/issues/29635 Change-Id: I3ac8791ad44ca588cbb1bd7d86f18243c956a04a Reviewed-on: https://dart-review.googlesource.com/32505 Commit-Queue: Stephen Adams <sra@google.com> Reviewed-by: Sigmund Cherem <sigmund@google.com>
This commit is contained in:
parent
b8b69b1bd9
commit
31cd4e1457
|
@ -851,7 +851,7 @@ class Emitter extends js_emitter.EmitterBase {
|
|||
jsAst.Expression laziesAccess =
|
||||
generateEmbeddedGlobalAccess(embeddedNames.LAZIES);
|
||||
|
||||
return js.statement('''
|
||||
return js.statement("""
|
||||
function init() {
|
||||
$isolatePropertiesName = Object.create(null);
|
||||
#allClasses = map();
|
||||
|
@ -955,7 +955,7 @@ class Emitter extends js_emitter.EmitterBase {
|
|||
return Isolate;
|
||||
}
|
||||
|
||||
}''', {
|
||||
}""", {
|
||||
'allClasses': allClassesAccess,
|
||||
'getTypeFromName': getTypeFromNameAccess,
|
||||
'interceptorsByTag': interceptorsByTagAccess,
|
||||
|
@ -1735,49 +1735,59 @@ class Emitter extends js_emitter.EmitterBase {
|
|||
generateEmbeddedGlobalAccess(embeddedNames.DEFERRED_INITIALIZED)
|
||||
}));
|
||||
|
||||
// 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
|
||||
// INITIALIZE_LOADED_HUNK and IS_HUNK_LOADED.
|
||||
Map<String, List<jsAst.LiteralString>> deferredLibraryUris =
|
||||
new Map<String, List<jsAst.LiteralString>>();
|
||||
Map<String, List<_DeferredOutputUnitHash>> deferredLibraryHashes =
|
||||
new Map<String, List<_DeferredOutputUnitHash>>();
|
||||
compiler.deferredLoadTask.hunksToLoad
|
||||
.forEach((String loadId, List<OutputUnit> outputUnits) {
|
||||
List<jsAst.LiteralString> uris = new List<jsAst.LiteralString>();
|
||||
List<_DeferredOutputUnitHash> hashes =
|
||||
new List<_DeferredOutputUnitHash>();
|
||||
deferredLibraryHashes[loadId] = new List<_DeferredOutputUnitHash>();
|
||||
for (OutputUnit outputUnit in outputUnits) {
|
||||
uris.add(js.escapedString(
|
||||
compiler.deferredLoadTask.deferredPartFileName(outputUnit.name)));
|
||||
hashes.add(deferredLoadHashes[outputUnit]);
|
||||
void store(
|
||||
jsAst.Expression map, jsAst.Expression uris, jsAst.Expression hashes) {
|
||||
void assign(String name, jsAst.Expression value) {
|
||||
parts.add(
|
||||
js.statement('# = #', [generateEmbeddedGlobalAccess(name), value]));
|
||||
}
|
||||
|
||||
deferredLibraryUris[loadId] = uris;
|
||||
deferredLibraryHashes[loadId] = hashes;
|
||||
});
|
||||
|
||||
void emitMapping(String name, Map<String, List<jsAst.Expression>> mapping) {
|
||||
List<jsAst.Property> properties = new List<jsAst.Property>();
|
||||
mapping.forEach((String key, List<jsAst.Expression> values) {
|
||||
properties.add(new jsAst.Property(
|
||||
js.escapedString(key), new jsAst.ArrayInitializer(values)));
|
||||
});
|
||||
jsAst.Node initializer =
|
||||
new jsAst.ObjectInitializer(properties, isOneLiner: true);
|
||||
|
||||
jsAst.Node globalName = generateEmbeddedGlobalAccess(name);
|
||||
parts.add(js.statement("# = #", [globalName, initializer]));
|
||||
assign(embeddedNames.DEFERRED_LIBRARY_PARTS, map);
|
||||
assign(embeddedNames.DEFERRED_PART_URIS, uris);
|
||||
assign(embeddedNames.DEFERRED_PART_HASHES, hashes);
|
||||
}
|
||||
|
||||
emitMapping(embeddedNames.DEFERRED_LIBRARY_URIS, deferredLibraryUris);
|
||||
emitMapping(embeddedNames.DEFERRED_LIBRARY_HASHES, deferredLibraryHashes);
|
||||
createDeferredLoadingData(
|
||||
compiler.deferredLoadTask.hunksToLoad, deferredLoadHashes, store);
|
||||
|
||||
return new jsAst.Block(parts);
|
||||
}
|
||||
|
||||
// Create data used for loading and initializing the hunks for a deferred
|
||||
// import. There are three parts: a map from loadId to list of parts, where
|
||||
// parts are represented as an index; an array of uris indexed by part; and an
|
||||
// array of hashes indexed by part.
|
||||
void createDeferredLoadingData(
|
||||
Map<String, List<OutputUnit>> loadMap,
|
||||
Map<OutputUnit, _DeferredOutputUnitHash> deferredLoadHashes,
|
||||
void finish(jsAst.Expression map, jsAst.Expression uris,
|
||||
jsAst.Expression hashes)) {
|
||||
Map<OutputUnit, int> fragmentIndexes = <OutputUnit, int>{};
|
||||
var uris = <jsAst.Expression>[];
|
||||
var hashes = <jsAst.Expression>[];
|
||||
|
||||
List<jsAst.Property> libraryPartsMapEntries = <jsAst.Property>[];
|
||||
|
||||
loadMap.forEach((String loadId, List<OutputUnit> fragmentList) {
|
||||
List<jsAst.Expression> indexes = <jsAst.Expression>[];
|
||||
for (OutputUnit fragment in fragmentList) {
|
||||
int index = fragmentIndexes[fragment];
|
||||
if (index == null) {
|
||||
index = fragmentIndexes[fragment] = fragmentIndexes.length;
|
||||
uris.add(js.escapedString(
|
||||
compiler.deferredLoadTask.deferredPartFileName(fragment.name)));
|
||||
hashes.add(deferredLoadHashes[fragment]);
|
||||
}
|
||||
indexes.add(js.number(index));
|
||||
}
|
||||
libraryPartsMapEntries.add(new jsAst.Property(
|
||||
js.string(loadId), new jsAst.ArrayInitializer(indexes)));
|
||||
});
|
||||
|
||||
finish(new jsAst.ObjectInitializer(libraryPartsMapEntries),
|
||||
new jsAst.ArrayInitializer(uris), new jsAst.ArrayInitializer(hashes));
|
||||
}
|
||||
|
||||
Map<OutputUnit, jsAst.Program> buildOutputAstForDeferredCode(
|
||||
Program program) {
|
||||
if (!program.isSplit) return const <OutputUnit, jsAst.Program>{};
|
||||
|
|
|
@ -1256,32 +1256,6 @@ class FragmentEmitter {
|
|||
|
||||
List<js.Property> globals = <js.Property>[];
|
||||
|
||||
js.ArrayInitializer fragmentUris(List<Fragment> fragments) {
|
||||
return js.stringArray(fragments.map((Fragment fragment) =>
|
||||
"${fragment.outputFileName}.${ModelEmitter.deferredExtension}"));
|
||||
}
|
||||
|
||||
js.ArrayInitializer fragmentHashes(List<Fragment> fragments) {
|
||||
return new js.ArrayInitializer(fragments
|
||||
.map((fragment) => deferredLoadHashes[fragment])
|
||||
.toList(growable: false));
|
||||
}
|
||||
|
||||
List<js.Property> uris = new List<js.Property>(loadMap.length);
|
||||
List<js.Property> hashes = new List<js.Property>(loadMap.length);
|
||||
int count = 0;
|
||||
loadMap.forEach((String loadId, List<Fragment> fragmentList) {
|
||||
uris[count] =
|
||||
new js.Property(js.string(loadId), fragmentUris(fragmentList));
|
||||
hashes[count] =
|
||||
new js.Property(js.string(loadId), fragmentHashes(fragmentList));
|
||||
count++;
|
||||
});
|
||||
|
||||
globals.add(new js.Property(
|
||||
js.string(DEFERRED_LIBRARY_URIS), new js.ObjectInitializer(uris)));
|
||||
globals.add(new js.Property(
|
||||
js.string(DEFERRED_LIBRARY_HASHES), new js.ObjectInitializer(hashes)));
|
||||
globals.add(new js.Property(
|
||||
js.string(DEFERRED_INITIALIZED), js.js("Object.create(null)")));
|
||||
|
||||
|
@ -1316,9 +1290,51 @@ class FragmentEmitter {
|
|||
globals.add(new js.Property(
|
||||
js.string(INITIALIZE_LOADED_HUNK), initializeLoadedHunkFunction));
|
||||
|
||||
createDeferredLoadingData(loadMap, deferredLoadHashes,
|
||||
(js.Expression map, js.Expression uris, js.Expression hashes) {
|
||||
globals.add(new js.Property(js.string(DEFERRED_LIBRARY_PARTS), map));
|
||||
globals.add(new js.Property(js.string(DEFERRED_PART_URIS), uris));
|
||||
globals.add(new js.Property(js.string(DEFERRED_PART_HASHES), hashes));
|
||||
});
|
||||
|
||||
return globals;
|
||||
}
|
||||
|
||||
// Create data used for loading and initializing the hunks for a deferred
|
||||
// import. There are three parts: a map from loadId to list of parts, where
|
||||
// parts are represented as an index; an array of uris indexed by part; and an
|
||||
// array of hashes indexed by part.
|
||||
static void createDeferredLoadingData(
|
||||
Map<String, List<Fragment>> loadMap,
|
||||
Map<DeferredFragment, _DeferredFragmentHash> deferredLoadHashes,
|
||||
void finish(
|
||||
js.Expression map, js.Expression uris, js.Expression hashes)) {
|
||||
Map<Fragment, int> fragmentIndexes = <Fragment, int>{};
|
||||
List<String> fragmentUris = <String>[];
|
||||
List<js.Expression> fragmentHashes = <js.Expression>[];
|
||||
|
||||
List<js.Property> libraryPartsMapEntries = <js.Property>[];
|
||||
|
||||
loadMap.forEach((String loadId, List<Fragment> fragmentList) {
|
||||
List<js.Expression> indexes = <js.Expression>[];
|
||||
for (Fragment fragment in fragmentList) {
|
||||
int index = fragmentIndexes[fragment];
|
||||
if (index == null) {
|
||||
index = fragmentIndexes[fragment] = fragmentIndexes.length;
|
||||
fragmentUris.add(
|
||||
"${fragment.outputFileName}.${ModelEmitter.deferredExtension}");
|
||||
fragmentHashes.add(deferredLoadHashes[fragment]);
|
||||
}
|
||||
indexes.add(js.number(index));
|
||||
}
|
||||
libraryPartsMapEntries.add(
|
||||
new js.Property(js.string(loadId), new js.ArrayInitializer(indexes)));
|
||||
});
|
||||
|
||||
finish(new js.ObjectInitializer(libraryPartsMapEntries),
|
||||
js.stringArray(fragmentUris), new js.ArrayInitializer(fragmentHashes));
|
||||
}
|
||||
|
||||
/// Emits the [MANGLED_GLOBAL_NAMES] embedded global.
|
||||
///
|
||||
/// This global maps minified names for selected classes (some important
|
||||
|
|
|
@ -13,8 +13,9 @@ import 'package:js_runtime/shared/embedded_names.dart'
|
|||
CLASS_ID_EXTRACTOR,
|
||||
CREATE_NEW_ISOLATE,
|
||||
DEFERRED_INITIALIZED,
|
||||
DEFERRED_LIBRARY_URIS,
|
||||
DEFERRED_LIBRARY_HASHES,
|
||||
DEFERRED_LIBRARY_PARTS,
|
||||
DEFERRED_PART_URIS,
|
||||
DEFERRED_PART_HASHES,
|
||||
GET_TYPE_FROM_NAME,
|
||||
INITIALIZE_EMPTY_INSTANCE,
|
||||
INITIALIZE_LOADED_HUNK,
|
||||
|
|
|
@ -6,8 +6,9 @@ library _js_helper;
|
|||
|
||||
import 'dart:_js_embedded_names'
|
||||
show
|
||||
DEFERRED_LIBRARY_URIS,
|
||||
DEFERRED_LIBRARY_HASHES,
|
||||
DEFERRED_LIBRARY_PARTS,
|
||||
DEFERRED_PART_URIS,
|
||||
DEFERRED_PART_HASHES,
|
||||
GET_TYPE_FROM_NAME,
|
||||
GET_ISOLATE_TAG,
|
||||
INITIALIZE_LOADED_HUNK,
|
||||
|
@ -3642,14 +3643,21 @@ typedef void DeferredLoadCallback();
|
|||
DeferredLoadCallback deferredLoadHook;
|
||||
|
||||
Future<Null> loadDeferredLibrary(String loadId) {
|
||||
// For each loadId there is a list of hunk-uris to load, and a corresponding
|
||||
// list of hashes. These are stored in the app-global scope.
|
||||
var urisMap = JS_EMBEDDED_GLOBAL('', DEFERRED_LIBRARY_URIS);
|
||||
List<String> uris = JS('JSExtendableArray|Null', '#[#]', urisMap, loadId);
|
||||
if (uris == null) return new Future.value(null);
|
||||
|
||||
var hashesMap = JS_EMBEDDED_GLOBAL('', DEFERRED_LIBRARY_HASHES);
|
||||
List<String> hashes = JS('JSExtendableArray|Null', '#[#]', hashesMap, loadId);
|
||||
// For each loadId there is a list of parts to load. The parts are represented
|
||||
// by an index. There are two arrays, one that maps the index into a Uri and
|
||||
// another that maps the index to a hash.
|
||||
var partsMap = JS_EMBEDDED_GLOBAL('', DEFERRED_LIBRARY_PARTS);
|
||||
List indexes = JS('JSExtendableArray|Null', '#[#]', partsMap, loadId);
|
||||
if (indexes == null) return new Future.value(null);
|
||||
List<String> uris = <String>[];
|
||||
List<String> hashes = <String>[];
|
||||
List index2uri = JS_EMBEDDED_GLOBAL('JSArray', DEFERRED_PART_URIS);
|
||||
List index2hash = JS_EMBEDDED_GLOBAL('JSArray', DEFERRED_PART_HASHES);
|
||||
for (int i = 0; i < indexes.length; i++) {
|
||||
int index = JS('int', '#[#]', indexes, i);
|
||||
uris.add(JS('String', '#[#]', index2uri, index));
|
||||
hashes.add(JS('String', '#[#]', index2hash, index));
|
||||
}
|
||||
|
||||
int total = hashes.length;
|
||||
assert(total == uris.length);
|
||||
|
|
|
@ -175,23 +175,34 @@ const CLASS_FIELDS_EXTRACTOR = 'classFieldsExtractor';
|
|||
/// This embedded global is used for deserialization in the isolate-library.
|
||||
const INITIALIZE_EMPTY_INSTANCE = "initializeEmptyInstance";
|
||||
|
||||
/// Returns a map from load-ids to URIs.
|
||||
/// Contains a map from load-ids to lists of part indexes.
|
||||
///
|
||||
/// To load the deferred library that is represented by the load-id, the runtime
|
||||
/// must load all associated URIs.
|
||||
/// must load all associated URIs (named in DEFERRED_PART_URIS) and initialize
|
||||
/// all the loaded hunks (DEFERRED_PART_HASHES).
|
||||
///
|
||||
/// This embedded global is only used for deferred loading.
|
||||
const DEFERRED_LIBRARY_URIS = 'deferredLibraryUris';
|
||||
const DEFERRED_LIBRARY_PARTS = 'deferredLibraryParts';
|
||||
|
||||
/// Returns a map from load-ids to hashes.
|
||||
/// Contains a list of URIs (Strings), indexed by part.
|
||||
///
|
||||
/// The lists in the DEFERRED_LIBRARY_PARTS map contain indexes into this list.
|
||||
///
|
||||
/// This embedded global is only used for deferred loading.
|
||||
const DEFERRED_PART_URIS = 'deferredPartUris';
|
||||
|
||||
/// Contains a list of hashes, indexed by part.
|
||||
///
|
||||
/// The lists in the DEFERRED_LIBRARY_PARTS map contain indexes into this list.
|
||||
///
|
||||
/// The hashes are associated with the URIs of the load-ids (see
|
||||
/// [DEFERRED_LIBRARY_URIS]). They are MD5 (or similar) hashes of the code that
|
||||
/// must be loaded. By using cryptographic hashes we can avoid loading similar
|
||||
/// code multiple times.
|
||||
/// [DEFERRED_PART_URIS]). They are SHA1 (or similar) hashes of the code that
|
||||
/// must be loaded. By using cryptographic hashes we can (1) handle loading in
|
||||
/// the same web page the parts from multiple Dart applications (2) avoid
|
||||
/// loading similar code multiple times.
|
||||
///
|
||||
/// This embedded global is only used for deferred loading.
|
||||
const DEFERRED_LIBRARY_HASHES = 'deferredLibraryHashes';
|
||||
const DEFERRED_PART_HASHES = 'deferredPartHashes';
|
||||
|
||||
/// Initialize a loaded hunk.
|
||||
///
|
||||
|
|
Loading…
Reference in a new issue