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

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: 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.startup_js_emitter.model_emitter; 5 part of dart2js.startup_js_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.
herhut 2015/07/27 11:02:22 To be uber precise here, it is the pretty printer
floitsch 2015/07/29 15:26:24 Updated the comment (new CL coming). Since the hol
35 const String mainBoilerplate = '''
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 constructor.#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 initialize with the [initializer].
Siggi Cherem (dart-lang) 2015/07/09 23:54:07 nit: it is initialize => it is initialized
floitsch 2015/07/10 17:13:59 Done.
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 // This variable is used by the tearOffCode to guarantee unique functions per
112 // tear-offs.
113 var functionCounter = 0;
114 #tearOffCode;
115
116 // Adapts the stored data, so it's suitable for a tearOff call.
117 // TODO(floitsch): Change tearOffCode to accept the data directly, or create a
118 // different tearOffCode?
119 function installTearOff(container, getterName,
120 isStatic, isIntercepted, requiredParameterCount,
121 optionalParameterDefaultValues,
122 callNames, funNames, funType) {
123 var funs = [];
124 for (var i = 0; i < funNames.length; i++) {
125 var fun = container[funNames[i]];
126 fun.#callName = callNames[i];
127 funs.push(fun);
128 }
129
130 funs[0][#argumentCount] = requiredParameterCount;
131 funs[0][#defaultArgumentValues] = optionalParameterDefaultValues;
132 var reflectionInfo = funType;
133 var name = funNames[0];
134 container[getterName] =
135 tearOff(funs, reflectionInfo, isStatic, name, isIntercepted);
136 }
137
138 // Instead of setting the interceptor tags directly we use this update
139 // function. This makes it easier for deferred fragments to contribute to the
140 // embedded global.
141 function setOrUpdateInterceptorsByTag(newTags) {
142 var tags = #embeddedInterceptorTags;
143 if (!tags) {
144 #embeddedInterceptorTags = newTags;
145 return;
146 }
147 copyProperties(newTags, tags);
148 }
149
150 // Instead of setting the leaf tags directly we use this update
151 // function. This makes it easier for deferred fragments to contribute to the
152 // embedded global.
153 function setOrUpdateLeafTags(newTags) {
154 var tags = #embeddedLeafTags;
155 if (!tags) {
156 #embeddedLeafTags = newTags;
157 return;
158 }
159 copyProperties(newTags, tags);
160 }
161
162 // Updates the types embedded global.
163 function updateTypes(newTypes) {
164 var types = #embeddedTypes;
165 types.push.apply(types, newTypes);
166 }
167
168 // Updates the given holder with the properties of the [newHolder].
169 // This function is used when a deferred fragment is initialized.
170 function updateHolder(holder, newHolder) {
171 // TODO(floitsch): updating the prototype (instead of copying) is
172 // *horribly* inefficient in Firefox. There we should just copy the
173 // properties.
174 var oldPrototype = holder.__proto__;
175 newHolder.__proto__ = oldPrototype;
176 holder.__proto__ = newHolder;
177 return holder;
178 }
179
180 // Every deferred hunk (i.e. fragment) is a function that we can invoke to
181 // initialize it. At this moment it contributes its data to the main hunk.
182 function initializeDeferredHunk(hunk) {
183 // TODO(floitsch): extend natives.
184 hunk(derive, mixin, lazy, makeConstList, installTearOff,
185 updateHolder, updateTypes, updateInterceptorsByTag, updateLeafTags,
186 #embeddedGlobalsObject, #holdersList, #currentIsolate);
187 }
188
189 // Creates the holders.
190 #holders;
191 // Sets the prototypes of classes.
192 #prototypes;
193 // Sets aliases of methods (on the prototypes of classes).
194 #aliases;
195 // Installs the tear-offs of functions.
196 #tearOffs;
197 // Builds the inheritance structure.
198 #inheritance;
199
200 // Emits the embedded globals.
201 #embeddedGlobals;
202
203 // Sets up the native support.
204 // Native-support uses setOrUpdateInterceptorsByTag and setOrUpdateLeafTags.
205 #nativeSupport;
206
207 // Instantiates all constants.
208 #constants;
209 // Initializes the static non-final fields (with their constant values).
210 #staticNonFinalFields;
211 // Creates lazy getters for statics that must run initializers on first access.
212 #lazyStatics;
213
214 // Invokes main (making sure that it records the 'current-script' value).
215 #invokeMain;
216 })();
217 }''';
218
219 /// Deferred fragments (aka 'hunks') are built similarly to the main fragment.
220 ///
221 /// However, at specific moments they need to contribute their data.
222 /// For example, once the holders have been created, they are included into
223 /// the main holders.
224 const String deferredBoilerplate = '''
225 {
226 #deferredInitializers.current =
227 function(derive, mixin, lazy, makeConstList, installTearOff,
228 updateHolder, updateTypes,
229 setOrUpdateInterceptorsByTag, setOrUpdateLeafTags,
230 #embeddedGlobalsObject, holdersList, #currentIsolate) {
231
232 // Builds the holders. They only contain the data for new holders.
233 #holders;
234 // Updates the holders of the main-fragment. Uses the provided holdersList to
235 // access the main holders.
236 // The local holders are replaced by the combined holders. This is necessary
237 // for the inheritance setup below.
238 #updateHolders;
239 // Sets the prototypes of the new classes.
240 #prototypes;
241 // Sets aliases of methods (on the prototypes of classes).
242 #aliases;
243 // Installs the tear-offs of functions.
244 #tearOffs;
245 // Builds the inheritance structure.
246 #inheritance;
247
248 updateTypes(#types);
249
250 // Native-support uses setOrUpdateInterceptorsByTag and setOrUpdateLeafTags.
251 #nativeSupport;
252
253 // Instantiates all constants of this deferred fragment.
254 // Note that the constant-holder has been updated earlier and storing the
255 // constant values in the constant-holder makes them available globally.
256 #constants;
257 // Initializes the static non-final fields (with their constant values).
258 #staticNonFinalFields;
259 // Creates lazy getters for statics that must run initializers on first access.
260 #lazyStatics;
261 };
262 // TODO(floitsch): this last line should be outside the AST, since it
263 // requires to know the hash of the part of the code above this comment.
264 #deferredInitializers[#hash] = #deferredInitializers.current;
265 }''';
266
7 /** 267 /**
8 * This class builds a JavaScript tree for a given fragment. 268 * This class builds a JavaScript tree for a given fragment.
9 * 269 *
10 * A fragment is generally written into a separate file so that it can be 270 * A fragment is generally written into a separate file so that it can be
11 * loaded dynamically when a deferred library is loaded. 271 * loaded dynamically when a deferred library is loaded.
12 * 272 *
13 * This class is stateless and can be reused for different fragments. 273 * This class is stateless and can be reused for different fragments.
14 */ 274 */
15 class FragmentEmitter { 275 class FragmentEmitter {
16 final Compiler compiler; 276 final Compiler compiler;
(...skipping 15 matching lines...) Expand all
32 MainFragment fragment = program.fragments.first; 292 MainFragment fragment = program.fragments.first;
33 throw new UnimplementedError('emitMain'); 293 throw new UnimplementedError('emitMain');
34 } 294 }
35 295
36 js.Statement emitDeferredFragment(DeferredFragment fragment, 296 js.Statement emitDeferredFragment(DeferredFragment fragment,
37 js.Expression deferredTypes, 297 js.Expression deferredTypes,
38 List<Holder> holders) { 298 List<Holder> holders) {
39 throw new UnimplementedError('emitDeferred'); 299 throw new UnimplementedError('emitDeferred');
40 } 300 }
41 } 301 }
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