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

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

Issue 1229913003: dart2js: Add boilerplate strings for the startup-emitter. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: reupload Created 5 years, 5 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
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 2e271d0b2a5d33e006e8e9aa21a7c29479a91d69..390ecd684ea42eb5ace5a8127e5759c023f5294b 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
@@ -4,6 +4,241 @@
part of dart2js.js_emitter.startup_emitter.model_emitter;
+/// The fast startup emitter's goal is to minimize the amount of work that the
+/// JavaScript engine has to do before it can start running user code.
+///
+/// Whenever possible, the emitter uses object literals instead of updating
+/// objects.
+///
+/// Example:
+///
+/// // Holders are initialized directly with the classes and static
+/// // functions.
+/// var A = { Point: function Point(x, y) { this.x = x; this.y = y },
+/// someStaticFunction: function someStaticFunction() { ... } };
+///
+/// // Class-behavior is emitted in a prototype object that is directly
+/// // assigned:
+/// A.Point.prototype = { distanceTo: function(other) { ... } };
+///
+/// // Inheritance is achieved by updating the prototype objects (hidden in
+/// // a helper function):
+/// A.Point.prototype.__proto__ = H.Object.prototype;
+///
+/// The emitter doesn't try to be clever and emits everything beforehand. This
+/// increases the output size, but improves performance.
+///
+// The code relies on the fact that all Dart code is inside holders. As such
+// we can use "global" names however we want. As long as we don't shadow
+// JavaScript variables (like `Array`) we are free to chose whatever variable
+// names we want. Furthermore, the minifier reduces the names of the variables.
+const String mainBoilerplate = '''
Siggi Cherem (dart-lang) 2015/07/14 15:57:25 minor nit question: Since you have other changes s
floitsch 2015/07/17 17:59:32 I found this to be the most important part of the
+{
+// 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) {
+ var keys = Object.keys(from);
+ for (var i = 0; i < keys.length; i++) {
+ to[keys[i]] = from[keys[i]];
+ }
+}
+
+// Makes [cls] inherit from [sup].
+// On Chrome, Firefox and recent IEs this happens by updating the internal
+// proto-property of the classes 'prototype' field.
+// Older IEs use `Object.create` and copy over the properties.
+function inherit(cls, sup) {
+ // TODO(floitsch): IE doesn't support changing the __proto__ property. There,
+ // we need to copy the properties instead.
+ cls.#typeNameProperty = cls.name; // Needed for RTI.
+ cls.prototype.constructor = cls;
+ cls.prototype[#operatorIsPrefix + cls.name] = cls;
+ cls.prototype.__proto__ = sup.prototype;
+}
+
+// Mixes in the properties of [mixin] into [cls].
+function mixin(cls, mixin) {
+ copyProperties(mixin.prototype, cls.prototype);
+}
+
+// Creates a lazy field.
+//
+// A lazy field has a storage entry, [name], which holds the value, and a
+// getter ([getterName]) to access the field. If the field wasn't set before
+// the first access, it is initialized with the [initializer].
+function lazy(holder, name, getterName, initializer) {
+ holder[name] = null;
+ holder[getterName] = function() {
+ holder[getterName] = function() { #cyclicThrow(name) };
+ var result;
+ var sentinelInProgress = initializer;
+ try {
+ result = holder[name] = sentinelInProgress;
+ result = holder[name] = initializer();
+ } finally {
+ // Use try-finally, not try-catch/throw as it destroys the stack
+ // trace.
+ if (result === sentinelInProgress) {
+ // The lazy static (holder[name]) might have been set to a different
+ // value. According to spec we still have to reset it to null, if
+ // the initialization failed.
+ holder[name] = null;
+ }
+ // TODO(floitsch): for performance reasons the function should probably
+ // be unique for each static.
+ holder[getterName] = function() { return this[name]; };
+ }
+ return result;
+ };
+}
+
+// Given a list, marks it as constant.
+//
+// The runtime ensures that const-lists cannot be modified.
+function makeConstList(list) {
+ // By assigning a function to the properties they become part of the
+ // hidden class. The actual values of the fields don't matter, since we
+ // only check if they exist.
+ list.immutable\$list = Array;
+ list.fixed\$length = Array;
+ return list;
+}
+
+// TODO(floitsch): provide code for tear-offs.
+
+// Instead of setting the interceptor tags directly we use this update
+// function. This makes it easier for deferred fragments to contribute to the
+// embedded global.
+function setOrUpdateInterceptorsByTag(newTags) {
+ var tags = #embeddedInterceptorTags;
+ if (!tags) {
+ #embeddedInterceptorTags = newTags;
+ return;
+ }
+ copyProperties(newTags, tags);
+}
+
+// Instead of setting the leaf tags directly we use this update
+// function. This makes it easier for deferred fragments to contribute to the
+// embedded global.
+function setOrUpdateLeafTags(newTags) {
+ var tags = #embeddedLeafTags;
+ if (!tags) {
+ #embeddedLeafTags = newTags;
+ return;
+ }
+ copyProperties(newTags, tags);
+}
+
+// Updates the types embedded global.
+function updateTypes(newTypes) {
+ var types = #embeddedTypes;
+ types.push.apply(types, newTypes);
+}
+
+// Updates the given holder with the properties of the [newHolder].
+// This function is used when a deferred fragment is initialized.
+function updateHolder(holder, newHolder) {
+ // TODO(floitsch): updating the prototype (instead of copying) is
+ // *horribly* inefficient in Firefox. There we should just copy the
+ // properties.
+ var oldPrototype = holder.__proto__;
+ newHolder.__proto__ = oldPrototype;
+ holder.__proto__ = newHolder;
+ return holder;
+}
+
+// Every deferred hunk (i.e. fragment) is a function that we can invoke to
+// initialize it. At this moment it contributes its data to the main hunk.
+function initializeDeferredHunk(hunk) {
+ // TODO(floitsch): extend natives.
+ hunk(derive, mixin, lazy, makeConstList, installTearOff,
+ updateHolder, updateTypes, updateInterceptorsByTag, updateLeafTags,
+ #embeddedGlobalsObject, #holdersList, #currentIsolate);
+}
+
+// Creates the holders.
+#holders;
+// Sets the prototypes of classes.
+#prototypes;
+// Sets aliases of methods (on the prototypes of classes).
+#aliases;
+// Installs the tear-offs of functions.
+#tearOffs;
+// Builds the inheritance structure.
+#inheritance;
+
+// Emits the embedded globals.
+#embeddedGlobals;
+
+// Sets up the native support.
+// Native-support uses setOrUpdateInterceptorsByTag and setOrUpdateLeafTags.
+#nativeSupport;
+
+// Instantiates all constants.
+#constants;
+// Initializes the static non-final fields (with their constant values).
+#staticNonFinalFields;
+// Creates lazy getters for statics that must run initializers on first access.
+#lazyStatics;
+
+// Invokes main (making sure that it records the 'current-script' value).
+#invokeMain;
+})();
+}''';
+
+/// Deferred fragments (aka 'hunks') are built similarly to the main fragment.
+///
+/// However, at specific moments they need to contribute their data.
+/// For example, once the holders have been created, they are included into
+/// the main holders.
+const String deferredBoilerplate = '''
+{
+#deferredInitializers.current =
+function(derive, mixin, lazy, makeConstList, installTearOff,
+ updateHolder, updateTypes,
+ setOrUpdateInterceptorsByTag, setOrUpdateLeafTags,
+ #embeddedGlobalsObject, holdersList, #currentIsolate) {
+
+// Builds the holders. They only contain the data for new holders.
+#holders;
+// Updates the holders of the main-fragment. Uses the provided holdersList to
+// access the main holders.
+// The local holders are replaced by the combined holders. This is necessary
+// for the inheritance setup below.
+#updateHolders;
+// 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;
+
+updateTypes(#types);
+
+// Native-support uses setOrUpdateInterceptorsByTag and setOrUpdateLeafTags.
+#nativeSupport;
+
+// Instantiates all constants of this deferred fragment.
+// Note that the constant-holder has been updated earlier and storing the
+// constant values in the constant-holder makes them available globally.
+#constants;
+// Initializes the static non-final fields (with their constant values).
+#staticNonFinalFields;
+// Creates lazy getters for statics that must run initializers on first access.
+#lazyStatics;
+};
+// TODO(floitsch): this last line should be outside the AST, since it
+// requires to know the hash of the part of the code above this comment.
+#deferredInitializers[#hash] = #deferredInitializers.current;
+}''';
+
/**
* This class builds a JavaScript tree for a given fragment.
*
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698