Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(519)

Unified Diff: pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart

Issue 2847343002: Add support for profile-based startup optimizations. (Closed)
Patch Set: Address comments. Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
index dbd8e3121903d65b9e8f428f6927d4ab149784d8..f87a10d45a18b231218841ed1d710b90730bc476 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
@@ -297,7 +297,7 @@ function initializeDeferredHunk(hunk) {
hunk(inherit, mixin, lazy, makeConstList, convertToFastObject, installTearOff,
setFunctionNamesIfNecessary, updateHolder, updateTypes,
setOrUpdateInterceptorsByTag, setOrUpdateLeafTags,
- #embeddedGlobalsObject, #holdersList, #staticState);
+ #embeddedGlobalsObject, holders, #staticState);
}
// Returns the global with the given [name].
@@ -313,11 +313,33 @@ function getGlobalFromName(name) {
}
}
+if (#hasSoftDeferredClasses) {
+ // Loads the soft-deferred classes and initializes them.
+ // Updates the prototype of the given object.
+ function softDef(o) {
+ softDef = function(o) {}; // Replace ourselves.
+ #deferredGlobal[#softId](
+ holders, #embeddedGlobalsObject, #staticState, inherit, mixin,
+ installTearOff);
+ if (o != null) {
+ // TODO(29574): should we do something different for Firefox?
+ // If we recommend that the program triggers the load by itself before
+ // classes are needed, then this line should rarely be hit.
+ // Also, it is only hit at most once (per soft-deferred chunk).
+ o.__proto__ = o.constructor.prototype;
+ }
+ }
+}
+
+if (#isTrackingAllocations) {
+ var allocations = #deferredGlobal['allocations'] = {};
+}
+
// Creates the holders.
#holders;
// If the name is not set on the functions, do it now.
-setFunctionNamesIfNecessary(#holdersList);
+setFunctionNamesIfNecessary(holders);
// TODO(floitsch): we should build this object as a literal.
var #staticStateDeclaration = {};
@@ -429,6 +451,28 @@ updateTypes(#types);
#nativeSupport;
}''';
+/// Soft-deferred fragments are built similarly to the main fragment.
+///
+/// However, they don't contribute anything to global namespace, but just
+/// initialize existing classes. For example, they update the inheritance
+/// hierarchy, and add methods the prototypes.
+const String softDeferredBoilerplate = '''
+#deferredGlobal[#softId] =
+ function(holdersList, #embeddedGlobalsObject, #staticState, inherit, mixin,
+ installTearOff) {
+
+// Installs the holders as local variables.
+#installHoldersAsLocals;
+// Sets the prototypes of the new classes.
+#prototypes;
+// Sets aliases of methods (on the prototypes of classes).
+#aliases;
+// Installs the tear-offs of functions.
+#tearOffs;
+// Builds the inheritance structure.
+#inheritance;
+}''';
+
/**
* This class builds a JavaScript tree for a given fragment.
*
@@ -464,7 +508,9 @@ class FragmentEmitter {
Iterable<Holder> nonStaticStateHolders =
program.holders.where((Holder holder) => !holder.isStaticStateHolder);
- return js.js.statement(mainBoilerplate, {
+ String softDeferredId = "softDeferred${new Random().nextInt(0x7FFFFFFF)}";
+
+ js.Statement mainCode = js.js.statement(mainBoilerplate, {
'directAccessTestExpression': js.js(directAccessTestExpression),
'typeNameProperty': js.string(ModelEmitter.typeNameProperty),
'cyclicThrow': backend.emitter
@@ -477,9 +523,6 @@ class FragmentEmitter {
generateEmbeddedGlobalAccess(INTERCEPTORS_BY_TAG),
'embeddedLeafTags': generateEmbeddedGlobalAccess(LEAF_TAGS),
'embeddedGlobalsObject': js.js("init"),
- 'holdersList': new js.ArrayInitializer(nonStaticStateHolders
- .map((holder) => js.js("#", holder.name))
- .toList(growable: false)),
'staticStateDeclaration': new js.VariableDeclaration(
namer.staticStateHolder,
allowRename: false),
@@ -490,6 +533,10 @@ class FragmentEmitter {
'stubName': js.string(namer.stubNameField),
'argumentCount': js.string(namer.requiredParameterField),
'defaultArgumentValues': js.string(namer.defaultValuesField),
+ 'deferredGlobal': ModelEmitter.deferredInitializersGlobal,
+ 'hasSoftDeferredClasses': program.hasSoftDeferredClasses,
+ 'softId': js.string(softDeferredId),
+ 'isTrackingAllocations': compiler.options.experimentalTrackAllocations,
'prototypes': emitPrototypes(fragment),
'inheritance': emitInheritance(fragment),
'aliases': emitInstanceMethodAliases(fragment),
@@ -506,6 +553,36 @@ class FragmentEmitter {
: new js.EmptyStatement(),
'invokeMain': fragment.invokeMain,
});
+ if (program.hasSoftDeferredClasses) {
+ return new js.Block([
+ js.js.statement(softDeferredBoilerplate, {
+ 'deferredGlobal': ModelEmitter.deferredInitializersGlobal,
+ 'softId': js.string(softDeferredId),
+ // TODO(floitsch): don't just reference 'init'.
+ 'embeddedGlobalsObject': new js.Parameter('init'),
+ 'staticState': new js.Parameter(namer.staticStateHolder),
+ 'installHoldersAsLocals':
+ emitInstallHoldersAsLocals(nonStaticStateHolders),
+ 'prototypes': emitPrototypes(fragment, softDeferred: true),
+ 'aliases': emitInstanceMethodAliases(fragment, softDeferred: true),
+ 'tearOffs': emitInstallTearOffs(fragment, softDeferred: true),
+ 'inheritance': emitInheritance(fragment, softDeferred: true),
+ }),
+ mainCode
+ ]);
+ }
+ return mainCode;
+ }
+
+ js.Statement emitInstallHoldersAsLocals(Iterable<Holder> holders) {
+ List<js.Statement> holderInits = <js.Statement>[];
+ int counter = 0;
+ for (Holder holder in holders) {
+ holderInits.add(new js.ExpressionStatement(new js.VariableInitialization(
+ new js.VariableDeclaration(holder.name, allowRename: false),
+ js.js("holdersList[#]", js.number(counter++)))));
+ }
+ return new js.Block(holderInits);
}
js.Expression emitDeferredFragment(DeferredFragment fragment,
@@ -657,6 +734,14 @@ class FragmentEmitter {
var parameters = <js.Name>[];
var thisRef;
+ if (cls.isSoftDeferred) {
+ statements.add(js.js.statement('softDef(this)'));
+ } else if (compiler.options.experimentalTrackAllocations) {
+ String qualifiedName =
+ "${cls.element.library.canonicalUri}:${cls.element.name}";
+ statements.add(js.js.statement('allocations["$qualifiedName"] = true'));
+ }
+
// If there are many references to `this`, cache it in a local.
if (cls.fields.length + (cls.hasRtiField ? 1 : 0) >= 4) {
// TODO(29455): Fix js_ast printer and minifier to avoid conflicts between
@@ -697,9 +782,10 @@ class FragmentEmitter {
///
/// This section updates the prototype-property of all constructors in the
/// global holders.
- js.Statement emitPrototypes(Fragment fragment) {
+ js.Statement emitPrototypes(Fragment fragment, {softDeferred = false}) {
List<js.Statement> assignments = fragment.libraries
.expand((Library library) => library.classes)
+ .where((Class cls) => cls.isSoftDeferred == softDeferred)
.map((Class cls) {
var proto = js.js.statement(
'#.prototype = #;', [classReference(cls), emitPrototype(cls)]);
@@ -864,13 +950,14 @@ class FragmentEmitter {
///
/// In this section prototype chains are updated and mixin functions are
/// copied.
- js.Statement emitInheritance(Fragment fragment) {
+ js.Statement emitInheritance(Fragment fragment, {bool softDeferred = false}) {
List<js.Statement> inheritCalls = <js.Statement>[];
List<js.Statement> mixinCalls = <js.Statement>[];
Set<Class> classesInFragment = new Set<Class>();
for (Library library in fragment.libraries) {
- classesInFragment.addAll(library.classes);
+ classesInFragment.addAll(library.classes
+ .where(((Class cls) => cls.isSoftDeferred == softDeferred)));
}
Map<Class, List<Class>> subclasses = <Class, List<Class>>{};
@@ -891,6 +978,7 @@ class FragmentEmitter {
for (Library library in fragment.libraries) {
for (Class cls in library.classes) {
+ if (cls.isSoftDeferred != softDeferred) continue;
collect(cls);
if (cls.isMixinApplication) {
@@ -937,11 +1025,13 @@ class FragmentEmitter {
///
/// This step consists of simply copying JavaScript functions to their
/// aliased names so they point to the same function.
- js.Statement emitInstanceMethodAliases(Fragment fragment) {
+ js.Statement emitInstanceMethodAliases(Fragment fragment,
+ {bool softDeferred = false}) {
List<js.Statement> assignments = <js.Statement>[];
for (Library library in fragment.libraries) {
for (Class cls in library.classes) {
+ if (cls.isSoftDeferred != softDeferred) continue;
for (InstanceMethod method in cls.methods) {
if (method.aliasName != null) {
assignments.add(js.js.statement('#.prototype.# = #.prototype.#', [
@@ -1066,7 +1156,8 @@ class FragmentEmitter {
}
/// Emits the section that installs tear-off getters.
- js.Statement emitInstallTearOffs(Fragment fragment) {
+ js.Statement emitInstallTearOffs(Fragment fragment,
+ {bool softDeferred = false}) {
List<js.Statement> inits = <js.Statement>[];
js.Expression temp;
@@ -1082,6 +1173,7 @@ class FragmentEmitter {
}
}
for (Class cls in library.classes) {
+ if (cls.isSoftDeferred != softDeferred) continue;
var methods = cls.methods.where((m) => m.needsTearOff).toList();
js.Expression container = js.js("#.prototype", classReference(cls));
js.Expression reference = container;

Powered by Google App Engine
This is Rietveld 408576698