Initialize the deferred global for every fragment.

This makes it possible to concatenate commonly used fragments in front of the main fragment. For example, if an application knows that it will immediately load a fragment, it can prefix its main fragment with that fragment.

R=sra@google.com

Review URL: https://codereview.chromium.org/1508543003 .
This commit is contained in:
Florian Loitsch 2015-12-09 01:20:58 +01:00
parent 7de1d190b9
commit aae5517866
3 changed files with 28 additions and 28 deletions

View file

@ -1371,6 +1371,16 @@ class Emitter implements js_emitter.Emitter {
assembleTypedefs(program);
}
jsAst.Statement buildDeferredHeader() {
/// For deferred loading we communicate the initializers via this global
/// variable. The deferred hunks will add their initialization to this.
/// The semicolon is important in minified mode, without it the
/// following parenthesis looks like a call to the object literal.
return js.statement('self.#deferredInitializers = '
'self.#deferredInitializers || Object.create(null);',
{'deferredInitializers': deferredInitializers});
}
jsAst.Program buildOutputAstForMain(Program program,
Map<OutputUnit, _DeferredOutputUnitHash> deferredLoadHashes) {
MainFragment mainFragment = program.mainFragment;
@ -1383,14 +1393,7 @@ class Emitter implements js_emitter.Emitter {
..add(js.comment(HOOKS_API_USAGE));
if (isProgramSplit) {
/// For deferred loading we communicate the initializers via this global
/// variable. The deferred hunks will add their initialization to this.
/// The semicolon is important in minified mode, without it the
/// following parenthesis looks like a call to the object literal.
statements.add(
js.statement('self.#deferredInitializers = '
'self.#deferredInitializers || Object.create(null);',
{'deferredInitializers': deferredInitializers}));
statements.add(buildDeferredHeader());
}
// Collect the AST for the decriptors
@ -1999,6 +2002,7 @@ function(originalDescriptor, name, holder, isStatic, globalFunctionsAccess) {
statements
..add(buildGeneratedBy())
..add(buildDeferredHeader())
..add(js.statement('${deferredInitializers}.current = '
"""function (#, ${namer.staticStateHolder}) {
#

View file

@ -55,11 +55,6 @@ const String cachedClassFieldNames = r'$cachedFieldNames';
// names we want. Furthermore, the pretty-printer minifies local variables, thus
// reducing their size.
const String mainBoilerplate = '''
{
// Declare deferred-initializer global, which is used to keep track of the
// loaded fragments.
#deferredInitializer;
(function() {
// Copies the own properties from [from] to [to].
function copyProperties(from, to) {
@ -355,8 +350,8 @@ var #staticStateDeclaration = {};
// Invokes main (making sure that it records the 'current-script' value).
#invokeMain;
})();
}''';
})()
''';
/// Deferred fragments (aka 'hunks') are built similarly to the main fragment.
///
@ -441,8 +436,7 @@ class FragmentEmitter {
.where((Holder holder) => !holder.isStaticStateHolder);
return js.js.statement(mainBoilerplate,
{'deferredInitializer': emitDeferredInitializerGlobal(program.loadMap),
'typeNameProperty': js.string(ModelEmitter.typeNameProperty),
{'typeNameProperty': js.string(ModelEmitter.typeNameProperty),
'cyclicThrow': backend.emitter.staticFunctionAccess(
backend.helpers.cyclicThrowHelper),
'operatorIsPrefix': js.string(namer.operatorIsPrefix),
@ -516,15 +510,6 @@ class FragmentEmitter {
});
}
js.Statement emitDeferredInitializerGlobal(Map loadMap) {
if (loadMap.isEmpty) return new js.Block.empty();
String global = ModelEmitter.deferredInitializersGlobal;
return js.js.statement(
"if (typeof($global) === 'undefined') var # = Object.create(null);",
new js.VariableDeclaration(global, allowRename: false));
}
/// Emits all holders, except for the static-state holder.
///
/// The emitted holders contain classes (only the constructors) and all

View file

@ -208,7 +208,8 @@ class ModelEmitter {
token.setHash(hunkHashes[key]);
});
writeMainFragment(mainFragment, mainCode);
writeMainFragment(mainFragment, mainCode,
isSplit: program.deferredFragments.isNotEmpty);
if (backend.requiresPreamble &&
!backend.htmlLibraryIsLoaded) {
@ -249,10 +250,18 @@ class ModelEmitter {
return hunkHashes;
}
js.Statement buildDeferredInitializerGlobal() {
String global = deferredInitializersGlobal;
return js.js.statement(
"if (typeof($global) === 'undefined') var # = Object.create(null);",
new js.VariableDeclaration(global, allowRename: false));
}
// Writes the given [fragment]'s [code] into a file.
//
// Updates the shared [outputBuffers] field with the output.
void writeMainFragment(MainFragment fragment, js.Statement code) {
void writeMainFragment(MainFragment fragment, js.Statement code,
{bool isSplit}) {
LineColumnCollector lineColumnCollector;
List<CodeOutputListener> codeOutputListeners;
if (shouldGenerateSourceMap) {
@ -268,6 +277,7 @@ class ModelEmitter {
js.Program program = new js.Program([
buildGeneratedBy(),
new js.Comment(HOOKS_API_USAGE),
isSplit ? buildDeferredInitializerGlobal() : new js.Block.empty(),
code]);
mainOutput.addBuffer(js.prettyPrint(program, compiler,
@ -321,6 +331,7 @@ class ModelEmitter {
js.Program program = new js.Program([
buildGeneratedBy(),
buildDeferredInitializerGlobal(),
js.js.statement('$deferredInitializersGlobal.current = #', code)]);
output.addBuffer(js.prettyPrint(program, compiler,