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

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: Fix forgotten cleanup. Created 3 years, 8 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 55f9f290c18e6b14e4b93ec3457b5213a293f1f8..977c4841bd5c1dbd24659161dfd68c732a375e76 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,27 @@ 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);
+ o.__proto__ = o.constructor.prototype;
sra1 2017/05/02 20:40:13 This will make Firefox angry.
floitsch 2017/05/06 19:25:43 Yes. I added a comment.
+ }
+}
+
+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 +445,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,48 +502,80 @@ class FragmentEmitter {
Iterable<Holder> nonStaticStateHolders =
program.holders.where((Holder holder) => !holder.isStaticStateHolder);
- return js.js.statement(mainBoilerplate, {
- 'directAccessTestExpression': js.js(directAccessTestExpression),
- 'typeNameProperty': js.string(ModelEmitter.typeNameProperty),
- 'cyclicThrow': backend.emitter
- .staticFunctionAccess(compiler.commonElements.cyclicThrowHelper),
- 'operatorIsPrefix': js.string(namer.operatorIsPrefix),
- 'tearOffCode': new js.Block(buildTearOffCode(compiler.options,
- backend.emitter.emitter, backend.namer, compiler.commonElements)),
- 'embeddedTypes': generateEmbeddedGlobalAccess(TYPES),
- 'embeddedInterceptorTags':
- 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),
- 'staticState': js.js('#', namer.staticStateHolder),
- 'constantHolderReference': buildConstantHolderReference(program),
- 'holders': emitHolders(program.holders, fragment),
- 'callName': js.string(namer.callNameField),
- 'stubName': js.string(namer.stubNameField),
- 'argumentCount': js.string(namer.requiredParameterField),
- 'defaultArgumentValues': js.string(namer.defaultValuesField),
- 'prototypes': emitPrototypes(fragment),
- 'inheritance': emitInheritance(fragment),
- 'aliases': emitInstanceMethodAliases(fragment),
- 'tearOffs': emitInstallTearOffs(fragment),
- 'constants': emitConstants(fragment),
- 'staticNonFinalFields': emitStaticNonFinalFields(fragment),
- 'lazyStatics': emitLazilyInitializedStatics(fragment),
- 'embeddedGlobals': emitEmbeddedGlobals(program, deferredLoadHashes),
- 'nativeSupport': program.needsNativeSupport
- ? emitNativeSupport(fragment)
- : new js.EmptyStatement(),
- 'jsInteropSupport': backend.jsInteropAnalysis.enabledJsInterop
- ? backend.jsInteropAnalysis.buildJsInteropBootstrap()
+ String softDeferredId = "softDeferred${new Random().nextInt(0x7FFFFFFF)}";
+
+ return new js.Block([
+ program.hasSoftDeferredClasses
+ ? 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),
+ })
: new js.EmptyStatement(),
- 'invokeMain': fragment.invokeMain,
- });
+ js.js.statement(mainBoilerplate, {
+ 'directAccessTestExpression': js.js(directAccessTestExpression),
+ 'typeNameProperty': js.string(ModelEmitter.typeNameProperty),
+ 'cyclicThrow': backend.emitter
+ .staticFunctionAccess(compiler.commonElements.cyclicThrowHelper),
+ 'operatorIsPrefix': js.string(namer.operatorIsPrefix),
+ 'tearOffCode': new js.Block(buildTearOffCode(compiler.options,
+ backend.emitter.emitter, backend.namer, compiler.commonElements)),
+ 'embeddedTypes': generateEmbeddedGlobalAccess(TYPES),
+ 'embeddedInterceptorTags':
+ generateEmbeddedGlobalAccess(INTERCEPTORS_BY_TAG),
+ 'embeddedLeafTags': generateEmbeddedGlobalAccess(LEAF_TAGS),
+ 'embeddedGlobalsObject': js.js("init"),
+ 'staticStateDeclaration': new js.VariableDeclaration(
+ namer.staticStateHolder,
+ allowRename: false),
+ 'staticState': js.js('#', namer.staticStateHolder),
+ 'constantHolderReference': buildConstantHolderReference(program),
+ 'holders': emitHolders(program.holders, fragment),
+ 'callName': js.string(namer.callNameField),
+ '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.trackAllocations,
+ 'prototypes': emitPrototypes(fragment),
+ 'inheritance': emitInheritance(fragment),
+ 'aliases': emitInstanceMethodAliases(fragment),
+ 'tearOffs': emitInstallTearOffs(fragment),
+ 'constants': emitConstants(fragment),
+ 'staticNonFinalFields': emitStaticNonFinalFields(fragment),
+ 'lazyStatics': emitLazilyInitializedStatics(fragment),
+ 'embeddedGlobals': emitEmbeddedGlobals(program, deferredLoadHashes),
+ 'nativeSupport': program.needsNativeSupport
+ ? emitNativeSupport(fragment)
+ : new js.EmptyStatement(),
+ 'jsInteropSupport': backend.jsInteropAnalysis.enabledJsInterop
+ ? backend.jsInteropAnalysis.buildJsInteropBootstrap()
+ : new js.EmptyStatement(),
+ 'invokeMain': fragment.invokeMain,
+ }),
+ ]);
+ }
+
+ 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 +727,14 @@ class FragmentEmitter {
var parameters = <js.Name>[];
var thisRef;
+ if (cls.isSoftDeferred) {
+ statements.add(js.js.statement('softDef(this)'));
+ } else if (compiler.options.trackAllocations) {
+ 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 +775,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 +943,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 +971,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 +1018,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 +1149,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 +1166,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