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

Side by Side Diff: sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart

Issue 237583014: JS templates (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: cleanup Created 6 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, 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; 5 part of dart2js.js_emitter;
6 6
7 /** 7 /**
8 * Generates the code for all used classes in the program. Static fields (even 8 * Generates the code for all used classes in the program. Static fields (even
9 * in classes) are ignored, since they can be treated as non-class elements. 9 * in classes) are ignored, since they can be treated as non-class elements.
10 * 10 *
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
141 const RANGE2_SIZE = RANGE2_LAST - RANGE2_FIRST + 1; 141 const RANGE2_SIZE = RANGE2_LAST - RANGE2_FIRST + 1;
142 const RANGE1_ADJUST = - (FIRST_FIELD_CODE - RANGE1_FIRST); 142 const RANGE1_ADJUST = - (FIRST_FIELD_CODE - RANGE1_FIRST);
143 const RANGE2_ADJUST = - (FIRST_FIELD_CODE + RANGE1_SIZE - RANGE2_FIRST); 143 const RANGE2_ADJUST = - (FIRST_FIELD_CODE + RANGE1_SIZE - RANGE2_FIRST);
144 const RANGE3_ADJUST = 144 const RANGE3_ADJUST =
145 - (FIRST_FIELD_CODE + RANGE1_SIZE + RANGE2_SIZE - RANGE3_FIRST); 145 - (FIRST_FIELD_CODE + RANGE1_SIZE + RANGE2_SIZE - RANGE3_FIRST);
146 146
147 String receiverParamName = compiler.enableMinification ? "r" : "receiver"; 147 String receiverParamName = compiler.enableMinification ? "r" : "receiver";
148 String valueParamName = compiler.enableMinification ? "v" : "value"; 148 String valueParamName = compiler.enableMinification ? "v" : "value";
149 String reflectableField = namer.reflectableField; 149 String reflectableField = namer.reflectableField;
150 150
151 // function generateAccessor(field, prototype, cls) { 151 return js.statement('''
152 jsAst.Fun fun = js.fun(['fieldDescriptor', 'accessors', 'cls'], [ 152 function generateAccessor(fieldDescriptor, accessors, cls) {
153 js('var fieldInformation = fieldDescriptor.split("-")'), 153 var fieldInformation = fieldDescriptor.split("-");
154 js('var field = fieldInformation[0]'), 154 var field = fieldInformation[0];
155 js('var len = field.length'), 155 var len = field.length;
156 js('var code = field.charCodeAt(len - 1)'), 156 var code = field.charCodeAt(len - 1);
157 js('var reflectable'), 157 var reflectable;
158 js.if_('fieldInformation.length > 1', js('reflectable = true'), 158 if (fieldInformation.length > 1) reflectable = true;
floitsch 2014/04/22 16:11:18 var reflectable = fieldInformation.length > 1;
sra1 2014/04/23 02:33:50 I agree, but the process for this change it to cha
159 js('reflectable = false')), 159 else reflectable = false;
160 js('code = ((code >= $RANGE1_FIRST) && (code <= $RANGE1_LAST))' 160 code = ((code >= $RANGE1_FIRST) && (code <= $RANGE1_LAST))
161 ' ? code - $RANGE1_ADJUST' 161 ? code - $RANGE1_ADJUST
162 ' : ((code >= $RANGE2_FIRST) && (code <= $RANGE2_LAST))' 162 : ((code >= $RANGE2_FIRST) && (code <= $RANGE2_LAST))
163 ' ? code - $RANGE2_ADJUST' 163 ? code - $RANGE2_ADJUST
164 ' : ((code >= $RANGE3_FIRST) && (code <= $RANGE3_LAST))' 164 : ((code >= $RANGE3_FIRST) && (code <= $RANGE3_LAST))
165 ' ? code - $RANGE3_ADJUST' 165 ? code - $RANGE3_ADJUST
166 ' : $NO_FIELD_CODE'), 166 : $NO_FIELD_CODE;
167 167
168 // if (needsAccessor) { 168 if (code) { // needsAccessor
169 js.if_('code', [ 169 var getterCode = code & 3;
170 js('var getterCode = code & 3'), 170 var setterCode = code >> 2;
171 js('var setterCode = code >> 2'), 171 var accessorName = field = field.substring(0, len - 1);
172 js('var accessorName = field = field.substring(0, len - 1)'),
173 172
174 js('var divider = field.indexOf(":")'), 173 var divider = field.indexOf(":");
175 js.if_('divider > 0', [ // Colon never in first position. 174 if (divider > 0) { // Colon never in first position.
176 js('accessorName = field.substring(0, divider)'), 175 accessorName = field.substring(0, divider);
177 js('field = field.substring(divider + 1)') 176 field = field.substring(divider + 1);
178 ]), 177 }
179 178
180 // if (needsGetter) { 179 if (getterCode) { // needsGetter
181 js.if_('getterCode', [ 180 var args = (getterCode & 2) ? "$receiverParamName" : "";
182 js('var args = (getterCode & 2) ? "$receiverParamName" : ""'), 181 var receiver = (getterCode & 1) ? "this" : "$receiverParamName";
183 js('var receiver = (getterCode & 1) ? "this" : "$receiverParamName"'), 182 var body = "return " + receiver + "." + field;
184 js('var body = "return " + receiver + "." + field'), 183 var property =
185 js('var property =' 184 cls + ".prototype.${namer.getterPrefix}" + accessorName + "=";
186 ' cls + ".prototype.${namer.getterPrefix}" + accessorName + "="'), 185 var fn = "function(" + args + "){" + body + "}";
187 js('var fn = "function(" + args + "){" + body + "}"'), 186 if (reflectable)
188 js.if_( 187 accessors.push(property + "\$reflectable(" + fn + ");\\n");
189 'reflectable', 188 else
190 js('accessors.push(property + "\$reflectable(" + fn + ");\\n")'), 189 accessors.push(property + fn + ";\\n");
191 js('accessors.push(property + fn + ";\\n")')), 190 }
192 ]),
193 191
194 // if (needsSetter) { 192 if (setterCode) { // needsSetter
195 js.if_('setterCode', [ 193 var args = (setterCode & 2)
196 js('var args = (setterCode & 2)' 194 ? "$receiverParamName,${_}$valueParamName"
197 ' ? "$receiverParamName,${_}$valueParamName"' 195 : "$valueParamName";
198 ' : "$valueParamName"'), 196 var receiver = (setterCode & 1) ? "this" : "$receiverParamName";
199 js('var receiver = (setterCode & 1) ? "this" : "$receiverParamName"'), 197 var body = receiver + "." + field + "$_=$_$valueParamName";
200 js('var body = receiver + "." + field + "$_=$_$valueParamName"'), 198 var property =
201 js('var property =' 199 cls + ".prototype.${namer.setterPrefix}" + accessorName + "=";
202 ' cls + ".prototype.${namer.setterPrefix}" + accessorName + "="'), 200 var fn = "function(" + args + "){" + body + "}";
203 js('var fn = "function(" + args + "){" + body + "}"'), 201 if (reflectable)
204 js.if_( 202 accessors.push(property + "\$reflectable(" + fn + ");\\n");
205 'reflectable', 203 else
206 js('accessors.push(property + "\$reflectable(" + fn + ");\\n")'), 204 accessors.push(property + fn + ";\\n");
207 js('accessors.push(property + fn + ";\\n")')), 205 }
208 ]), 206 }
209 207
210 ]), 208 return field;
211 209 }''');
212 // return field;
213 js.return_('field')
214 ]);
215
216 return new jsAst.FunctionDeclaration(
217 new jsAst.VariableDeclaration('generateAccessor'),
218 fun);
219 } 210 }
220 211
221 List get defineClassFunction { 212 List get defineClassFunction {
222 // First the class name, then the field names in an array and the members 213 // First the class name, then the field names in an array and the members
223 // (inside an Object literal). 214 // (inside an Object literal).
224 // The caller can also pass in the constructor as a function if needed. 215 // The caller can also pass in the constructor as a function if needed.
225 // 216 //
226 // Example: 217 // Example:
227 // defineClass("A", ["x", "y"], { 218 // defineClass("A", ["x", "y"], {
228 // foo$1: function(y) { 219 // foo$1: function(y) {
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
297 // - it contains all (local) members. 288 // - it contains all (local) members.
298 // - its internal prototype (__proto__) points to the superclass' 289 // - its internal prototype (__proto__) points to the superclass'
299 // prototype field. 290 // prototype field.
300 // - the prototype's constructor field points to the JavaScript 291 // - the prototype's constructor field points to the JavaScript
301 // constructor. 292 // constructor.
302 // For engines where we have access to the '__proto__' we can manipulate 293 // For engines where we have access to the '__proto__' we can manipulate
303 // the object literal directly. For other engines we have to create a new 294 // the object literal directly. For other engines we have to create a new
304 // object and copy over the members. 295 // object and copy over the members.
305 296
306 String reflectableField = namer.reflectableField; 297 String reflectableField = namer.reflectableField;
307 List<jsAst.Node> statements = [
308 js('var pendingClasses = {}'),
309 js.if_('!init.allClasses', js('init.allClasses = {}')),
310 js('var allClasses = init.allClasses'),
311 298
312 optional( 299 return js('''
313 DEBUG_FAST_OBJECTS, 300 function(collectedClasses, isolateProperties, existingIsolateProperties) {
314 js('print("Number of classes: "' 301 var pendingClasses = {};
315 r' + Object.getOwnPropertyNames($$).length)')), 302 if (!init.allClasses) init.allClasses = {};
303 var allClasses = init.allClasses;
316 304
317 js('var hasOwnProperty = Object.prototype.hasOwnProperty'), 305 if (#) // DEBUG_FAST_OBJECTS
306 print("Number of classes: " +
307 Object.getOwnPropertyNames(\$\$).length);
318 308
319 js.if_('typeof dart_precompiled == "function"', 309 var hasOwnProperty = Object.prototype.hasOwnProperty;
320 [js('var constructors = dart_precompiled(collectedClasses)')],
321 310
322 [js('var combinedConstructorFunction = "function \$reflectable(fn){' 311 if (typeof dart_precompiled == "function") {
floitsch 2014/04/22 16:11:18 Not this CL, but I think this is a compile-time co
sra1 2014/04/23 02:33:50 I'm not sure because the csp stuff is appended. It
323 'fn.$reflectableField=1;return fn};\\n"+ "var \$desc;\\n"'), 312 var constructors = dart_precompiled(collectedClasses);
324 js('var constructorsList = []')]), 313 } else {
325 js.forIn('cls', 'collectedClasses', [ 314 var combinedConstructorFunction =
326 js.if_('hasOwnProperty.call(collectedClasses, cls)', [ 315 "function \$reflectable(fn){fn.$reflectableField=1;return fn};\\n"+
327 js('var desc = collectedClasses[cls]'), 316 "var \$desc;\\n";
328 js.if_('desc instanceof Array', js('desc = desc[1]')), 317 var constructorsList = [];
318 }
329 319
330 /* The 'fields' are either a constructor function or a 320 for (var cls in collectedClasses) {
331 * string encoding fields, constructor and superclass. Get 321 if (hasOwnProperty.call(collectedClasses, cls)) {
332 * the superclass and the fields in the format 322 var desc = collectedClasses[cls];
333 * '[name/]Super;field1,field2' 323 if (desc instanceof Array) desc = desc[1];
334 * from the CLASS_DESCRIPTOR_PROPERTY property on the descriptor.
335 * The 'name/' is optional and contains the name that should be used
336 * when printing the runtime type string. It is used, for example, to
337 * print the runtime type JSInt as 'int'.
338 */
339 js('var classData = desc["${namer.classDescriptorProperty}"], '
340 'supr, name = cls, fields = classData'),
341 optional(
342 backend.hasRetainedMetadata,
343 js.if_('typeof classData == "object" && '
344 'classData instanceof Array',
345 [js('classData = fields = classData[0]')])),
346 324
347 js.if_('typeof classData == "string"', [ 325 /* The 'fields' are either a constructor function or a
348 js('var split = classData.split("/")'), 326 * string encoding fields, constructor and superclass. Get
349 js.if_('split.length == 2', [ 327 * the superclass and the fields in the format
350 js('name = split[0]'), 328 * '[name/]Super;field1,field2'
351 js('fields = split[1]') 329 * from the CLASS_DESCRIPTOR_PROPERTY property on the descriptor.
352 ]) 330 * The 'name/' is optional and contains the name that should be used
353 ]), 331 * when printing the runtime type string. It is used, for example,
332 * to print the runtime type JSInt as 'int'.
333 */
334 var classData = desc["${namer.classDescriptorProperty}"],
335 supr, name = cls, fields = classData;
336 if (#) // backend.hasRetainedMetadata
337 if (typeof classData == "object" &&
338 classData instanceof Array) {
339 classData = fields = classData[0];
340 }
341 if (typeof classData == "string") {
342 var split = classData.split("/");
343 if (split.length == 2) {
344 name = split[0];
345 fields = split[1];
346 }
347 }
354 348
355 js('var s = fields.split(";")'), 349 var s = fields.split(";");
356 js('fields = s[1] == "" ? [] : s[1].split(",")'), 350 fields = s[1] == "" ? [] : s[1].split(",");
357 js('supr = s[0]'), 351 supr = s[0];
358 js('split = supr.split(":")'), 352 split = supr.split(":");
359 js.if_('split.length == 2', [ 353 if (split.length == 2) {
360 js('supr = split[0]'), 354 supr = split[0];
361 js('var functionSignature = split[1]'), 355 var functionSignature = split[1];
362 js.if_('functionSignature', 356 if (functionSignature)
363 js('desc.\$signature = #', 357 desc.\$signature = (function(s) {
364 js.fun('s', 358 return function(){ return init.metadata[s]; };
365 js.return_(js.fun([], js.return_('init.metadata[s]'))))( 359 })(functionSignature);
366 js('functionSignature')))) 360 }
367 ]),
368 361
369 optional(needsMixinSupport, js.if_('supr && supr.indexOf("+") > 0', [ 362 if (#) // needsMixinSupport
370 js('s = supr.split("+")'), 363 if (supr && supr.indexOf("+") > 0) {
371 js('supr = s[0]'), 364 s = supr.split("+");
372 js('var mixin = collectedClasses[s[1]]'), 365 supr = s[0];
373 js.if_('mixin instanceof Array', js('mixin = mixin[1]')), 366 var mixin = collectedClasses[s[1]];
374 js.forIn('d', 'mixin', [ 367 if (mixin instanceof Array) mixin = mixin[1];
375 js.if_('hasOwnProperty.call(mixin, d)' 368 for(var d in mixin) {
376 '&& !hasOwnProperty.call(desc, d)', 369 if (hasOwnProperty.call(mixin, d) &&
377 js('desc[d] = mixin[d]')) 370 !hasOwnProperty.call(desc, d))
378 ]), 371 desc[d] = mixin[d];
379 ])), 372 }
373 }
380 374
381 js.if_('typeof dart_precompiled != "function"', 375 if (typeof dart_precompiled != "function") {
382 [js('combinedConstructorFunction +=' 376 combinedConstructorFunction += defineClass(name, cls, fields);
383 ' defineClass(name, cls, fields)'), 377 constructorsList.push(cls);
384 js('constructorsList.push(cls)')]), 378 }
385 js.if_('supr', js('pendingClasses[cls] = supr')) 379 if (supr) pendingClasses[cls] = supr;
386 ]) 380 }
387 ]), 381 }
388 js.statement('''
389 if (typeof dart_precompiled != "function") {
390 combinedConstructorFunction +=
391 "return [\\n " + constructorsList.join(",\\n ") + "\\n]";
392 var constructors =
393 new Function("\$collectedClasses", combinedConstructorFunction)
394 (collectedClasses);
395 combinedConstructorFunction = null;
396 }'''),
397 js.for_('var i = 0', 'i < constructors.length', 'i++', [
398 js('var constructor = constructors[i]'),
399 js('var cls = constructor.name'),
400 js('var desc = collectedClasses[cls]'),
401 js('var globalObject = isolateProperties'),
402 js.if_('desc instanceof Array', [
403 js('globalObject = desc[0] || isolateProperties'),
404 js('desc = desc[1]')
405 ]),
406 optional(backend.isTreeShakingDisabled,
407 js('constructor["${namer.metadataField}"] = desc')),
408 js('allClasses[cls] = constructor'),
409 js('globalObject[cls] = constructor'),
410 ]),
411 js('constructors = null'),
412 382
413 js('var finishedClasses = {}'), 383 if (typeof dart_precompiled != "function") {
414 js('init.interceptorsByTag = Object.create(null)'), 384 combinedConstructorFunction +=
415 js('init.leafTags = {}'), 385 "return [\\n " + constructorsList.join(",\\n ") + "\\n]";
386 var constructors =
387 new Function("\$collectedClasses", combinedConstructorFunction)
388 (collectedClasses);
389 combinedConstructorFunction = null;
390 }
416 391
417 buildFinishClass(), 392 for (var i = 0; i < constructors.length; i++) {
418 ]; 393 var constructor = constructors[i];
394 var cls = constructor.name;
395 var desc = collectedClasses[cls];
396 var globalObject = isolateProperties;
397 if (desc instanceof Array) {
398 globalObject = desc[0] || isolateProperties;
399 desc = desc[1];
400 }
401 if (#) //backend.isTreeShakingDisabled,
402 constructor["${namer.metadataField}"] = desc;
403 allClasses[cls] = constructor;
404 globalObject[cls] = constructor;
405 }
419 406
420 nsmEmitter.addTrivialNsmHandlers(statements); 407 constructors = null;
421 408
422 statements.add( 409 var finishedClasses = {};
423 js.statement('for (var cls in pendingClasses) finishClass(cls);') 410 init.interceptorsByTag = Object.create(null);
424 ); 411 init.leafTags = {};
425 412
426 // function(collectedClasses, 413 #; // buildFinishClass(),
427 // isolateProperties, 414
428 // existingIsolateProperties) 415 #; // buildTrivialNsmHandlers()
429 return js.fun(['collectedClasses', 'isolateProperties', 416
430 'existingIsolateProperties'], statements); 417 for (var cls in pendingClasses) finishClass(cls);
418 }''', [
419 DEBUG_FAST_OBJECTS,
420 backend.hasRetainedMetadata,
421 needsMixinSupport,
422 backend.isTreeShakingDisabled,
423 buildFinishClass(),
424 nsmEmitter.buildTrivialNsmHandlers()]);
425
431 } 426 }
432 427
433 jsAst.Node optional(bool condition, jsAst.Node node) { 428 jsAst.Node optional(bool condition, jsAst.Node node) {
434 return condition ? node : new jsAst.EmptyStatement(); 429 return condition ? node : new jsAst.EmptyStatement();
435 } 430 }
436 431
437 jsAst.FunctionDeclaration buildFinishClass() { 432 jsAst.FunctionDeclaration buildFinishClass() {
438 String specProperty = '"${namer.nativeSpecProperty}"'; // "%" 433 String specProperty = '"${namer.nativeSpecProperty}"'; // "%"
439 434
440 // function finishClass(cls) { 435 return js.statement('''
441 jsAst.Fun fun = js.fun(['cls'], [ 436 function finishClass(cls) {
442 437
443 // TODO(8540): Remove this work around. 438 // TODO(8540): Remove this work around.
444 /* Opera does not support 'getOwnPropertyNames'. Therefore we use 439 // Opera does not support 'getOwnPropertyNames'. Therefore we use
445 hasOwnProperty instead. */ 440 // hasOwnProperty instead.
446 js('var hasOwnProperty = Object.prototype.hasOwnProperty'), 441 var hasOwnProperty = Object.prototype.hasOwnProperty;
447 442
448 // if (hasOwnProperty.call(finishedClasses, cls)) return; 443 if (hasOwnProperty.call(finishedClasses, cls)) return;
449 js.if_('hasOwnProperty.call(finishedClasses, cls)',
450 js.return_()),
451 444
452 js('finishedClasses[cls] = true'), 445 finishedClasses[cls] = true;
453 446
454 js('var superclass = pendingClasses[cls]'), 447 var superclass = pendingClasses[cls];
455 448
456 // The superclass is only false (empty string) for Dart's Object class. 449 // The superclass is only false (empty string) for the Dart Object
457 // The minifier together with noSuchMethod can put methods on the 450 // class. The minifier together with noSuchMethod can put methods on
458 // Object.prototype object, and they show through here, so we check that 451 // the Object.prototype object, and they show through here, so we check
459 // we have a string. 452 // that we have a string.
460 js.if_('!superclass || typeof superclass != "string"', js.return_()), 453 if (!superclass || typeof superclass != "string") return;
461 js('finishClass(superclass)'), 454 finishClass(superclass);
462 js('var constructor = allClasses[cls]'), 455 var constructor = allClasses[cls];
463 js('var superConstructor = allClasses[superclass]'), 456 var superConstructor = allClasses[superclass];
464 457
465 js.if_(js('!superConstructor'), 458 if (!superConstructor)
466 js('superConstructor =' 459 superConstructor = existingIsolateProperties[superclass];
467 'existingIsolateProperties[superclass]')),
468 460
469 js('var prototype = inheritFrom(constructor, superConstructor)'), 461 var prototype = inheritFrom(constructor, superConstructor);
470 462
471 optional(!nativeClasses.isEmpty, 463 if (#) { // !nativeClasses.isEmpty,
472 // The property looks like this: 464 // The property looks like this:
473 // 465 //
474 // HtmlElement: { 466 // HtmlElement: {
475 // "%": "HTMLDivElement|HTMLAnchorElement;HTMLElement;FancyButton" 467 // "%": "HTMLDivElement|HTMLAnchorElement;HTMLElement;FancyButton"
476 // 468 //
477 // The first two semicolon-separated parts contain dispatch tags, the 469 // The first two semicolon-separated parts contain dispatch tags, the
478 // third contains the JavaScript names for classes. 470 // third contains the JavaScript names for classes.
479 // 471 //
480 // The tags indicate that JavaScript objects with the dispatch tags 472 // The tags indicate that JavaScript objects with the dispatch tags
481 // (usually constructor names) HTMLDivElement, HTMLAnchorElement and 473 // (usually constructor names) HTMLDivElement, HTMLAnchorElement and
482 // HTMLElement all map to the Dart native class named HtmlElement. 474 // HTMLElement all map to the Dart native class named HtmlElement.
483 // The first set is for effective leaf nodes in the hierarchy, the 475 // The first set is for effective leaf nodes in the hierarchy, the
484 // second set is non-leaf nodes. 476 // second set is non-leaf nodes.
485 // 477 //
486 // The third part contains the JavaScript names of Dart classes that 478 // The third part contains the JavaScript names of Dart classes that
487 // extend the native class. Here, FancyButton extends HtmlElement, so 479 // extend the native class. Here, FancyButton extends HtmlElement, so
488 // the runtime needs to know that window.HTMLElement.prototype is the 480 // the runtime needs to know that window.HTMLElement.prototype is the
489 // prototype that needs to be extended in creating the custom element. 481 // prototype that needs to be extended in creating the custom element.
490 // 482 //
491 // The information is used to build tables referenced by 483 // The information is used to build tables referenced by
492 // getNativeInterceptor and custom element support. 484 // getNativeInterceptor and custom element support.
493 js.if_('hasOwnProperty.call(prototype, $specProperty)', [ 485 if (hasOwnProperty.call(prototype, $specProperty)) {
494 js('var nativeSpec = prototype[$specProperty].split(";")'), 486 var nativeSpec = prototype[$specProperty].split(";");
495 js.if_('nativeSpec[0]', [ 487 if (nativeSpec[0]) {
496 js('var tags = nativeSpec[0].split("|")'), 488 var tags = nativeSpec[0].split("|");
497 js.for_('var i = 0', 'i < tags.length', 'i++', [ 489 for (var i = 0; i < tags.length; i++) {
498 js('init.interceptorsByTag[tags[i]] = constructor'), 490 init.interceptorsByTag[tags[i]] = constructor;
499 js('init.leafTags[tags[i]] = true')])]), 491 init.leafTags[tags[i]] = true;
500 js.if_('nativeSpec[1]', [ 492 }
501 js('tags = nativeSpec[1].split("|")'), 493 }
502 optional(true, // User subclassing of native classes? 494 if (nativeSpec[1]) {
503 js.if_('nativeSpec[2]', [ 495 tags = nativeSpec[1].split("|");
504 js('var subclasses = nativeSpec[2].split("|")'), 496 if (#) { // User subclassing of native classes?
505 js.for_('var i = 0', 'i < subclasses.length', 'i++', [ 497 if (nativeSpec[2]) {
506 js('var subclass = allClasses[subclasses[i]]'), 498 var subclasses = nativeSpec[2].split("|");
507 js('subclass.\$nativeSuperclassTag = ' 499 for (var i = 0; i < subclasses.length; i++) {
508 'tags[0]')])])), 500 var subclass = allClasses[subclasses[i]];
509 js.for_('i = 0', 'i < tags.length', 'i++', [ 501 subclass.\$nativeSuperclassTag = tags[0];
510 js('init.interceptorsByTag[tags[i]] = constructor'), 502 }
511 js('init.leafTags[tags[i]] = false')])])])) 503 }
512 ]); 504 for (i = 0; i < tags.length; i++) {
513 505 init.interceptorsByTag[tags[i]] = constructor;
514 return new jsAst.FunctionDeclaration( 506 init.leafTags[tags[i]] = false;
515 new jsAst.VariableDeclaration('finishClass'), 507 }
516 fun); 508 }
509 }
510 }
511 }
512 }''', [!nativeClasses.isEmpty, true]);
517 } 513 }
518 514
519 jsAst.Fun get finishIsolateConstructorFunction { 515 jsAst.Fun get finishIsolateConstructorFunction {
520 // We replace the old Isolate function with a new one that initializes 516 // We replace the old Isolate function with a new one that initializes
521 // all its fields with the initial (and often final) value of all globals. 517 // all its fields with the initial (and often final) value of all globals.
522 // 518 //
523 // We also copy over old values like the prototype, and the 519 // We also copy over old values like the prototype, and the
524 // isolateProperties themselves. 520 // isolateProperties themselves.
525 return js(''' 521 return js('''
526 function (oldIsolate) { 522 function (oldIsolate) {
527 var isolateProperties = oldIsolate.${namer.isolatePropertiesName}; 523 var isolateProperties = oldIsolate.${namer.isolatePropertiesName};
528 function Isolate() { 524 function Isolate() {
529 var hasOwnProperty = Object.prototype.hasOwnProperty; 525 var hasOwnProperty = Object.prototype.hasOwnProperty;
530 for (var staticName in isolateProperties) 526 for (var staticName in isolateProperties)
531 if (hasOwnProperty.call(isolateProperties, staticName)) 527 if (hasOwnProperty.call(isolateProperties, staticName))
532 this[staticName] = isolateProperties[staticName]; 528 this[staticName] = isolateProperties[staticName];
533 // Use the newly created object as prototype. In Chrome, 529 // Use the newly created object as prototype. In Chrome,
534 // this creates a hidden class for the object and makes 530 // this creates a hidden class for the object and makes
535 // sure it is fast to access. 531 // sure it is fast to access.
536 function ForceEfficientMap() {} 532 function ForceEfficientMap() {}
537 ForceEfficientMap.prototype = this; 533 ForceEfficientMap.prototype = this;
538 new ForceEfficientMap(); 534 new ForceEfficientMap();
539 } 535 }
540 Isolate.prototype = oldIsolate.prototype; 536 Isolate.prototype = oldIsolate.prototype;
541 Isolate.prototype.constructor = Isolate; 537 Isolate.prototype.constructor = Isolate;
542 Isolate.${namer.isolatePropertiesName} = isolateProperties; 538 Isolate.${namer.isolatePropertiesName} = isolateProperties;
543 # 539 if (#)
544 # 540 Isolate.$finishClassesProperty = oldIsolate.$finishClassesProperty;
541 if (#)
542 Isolate.makeConstantList = oldIsolate.makeConstantList;
545 return Isolate; 543 return Isolate;
546 }''', 544 }''',
547 [ optional(needsDefineClass, 545 [ needsDefineClass, hasMakeConstantList ]);
548 js('Isolate.$finishClassesProperty ='
549 ' oldIsolate.$finishClassesProperty')),
550 optional(hasMakeConstantList,
551 js('Isolate.makeConstantList = oldIsolate.makeConstantList'))
552 ]);
553 } 546 }
554 547
555 jsAst.Fun get lazyInitializerFunction { 548 jsAst.Fun get lazyInitializerFunction {
556 // function(prototype, staticName, fieldName, getterName, lazyValue) {
557 var parameters = <String>['prototype', 'staticName', 'fieldName',
558 'getterName', 'lazyValue'];
559 return js.fun(parameters, addLazyInitializerLogic());
560 }
561
562 List addLazyInitializerLogic() {
563 String isolate = namer.currentIsolate; 549 String isolate = namer.currentIsolate;
564 String cyclicThrow = namer.isolateAccess(backend.getCyclicThrowHelper()); 550 String cyclicThrow = namer.isolateAccess(backend.getCyclicThrowHelper());
565 var lazies = [];
566 if (backend.rememberLazies) {
567 lazies = [
568 js.if_('!init.lazies', js('init.lazies = {}')),
569 js('init.lazies[fieldName] = getterName')];
570 }
571 551
572 return lazies..addAll([ 552 return js('''
573 js('var sentinelUndefined = {}'), 553 function (prototype, staticName, fieldName, getterName, lazyValue) {
574 js('var sentinelInProgress = {}'), 554 if (#) {
575 js('prototype[fieldName] = sentinelUndefined'), 555 if (!init.lazies) init.lazies = {};
556 init.lazies[fieldName] = getterName;
557 }
576 558
577 // prototype[getterName] = function() 559 var sentinelUndefined = {};
578 js('prototype[getterName] = #', js.fun([], [ 560 var sentinelInProgress = {};
579 js('var result = $isolate[fieldName]'), 561 prototype[fieldName] = sentinelUndefined;
580 562
581 // try 563 prototype[getterName] = function () {
582 js.try_([ 564 var result = $isolate[fieldName];
583 js.if_('result === sentinelUndefined', [ 565 try {
584 js('$isolate[fieldName] = sentinelInProgress'), 566 if (result === sentinelUndefined) {
567 $isolate[fieldName] = sentinelInProgress;
585 568
586 // try 569 try {
587 js.try_([ 570 result = $isolate[fieldName] = lazyValue();
588 js('result = $isolate[fieldName] = lazyValue()'), 571 } finally {
572 // Use try-finally, not try-catch/throw as it destroys the
573 // stack trace.
574 if (result === sentinelUndefined)
575 if ($isolate[fieldName] === sentinelInProgress)
576 $isolate[fieldName] = null;
577 }
578 } else {
579 if (result === sentinelInProgress)
580 $cyclicThrow(staticName);
581 }
589 582
590 ], finallyPart: [ 583 return result;
591 // Use try-finally, not try-catch/throw as it destroys the 584 } finally {
592 // stack trace. 585 $isolate[getterName] = function() { return this[fieldName]; };
593 586 }
594 // if (result === sentinelUndefined) 587 }
595 js.if_('result === sentinelUndefined', [ 588 }
596 // if ($isolate[fieldName] === sentinelInProgress) 589 ''', [backend.rememberLazies]);
597 js.if_('$isolate[fieldName] === sentinelInProgress', [
598 js('$isolate[fieldName] = null'),
599 ])
600 ])
601 ])
602 ], /* else */ [
603 js.if_('result === sentinelInProgress',
604 js('$cyclicThrow(staticName)')
605 )
606 ]),
607
608 // return result;
609 js.return_('result')
610
611 ], finallyPart: [
612 js('$isolate[getterName] = #',
613 js.fun([], [js.return_('this[fieldName]')]))
614 ])
615 ]))
616 ]);
617 } 590 }
618 591
619 List buildDefineClassAndFinishClassFunctionsIfNecessary() { 592 List buildDefineClassAndFinishClassFunctionsIfNecessary() {
620 if (!needsDefineClass) return []; 593 if (!needsDefineClass) return [];
621 return defineClassFunction 594 return defineClassFunction
622 ..addAll(buildInheritFrom()) 595 ..addAll(buildInheritFrom())
623 ..addAll([ 596 ..addAll([
624 js('$finishClassesName = #', finishClassesFunction) 597 js('$finishClassesName = #', finishClassesFunction)
625 ]); 598 ]);
626 } 599 }
627 600
628 List buildLazyInitializerFunctionIfNecessary() { 601 List buildLazyInitializerFunctionIfNecessary() {
629 if (!needsLazyInitializer) return []; 602 if (!needsLazyInitializer) return [];
630 603
631 return [js('$lazyInitializerName = #', lazyInitializerFunction)]; 604 return [js('# = #', [js(lazyInitializerName), lazyInitializerFunction])];
floitsch 2014/04/22 16:11:18 lazyInitializerName is a string. Do you have to ru
sra1 2014/04/23 02:33:50 It is a String, but it is not an identifier: "Isol
632 } 605 }
633 606
634 List buildFinishIsolateConstructor() { 607 List buildFinishIsolateConstructor() {
635 return [ 608 return [
636 js('$finishIsolateConstructorName = #', finishIsolateConstructorFunction) 609 js('$finishIsolateConstructorName = #', finishIsolateConstructorFunction)
637 ]; 610 ];
638 } 611 }
639 612
640 void emitFinishIsolateConstructorInvocation(CodeBuffer buffer) { 613 void emitFinishIsolateConstructorInvocation(CodeBuffer buffer) {
641 String isolate = namer.isolateName; 614 String isolate = namer.isolateName;
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
753 726
754 String namedParametersAsReflectionNames(Selector selector) { 727 String namedParametersAsReflectionNames(Selector selector) {
755 if (selector.getOrderedNamedArguments().isEmpty) return ''; 728 if (selector.getOrderedNamedArguments().isEmpty) return '';
756 String names = selector.getOrderedNamedArguments().join(':'); 729 String names = selector.getOrderedNamedArguments().join(':');
757 return ':$names'; 730 return ':$names';
758 } 731 }
759 732
760 jsAst.FunctionDeclaration buildPrecompiledFunction() { 733 jsAst.FunctionDeclaration buildPrecompiledFunction() {
761 // TODO(ahe): Compute a hash code. 734 // TODO(ahe): Compute a hash code.
762 String name = 'dart_precompiled'; 735 String name = 'dart_precompiled';
763 736 return js.statement('''
floitsch 2014/04/22 16:11:18 This should not be cached. Write TODO, that this s
sra1 2014/04/23 02:33:50 The name is dart_precompiled, from the previous li
764 precompiledFunction.add( 737 function $name(\$collectedClasses) {
765 js.return_( 738 var \$desc;
766 new jsAst.ArrayInitializer.from(precompiledConstructorNames))); 739 #;
767 precompiledFunction.insert(0, js(r'var $desc')); 740 return #;
768 return new jsAst.FunctionDeclaration( 741 }''', [
769 new jsAst.VariableDeclaration(name), 742 precompiledFunction,
770 js.fun([r'$collectedClasses'], precompiledFunction)); 743 new jsAst.ArrayInitializer.from(precompiledConstructorNames)]);
771 } 744 }
772 745
773 void generateClass(ClassElement classElement, ClassBuilder properties) { 746 void generateClass(ClassElement classElement, ClassBuilder properties) {
774 compiler.withCurrentElement(classElement, () { 747 compiler.withCurrentElement(classElement, () {
775 classEmitter.generateClass( 748 classEmitter.generateClass(
776 classElement, properties, additionalProperties[classElement]); 749 classElement, properties, additionalProperties[classElement]);
777 }); 750 });
778 } 751 }
779 752
780 /** 753 /**
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
851 Iterable<VariableElement> staticNonFinalFields = 824 Iterable<VariableElement> staticNonFinalFields =
852 handler.getStaticNonFinalFieldsForEmission(); 825 handler.getStaticNonFinalFieldsForEmission();
853 for (Element element in Elements.sortedByPosition(staticNonFinalFields)) { 826 for (Element element in Elements.sortedByPosition(staticNonFinalFields)) {
854 // [:interceptedNames:] is handled in [emitInterceptedNames]. 827 // [:interceptedNames:] is handled in [emitInterceptedNames].
855 if (element == backend.interceptedNames) continue; 828 if (element == backend.interceptedNames) continue;
856 // `mapTypeToInterceptor` is handled in [emitMapTypeToInterceptor]. 829 // `mapTypeToInterceptor` is handled in [emitMapTypeToInterceptor].
857 if (element == backend.mapTypeToInterceptor) continue; 830 if (element == backend.mapTypeToInterceptor) continue;
858 compiler.withCurrentElement(element, () { 831 compiler.withCurrentElement(element, () {
859 Constant initialValue = handler.getInitialValueFor(element); 832 Constant initialValue = handler.getInitialValueFor(element);
860 jsAst.Expression init = 833 jsAst.Expression init =
861 js('$isolateProperties.${namer.getNameOfGlobalField(element)} = #', 834 js('$isolateProperties.# = #',
862 constantEmitter.referenceInInitializationContext(initialValue)); 835 [namer.getNameOfGlobalField(element),
836 constantEmitter.referenceInInitializationContext(initialValue)]);
863 buffer.write(jsAst.prettyPrint(init, compiler)); 837 buffer.write(jsAst.prettyPrint(init, compiler));
864 buffer.write('$N'); 838 buffer.write('$N');
865 }); 839 });
866 } 840 }
867 } 841 }
868 842
869 void emitLazilyInitializedStaticFields(CodeBuffer buffer) { 843 void emitLazilyInitializedStaticFields(CodeBuffer buffer) {
870 JavaScriptConstantCompiler handler = backend.constants; 844 JavaScriptConstantCompiler handler = backend.constants;
871 List<VariableElement> lazyFields = 845 List<VariableElement> lazyFields =
872 handler.getLazilyInitializedFieldsForEmission(); 846 handler.getLazilyInitializedFieldsForEmission();
873 if (!lazyFields.isEmpty) { 847 if (!lazyFields.isEmpty) {
874 needsLazyInitializer = true; 848 needsLazyInitializer = true;
875 for (VariableElement element in Elements.sortedByPosition(lazyFields)) { 849 for (VariableElement element in Elements.sortedByPosition(lazyFields)) {
876 jsAst.Expression code = backend.generatedCode[element]; 850 jsAst.Expression code = backend.generatedCode[element];
877 // The code is null if we ended up not needing the lazily 851 // The code is null if we ended up not needing the lazily
878 // initialized field after all because of constant folding 852 // initialized field after all because of constant folding
879 // before code generation. 853 // before code generation.
880 if (code == null) continue; 854 if (code == null) continue;
881 // The code only computes the initial value. We build the lazy-check 855 // The code only computes the initial value. We build the lazy-check
882 // here: 856 // here:
883 // lazyInitializer(prototype, 'name', fieldName, getterName, initial); 857 // lazyInitializer(prototype, 'name', fieldName, getterName, initial);
884 // The name is used for error reporting. The 'initial' must be a 858 // The name is used for error reporting. The 'initial' must be a
885 // closure that constructs the initial value. 859 // closure that constructs the initial value.
886 List<jsAst.Expression> arguments = <jsAst.Expression>[];
887 arguments.add(js(isolateProperties));
888 arguments.add(js.string(element.name));
889 arguments.add(js.string(namer.getNameX(element)));
890 arguments.add(js.string(namer.getLazyInitializerName(element)));
891 arguments.add(code);
892 jsAst.Expression getter = buildLazyInitializedGetter(element); 860 jsAst.Expression getter = buildLazyInitializedGetter(element);
893 if (getter != null) { 861 jsAst.Expression init = js('#(#,#,#,#,#,#)',
894 arguments.add(getter); 862 [js(lazyInitializerName),
floitsch 2014/04/22 16:11:18 lazyInitializerName is a String. Why do we need to
sra1 2014/04/23 02:33:50 It is "Isolate.$lazy" Only strings in the form of
895 } 863 js(isolateProperties),
896 jsAst.Expression init = js(lazyInitializerName)(arguments); 864 js.string(element.name),
865 js.string(namer.getNameX(element)),
866 js.string(namer.getLazyInitializerName(element)),
867 code,
868 getter == null ? [] : [getter]]);
897 buffer.write(jsAst.prettyPrint(init, compiler)); 869 buffer.write(jsAst.prettyPrint(init, compiler));
898 buffer.write("$N"); 870 buffer.write("$N");
899 } 871 }
900 } 872 }
901 } 873 }
902 874
903 jsAst.Expression buildLazyInitializedGetter(VariableElement element) { 875 jsAst.Expression buildLazyInitializedGetter(VariableElement element) {
904 // Nothing to do, the 'lazy' function will create the getter. 876 // Nothing to do, the 'lazy' function will create the getter.
905 return null; 877 return null;
906 } 878 }
(...skipping 14 matching lines...) Expand all
921 && constantUnit == null) { 893 && constantUnit == null) {
922 // The back-end introduces some constants, like "InterceptorConstant" or 894 // The back-end introduces some constants, like "InterceptorConstant" or
923 // some list constants. They are emitted in the main output-unit, and 895 // some list constants. They are emitted in the main output-unit, and
924 // ignored otherwise. 896 // ignored otherwise.
925 // TODO(sigurdm): We should track those constants. 897 // TODO(sigurdm): We should track those constants.
926 continue; 898 continue;
927 } 899 }
928 900
929 String name = namer.constantName(constant); 901 String name = namer.constantName(constant);
930 if (constant.isList) emitMakeConstantListIfNotEmitted(buffer); 902 if (constant.isList) emitMakeConstantListIfNotEmitted(buffer);
931 jsAst.Expression init = js( 903 jsAst.Expression init = js('#.# = #',
932 '${namer.globalObjectForConstant(constant)}.$name = #', 904 [namer.globalObjectForConstant(constant), name,
933 constantInitializerExpression(constant)); 905 constantInitializerExpression(constant)]);
934 buffer.write(jsAst.prettyPrint(init, compiler)); 906 buffer.write(jsAst.prettyPrint(init, compiler));
935 buffer.write('$N'); 907 buffer.write('$N');
936 } 908 }
937 } 909 }
938 910
939 bool isConstantInlinedOrAlreadyEmitted(Constant constant) { 911 bool isConstantInlinedOrAlreadyEmitted(Constant constant) {
940 if (constant.isFunction) return true; // Already emitted. 912 if (constant.isFunction) return true; // Already emitted.
941 if (constant.isPrimitive) return true; // Inlined. 913 if (constant.isPrimitive) return true; // Inlined.
942 if (constant.isDummy) return true; // Inlined. 914 if (constant.isDummy) return true; // Inlined.
943 // The name is null when the constant is already a JS constant. 915 // The name is null when the constant is already a JS constant.
(...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after
1187 } else { 1159 } else {
1188 outputClassLists.putIfAbsent( 1160 outputClassLists.putIfAbsent(
1189 compiler.deferredLoadTask.outputUnitForElement(element), 1161 compiler.deferredLoadTask.outputUnitForElement(element),
1190 () => new List<ClassElement>()) 1162 () => new List<ClassElement>())
1191 .add(element); 1163 .add(element);
1192 } 1164 }
1193 } 1165 }
1194 } 1166 }
1195 1167
1196 void emitInitFunction(CodeBuffer buffer) { 1168 void emitInitFunction(CodeBuffer buffer) {
1197 jsAst.Fun fun = js.fun([], [ 1169 jsAst.FunctionDeclaration decl = js.statement('''
1198 js('$isolateProperties = {}'), 1170 function init() {
1199 ] 1171 $isolateProperties = {};
1200 ..addAll(buildDefineClassAndFinishClassFunctionsIfNecessary()) 1172 #; #; #;
1201 ..addAll(buildLazyInitializerFunctionIfNecessary()) 1173 }''', [
1202 ..addAll(buildFinishIsolateConstructor()) 1174 buildDefineClassAndFinishClassFunctionsIfNecessary(),
1203 ); 1175 buildLazyInitializerFunctionIfNecessary(),
1204 jsAst.FunctionDeclaration decl = new jsAst.FunctionDeclaration( 1176 buildFinishIsolateConstructor()]);
1205 new jsAst.VariableDeclaration('init'), fun); 1177
1206 buffer.write(jsAst.prettyPrint(decl, compiler).getText()); 1178 buffer.write(jsAst.prettyPrint(decl, compiler).getText());
1207 if (compiler.enableMinification) buffer.write('\n'); 1179 if (compiler.enableMinification) buffer.write('\n');
1208 } 1180 }
1209 1181
1210 void emitConvertToFastObjectFunction() { 1182 void emitConvertToFastObjectFunction() {
1211 // Create an instance that uses 'properties' as prototype. This should make 1183 // Create an instance that uses 'properties' as prototype. This should make
1212 // 'properties' a fast object. 1184 // 'properties' a fast object.
1213 mainBuffer.add(r'''function convertToFastObject(properties) { 1185 mainBuffer.add(r'''function convertToFastObject(properties) {
1214 function MyClass() {}; 1186 function MyClass() {};
1215 MyClass.prototype = properties; 1187 MyClass.prototype = properties;
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after
1382 var keys = mangledFieldNames.keys.toList(); 1354 var keys = mangledFieldNames.keys.toList();
1383 keys.sort(); 1355 keys.sort();
1384 var properties = []; 1356 var properties = [];
1385 for (String key in keys) { 1357 for (String key in keys) {
1386 var value = js.string('${mangledFieldNames[key]}'); 1358 var value = js.string('${mangledFieldNames[key]}');
1387 properties.add(new jsAst.Property(js.string(key), value)); 1359 properties.add(new jsAst.Property(js.string(key), value));
1388 } 1360 }
1389 var map = new jsAst.ObjectInitializer(properties); 1361 var map = new jsAst.ObjectInitializer(properties);
1390 mainBuffer.write( 1362 mainBuffer.write(
1391 jsAst.prettyPrint( 1363 jsAst.prettyPrint(
1392 js('init.mangledNames = #', map).toStatement(), compiler)); 1364 js.statement('init.mangledNames = #', map), compiler));
1393 if (compiler.enableMinification) { 1365 if (compiler.enableMinification) {
1394 mainBuffer.write(';'); 1366 mainBuffer.write(';');
1395 } 1367 }
1396 } 1368 }
1397 if (!mangledGlobalFieldNames.isEmpty) { 1369 if (!mangledGlobalFieldNames.isEmpty) {
1398 var keys = mangledGlobalFieldNames.keys.toList(); 1370 var keys = mangledGlobalFieldNames.keys.toList();
1399 keys.sort(); 1371 keys.sort();
1400 var properties = []; 1372 var properties = [];
1401 for (String key in keys) { 1373 for (String key in keys) {
1402 var value = js.string('${mangledGlobalFieldNames[key]}'); 1374 var value = js.string('${mangledGlobalFieldNames[key]}');
1403 properties.add(new jsAst.Property(js.string(key), value)); 1375 properties.add(new jsAst.Property(js.string(key), value));
1404 } 1376 }
1405 var map = new jsAst.ObjectInitializer(properties); 1377 var map = new jsAst.ObjectInitializer(properties);
1406 mainBuffer.write( 1378 mainBuffer.write(
1407 jsAst.prettyPrint( 1379 jsAst.prettyPrint(
1408 js('init.mangledGlobalNames = #', map).toStatement(), 1380 js.statement('init.mangledGlobalNames = #', map),
1409 compiler)); 1381 compiler));
1410 if (compiler.enableMinification) { 1382 if (compiler.enableMinification) {
1411 mainBuffer.write(';'); 1383 mainBuffer.write(';');
1412 } 1384 }
1413 } 1385 }
1414 mainBuffer 1386 mainBuffer
1415 ..write('(') 1387 ..write('(')
1416 ..write( 1388 ..write(
1417 jsAst.prettyPrint( 1389 jsAst.prettyPrint(
1418 getReflectionDataParser(classesCollector, backend), 1390 getReflectionDataParser(classesCollector, backend),
(...skipping 310 matching lines...) Expand 10 before | Expand all | Expand 10 after
1729 String sourceMap = sourceMapBuilder.build(); 1701 String sourceMap = sourceMapBuilder.build();
1730 compiler.outputProvider(name, 'js.map') 1702 compiler.outputProvider(name, 'js.map')
1731 ..add(sourceMap) 1703 ..add(sourceMap)
1732 ..close(); 1704 ..close();
1733 } 1705 }
1734 1706
1735 void registerReadTypeVariable(TypeVariableElement element) { 1707 void registerReadTypeVariable(TypeVariableElement element) {
1736 readTypeVariables.add(element); 1708 readTypeVariables.add(element);
1737 } 1709 }
1738 } 1710 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698