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

Side by Side 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 unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 part of dart2js.js_emitter.startup_emitter.model_emitter; 5 part of dart2js.js_emitter.startup_emitter.model_emitter;
6 6
7 /// The fast startup emitter's goal is to minimize the amount of work that the
8 /// JavaScript engine has to do before it can start running user code.
9 ///
10 /// Whenever possible, the emitter uses object literals instead of updating
11 /// objects.
12 ///
13 /// Example:
14 ///
15 /// // Holders are initialized directly with the classes and static
16 /// // functions.
17 /// var A = { Point: function Point(x, y) { this.x = x; this.y = y },
18 /// someStaticFunction: function someStaticFunction() { ... } };
19 ///
20 /// // Class-behavior is emitted in a prototype object that is directly
21 /// // assigned:
22 /// A.Point.prototype = { distanceTo: function(other) { ... } };
23 ///
24 /// // Inheritance is achieved by updating the prototype objects (hidden in
25 /// // a helper function):
26 /// A.Point.prototype.__proto__ = H.Object.prototype;
27 ///
28 /// The emitter doesn't try to be clever and emits everything beforehand. This
29 /// increases the output size, but improves performance.
30 ///
31 // The code relies on the fact that all Dart code is inside holders. As such
32 // we can use "global" names however we want. As long as we don't shadow
33 // JavaScript variables (like `Array`) we are free to chose whatever variable
34 // names we want. Furthermore, the minifier reduces the names of the variables.
35 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
36 {
37 // Declare deferred-initializer global, which is used to keep track of the
38 // loaded fragments.
39 #deferredInitializer;
40
41 (function() {
42 // Copies the own properties from [from] to [to].
43 function copyProperties(from, to) {
44 var keys = Object.keys(from);
45 for (var i = 0; i < keys.length; i++) {
46 to[keys[i]] = from[keys[i]];
47 }
48 }
49
50 // Makes [cls] inherit from [sup].
51 // On Chrome, Firefox and recent IEs this happens by updating the internal
52 // proto-property of the classes 'prototype' field.
53 // Older IEs use `Object.create` and copy over the properties.
54 function inherit(cls, sup) {
55 // TODO(floitsch): IE doesn't support changing the __proto__ property. There,
56 // we need to copy the properties instead.
57 cls.#typeNameProperty = cls.name; // Needed for RTI.
58 cls.prototype.constructor = cls;
59 cls.prototype[#operatorIsPrefix + cls.name] = cls;
60 cls.prototype.__proto__ = sup.prototype;
61 }
62
63 // Mixes in the properties of [mixin] into [cls].
64 function mixin(cls, mixin) {
65 copyProperties(mixin.prototype, cls.prototype);
66 }
67
68 // Creates a lazy field.
69 //
70 // A lazy field has a storage entry, [name], which holds the value, and a
71 // getter ([getterName]) to access the field. If the field wasn't set before
72 // the first access, it is initialized with the [initializer].
73 function lazy(holder, name, getterName, initializer) {
74 holder[name] = null;
75 holder[getterName] = function() {
76 holder[getterName] = function() { #cyclicThrow(name) };
77 var result;
78 var sentinelInProgress = initializer;
79 try {
80 result = holder[name] = sentinelInProgress;
81 result = holder[name] = initializer();
82 } finally {
83 // Use try-finally, not try-catch/throw as it destroys the stack
84 // trace.
85 if (result === sentinelInProgress) {
86 // The lazy static (holder[name]) might have been set to a different
87 // value. According to spec we still have to reset it to null, if
88 // the initialization failed.
89 holder[name] = null;
90 }
91 // TODO(floitsch): for performance reasons the function should probably
92 // be unique for each static.
93 holder[getterName] = function() { return this[name]; };
94 }
95 return result;
96 };
97 }
98
99 // Given a list, marks it as constant.
100 //
101 // The runtime ensures that const-lists cannot be modified.
102 function makeConstList(list) {
103 // By assigning a function to the properties they become part of the
104 // hidden class. The actual values of the fields don't matter, since we
105 // only check if they exist.
106 list.immutable\$list = Array;
107 list.fixed\$length = Array;
108 return list;
109 }
110
111 // TODO(floitsch): provide code for tear-offs.
112
113 // Instead of setting the interceptor tags directly we use this update
114 // function. This makes it easier for deferred fragments to contribute to the
115 // embedded global.
116 function setOrUpdateInterceptorsByTag(newTags) {
117 var tags = #embeddedInterceptorTags;
118 if (!tags) {
119 #embeddedInterceptorTags = newTags;
120 return;
121 }
122 copyProperties(newTags, tags);
123 }
124
125 // Instead of setting the leaf tags directly we use this update
126 // function. This makes it easier for deferred fragments to contribute to the
127 // embedded global.
128 function setOrUpdateLeafTags(newTags) {
129 var tags = #embeddedLeafTags;
130 if (!tags) {
131 #embeddedLeafTags = newTags;
132 return;
133 }
134 copyProperties(newTags, tags);
135 }
136
137 // Updates the types embedded global.
138 function updateTypes(newTypes) {
139 var types = #embeddedTypes;
140 types.push.apply(types, newTypes);
141 }
142
143 // Updates the given holder with the properties of the [newHolder].
144 // This function is used when a deferred fragment is initialized.
145 function updateHolder(holder, newHolder) {
146 // TODO(floitsch): updating the prototype (instead of copying) is
147 // *horribly* inefficient in Firefox. There we should just copy the
148 // properties.
149 var oldPrototype = holder.__proto__;
150 newHolder.__proto__ = oldPrototype;
151 holder.__proto__ = newHolder;
152 return holder;
153 }
154
155 // Every deferred hunk (i.e. fragment) is a function that we can invoke to
156 // initialize it. At this moment it contributes its data to the main hunk.
157 function initializeDeferredHunk(hunk) {
158 // TODO(floitsch): extend natives.
159 hunk(derive, mixin, lazy, makeConstList, installTearOff,
160 updateHolder, updateTypes, updateInterceptorsByTag, updateLeafTags,
161 #embeddedGlobalsObject, #holdersList, #currentIsolate);
162 }
163
164 // Creates the holders.
165 #holders;
166 // Sets the prototypes of classes.
167 #prototypes;
168 // Sets aliases of methods (on the prototypes of classes).
169 #aliases;
170 // Installs the tear-offs of functions.
171 #tearOffs;
172 // Builds the inheritance structure.
173 #inheritance;
174
175 // Emits the embedded globals.
176 #embeddedGlobals;
177
178 // Sets up the native support.
179 // Native-support uses setOrUpdateInterceptorsByTag and setOrUpdateLeafTags.
180 #nativeSupport;
181
182 // Instantiates all constants.
183 #constants;
184 // Initializes the static non-final fields (with their constant values).
185 #staticNonFinalFields;
186 // Creates lazy getters for statics that must run initializers on first access.
187 #lazyStatics;
188
189 // Invokes main (making sure that it records the 'current-script' value).
190 #invokeMain;
191 })();
192 }''';
193
194 /// Deferred fragments (aka 'hunks') are built similarly to the main fragment.
195 ///
196 /// However, at specific moments they need to contribute their data.
197 /// For example, once the holders have been created, they are included into
198 /// the main holders.
199 const String deferredBoilerplate = '''
200 {
201 #deferredInitializers.current =
202 function(derive, mixin, lazy, makeConstList, installTearOff,
203 updateHolder, updateTypes,
204 setOrUpdateInterceptorsByTag, setOrUpdateLeafTags,
205 #embeddedGlobalsObject, holdersList, #currentIsolate) {
206
207 // Builds the holders. They only contain the data for new holders.
208 #holders;
209 // Updates the holders of the main-fragment. Uses the provided holdersList to
210 // access the main holders.
211 // The local holders are replaced by the combined holders. This is necessary
212 // for the inheritance setup below.
213 #updateHolders;
214 // Sets the prototypes of the new classes.
215 #prototypes;
216 // Sets aliases of methods (on the prototypes of classes).
217 #aliases;
218 // Installs the tear-offs of functions.
219 #tearOffs;
220 // Builds the inheritance structure.
221 #inheritance;
222
223 updateTypes(#types);
224
225 // Native-support uses setOrUpdateInterceptorsByTag and setOrUpdateLeafTags.
226 #nativeSupport;
227
228 // Instantiates all constants of this deferred fragment.
229 // Note that the constant-holder has been updated earlier and storing the
230 // constant values in the constant-holder makes them available globally.
231 #constants;
232 // Initializes the static non-final fields (with their constant values).
233 #staticNonFinalFields;
234 // Creates lazy getters for statics that must run initializers on first access.
235 #lazyStatics;
236 };
237 // TODO(floitsch): this last line should be outside the AST, since it
238 // requires to know the hash of the part of the code above this comment.
239 #deferredInitializers[#hash] = #deferredInitializers.current;
240 }''';
241
7 /** 242 /**
8 * This class builds a JavaScript tree for a given fragment. 243 * This class builds a JavaScript tree for a given fragment.
9 * 244 *
10 * A fragment is generally written into a separate file so that it can be 245 * A fragment is generally written into a separate file so that it can be
11 * loaded dynamically when a deferred library is loaded. 246 * loaded dynamically when a deferred library is loaded.
12 * 247 *
13 * This class is stateless and can be reused for different fragments. 248 * This class is stateless and can be reused for different fragments.
14 */ 249 */
15 class FragmentEmitter { 250 class FragmentEmitter {
16 final Compiler compiler; 251 final Compiler compiler;
(...skipping 15 matching lines...) Expand all
32 MainFragment fragment = program.fragments.first; 267 MainFragment fragment = program.fragments.first;
33 throw new UnimplementedError('emitMain'); 268 throw new UnimplementedError('emitMain');
34 } 269 }
35 270
36 js.Statement emitDeferredFragment(DeferredFragment fragment, 271 js.Statement emitDeferredFragment(DeferredFragment fragment,
37 js.Expression deferredTypes, 272 js.Expression deferredTypes,
38 List<Holder> holders) { 273 List<Holder> holders) {
39 throw new UnimplementedError('emitDeferred'); 274 throw new UnimplementedError('emitDeferred');
40 } 275 }
41 } 276 }
OLDNEW
« 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